Commit 96de0e2f50d for nodejs
commit 96de0e2f50d5289eaaeade9cc9e5d7e01a850774
Author: Node.js GitHub Bot <github-bot@iojs.org>
Date: Mon Nov 2 19:53:29 2026 -0500
deps: update perfetto to 59.1
PR-URL: https://github.com/nodejs/node/pull/67171
Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
Reviewed-By: Antoine du Hamel <duhamelantoine1995@gmail.com>
diff --git a/deps/perfetto/LICENSE b/deps/perfetto/LICENSE
index 681d40008ee..2db252fd570 100644
--- a/deps/perfetto/LICENSE
+++ b/deps/perfetto/LICENSE
@@ -226,7 +226,7 @@ Files: src/trace_processor/perfetto_sql/stdlib/chromium/*, protos/third_party/ch
------------------
-Files: src/trace_processor/perfetto_sql/syntaqlite/syntaqlite_perfetto.{c, h}
+Files: src/perfetto_sql/syntaqlite/syntaqlite_perfetto.{c, h}
Copyright 2025 The syntaqlite Authors. All rights reserved.
diff --git a/deps/perfetto/VERSION b/deps/perfetto/VERSION
index 5132e635a5f..2246a13a3da 100644
--- a/deps/perfetto/VERSION
+++ b/deps/perfetto/VERSION
@@ -1 +1 @@
-58.2
+59.1
diff --git a/deps/perfetto/sdk/LICENSE b/deps/perfetto/sdk/LICENSE
new file mode 100644
index 00000000000..2db252fd570
--- /dev/null
+++ b/deps/perfetto/sdk/LICENSE
@@ -0,0 +1,285 @@
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+------------------
+
+Files: * except those files noted below
+
+ 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.
+
+ 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.
+
+
+------------------
+
+Files: src/trace_processor/perfetto_sql/stdlib/chromium/*, protos/third_party/chromium/*, test/trace_processor/diff_tests/stdlib/chrome/*
+
+ Copyright 2015 The Chromium Authors
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are
+ met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following disclaimer
+ in the documentation and/or other materials provided with the
+ distribution.
+ * Neither the name of Google LLC nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+------------------
+
+Files: src/perfetto_sql/syntaqlite/syntaqlite_perfetto.{c, h}
+
+ Copyright 2025 The syntaqlite Authors. All rights reserved.
+
+ Machine-generated amalgamation of syntaqlite runtime + Perfetto dialect
+ sources (https://github.com/LalitMaganti/syntaqlite). Portions derive
+ from SQLite's public-domain `parse.y` grammar.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+
+ 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.
+
+
+------------------
+
+Files: src/trace_processor/perfetto_sql/preprocessor/preprocessor_grammar.{c, h}
+
+The author disclaims copyright to this source code. In place of a legal notice, here is a blessing:
+
+May you do good and not evil.
+May you find forgiveness for yourself and forgive others.
+May you share freely, never taking more than you give.
+
+
+------------------
+
+Files: src/base/intrusive_tree.cc
+
+$OpenBSD: tree.h,v 1.31 2023/03/08 04:43:09 guenther Exp $
+
+Copyright 2002 Niels Provos <provos@citi.umich.edu>
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/deps/perfetto/sdk/perfetto.cc b/deps/perfetto/sdk/perfetto.cc
index 739d4832204..3aa0cd8e36b 100644
--- a/deps/perfetto/sdk/perfetto.cc
+++ b/deps/perfetto/sdk/perfetto.cc
@@ -122,6 +122,14 @@ void AfterMaybeBlockingSyscall() {}
#include <stdint.h>
+// The __attribute__((constructor)) below is intentional: this function runs at
+// load time on purpose to verify the CPU supports the extensions the binary is
+// built with. -Wglobal-constructors (enabled by -Weverything) would otherwise
+// flag it.
+#if defined(__clang__)
+#pragma clang diagnostic ignored "-Wglobal-constructors"
+#endif
+
// gen_amalgamated expanded: #include "perfetto/base/build_config.h"
// gen_amalgamated expanded: #include "perfetto/base/export.h"
@@ -150,7 +158,13 @@ uint32_t GetXCR0EAX() {
// If we are building with -msse4 check that the CPU actually supports it.
// This file must be kept in sync with gn/standalone/BUILD.gn.
-void PERFETTO_EXPORT_COMPONENT __attribute__((constructor))
+//
+// Priority 101 is the earliest non-reserved constructor priority. With the
+// default (65535) this would run after protobuf's descriptor registration
+// (priority 102), which already executes BMI2 instructions and SIGILLs on
+// older CPUs before this check can print its message. See
+// https://github.com/google/perfetto/issues/7504.
+void PERFETTO_EXPORT_COMPONENT __attribute__((constructor(101)))
CheckCpuOptimizations() {
uint32_t eax = 0, ebx = 0, ecx = 0, edx = 0;
PERFETTO_GETCPUID(eax, ebx, ecx, edx, 1, 0);
@@ -221,6 +235,7 @@ CheckCpuOptimizations() {
#include <cstdint>
#include <optional>
#include <string>
+#include <vector>
// gen_amalgamated expanded: #include "perfetto/base/build_config.h"
@@ -258,6 +273,7 @@ struct SystemInfo {
std::string android_storage_model;
std::string android_ram_model;
std::string android_serial_console;
+ std::vector<std::string> device_tree_compatibles;
};
// Returns the device's utsname information.
@@ -277,9 +293,8 @@ std::string GetPerfettoMachineName();
} // namespace perfetto
#endif // INCLUDE_PERFETTO_EXT_BASE_ANDROID_UTILS_H_
-// gen_amalgamated begin header: include/perfetto/ext/base/string_utils.h
-// gen_amalgamated begin header: include/perfetto/ext/base/string_view.h
-// gen_amalgamated begin header: include/perfetto/ext/base/fnv_hash.h
+// gen_amalgamated begin header: include/perfetto/ext/base/file_utils.h
+// gen_amalgamated begin header: include/perfetto/base/status.h
/*
* Copyright (C) 2019 The Android Open Source Project
*
@@ -296,135 +311,110 @@ std::string GetPerfettoMachineName();
* limitations under the License.
*/
-#ifndef INCLUDE_PERFETTO_EXT_BASE_FNV_HASH_H_
-#define INCLUDE_PERFETTO_EXT_BASE_FNV_HASH_H_
+#ifndef INCLUDE_PERFETTO_BASE_STATUS_H_
+#define INCLUDE_PERFETTO_BASE_STATUS_H_
-#include <stddef.h>
-#include <stdint.h>
+#include <optional>
+#include <string>
#include <string_view>
-#include <type_traits>
-#include <utility>
+#include <vector>
-namespace perfetto::base {
+// gen_amalgamated expanded: #include "perfetto/base/compiler.h"
+// gen_amalgamated expanded: #include "perfetto/base/export.h"
+// gen_amalgamated expanded: #include "perfetto/base/logging.h"
-// A helper class which computes a 64-bit hash of the input data.
-// The algorithm used is FNV-1a as it is fast and easy to implement and has
-// relatively few collisions.
-// WARNING: This hash function should not be used for any cryptographic purpose.
-class FnvHasher {
- public:
- // Creates an empty hash object
- constexpr FnvHasher() = default;
+namespace perfetto {
+namespace base {
- // Hashes a numeric value.
- template <
- typename T,
- typename std::enable_if<std::is_arithmetic<T>::value, bool>::type = true>
- void Update(T data) {
- Update(reinterpret_cast<const char*>(&data), sizeof(data));
+// Represents either the success or the failure message of a function.
+// This can used as the return type of functions which would usually return an
+// bool for success or int for errno but also wants to add some string context
+// (ususally for logging).
+//
+// Similar to absl::Status, an optional "payload" can also be included with more
+// context about the error. This allows passing additional metadata about the
+// error (e.g. location of errors, potential mitigations etc).
+class PERFETTO_EXPORT_COMPONENT Status {
+ public:
+ Status() : ok_(true) {}
+ explicit Status(std::string msg) : ok_(false), message_(std::move(msg)) {
+ PERFETTO_CHECK(!message_.empty());
}
- constexpr void Update(char c) { return Update(&c, 1); }
-
- // Using the loop instead of "Update(str, strlen(str))" to avoid looping twice
- constexpr void Update(const char* str) {
- for (const auto* p = str; *p; ++p)
- Update(*p);
- }
+ // Copy operations.
+ Status(const Status&) = default;
+ Status& operator=(const Status&) = default;
- // Hashes a byte array.
- constexpr void Update(const char* data, size_t size) {
- for (size_t i = 0; i < size; i++) {
- result_ ^= static_cast<uint8_t>(data[i]);
- // Note: Arithmetic overflow of unsigned integers is well defined in C++
- // standard unlike signed integers.
- // https://stackoverflow.com/a/41280273
- result_ *= kFnv1a64Prime;
- }
- }
+ // Move operations. The moved-from state is valid but unspecified.
+ Status(Status&&) noexcept = default;
+ Status& operator=(Status&&) = default;
- // Allow hashing anything that has `data` and `size` and has the kHashable
- // trait (e.g., base::StringView).
- template <typename T, typename = std::enable_if_t<T::kHashable>>
- constexpr void Update(const T& t) {
- if constexpr (std::is_member_function_pointer_v<decltype(&T::data)>) {
- Update(t.data(), t.size());
- } else {
- Update(t.data, t.size);
- }
- }
+ bool ok() const { return ok_; }
- constexpr void Update(std::string_view s) { Update(s.data(), s.size()); }
+ // When ok() is false this returns the error message. Returns the empty string
+ // otherwise.
+ const std::string& message() const { return message_; }
+ const char* c_message() const { return message_.c_str(); }
- constexpr uint64_t digest() const { return result_; }
+ //////////////////////////////////////////////////////////////////////////////
+ // Payload Management APIs
+ //////////////////////////////////////////////////////////////////////////////
- // Usage:
- // uint64_t hashed_value =
- // FnvHasher::Combine(33, false, "ABC", 458L, 3u, 'x');
- template <typename... Ts>
- static constexpr uint64_t Combine(Ts&&... args) {
- FnvHasher hasher;
- hasher.UpdateAll(std::forward<Ts>(args)...);
- return hasher.digest();
- }
+ // Payloads can be attached to error statuses to provide additional context.
+ //
+ // Payloads are (key, value) pairs, where the key is a string acting as a
+ // unique "type URL" and the value is an opaque string. The "type URL" should
+ // be unique, follow the format of a URL and, ideally, documentation on how to
+ // interpret its associated data should be available.
+ //
+ // To attach a payload to a status object, call `Status::SetPayload()`.
+ // Similarly, to extract the payload from a status, call
+ // `Status::GetPayload()`.
+ //
+ // Note: the payload APIs are only meaningful to call when the status is an
+ // error. Otherwise, all methods are noops.
- // Creates a hasher with `args` already hashed.
+ // Gets the payload for the given |type_url| if one exists.
//
- // Usage:
- // FnvHasher partial = FnvHasher::CreatePartial(33, false, "ABC", 458L);
- template <typename... Ts>
- static constexpr FnvHasher CreatePartial(Ts&&... args) {
- FnvHasher hasher;
- hasher.UpdateAll(std::forward<Ts>(args)...);
- return hasher;
- }
+ // Will always return std::nullopt if |ok()|.
+ std::optional<std::string_view> GetPayload(std::string_view type_url) const;
- // `hasher.UpdateAll(33, false, "ABC")` is shorthand for:
- // `hasher.Update(33); hasher.Update(false); hasher.Update("ABC");`
- constexpr void UpdateAll() {}
+ // Sets the payload for the given key. The key should
+ //
+ // Will always do nothing if |ok()|.
+ void SetPayload(std::string_view type_url, std::string value);
- template <typename T, typename... Ts>
- constexpr void UpdateAll(T&& arg, Ts&&... args) {
- Update(arg);
- UpdateAll(std::forward<Ts>(args)...);
- }
+ // Erases the payload for the given string and returns true if the payload
+ // existed and was erased.
+ //
+ // Will always do nothing if |ok()|.
+ bool ErasePayload(std::string_view type_url);
private:
- static constexpr uint64_t kFnv1a64OffsetBasis = 0xcbf29ce484222325;
- static constexpr uint64_t kFnv1a64Prime = 0x100000001b3;
+ struct Payload {
+ std::string type_url;
+ std::string payload;
+ };
- uint64_t result_ = kFnv1a64OffsetBasis;
+ bool ok_ = false;
+ std::string message_;
+ std::vector<Payload> payloads_;
};
-// base::FnvHash uses base::FnvHasher for integer values and falls back to
-// std::hash for other types. This is needed as std::hash for integers is just
-// the identity function and Perfetto uses open-addressing hash table, which are
-// very sensitive to hash quality and are known to degrade in performance
-// when using std::hash.
-template <typename T>
-struct FnvHash {
- // Version for ints, using base::FnvHasher.
- template <typename U = T>
- auto operator()(const U& x) ->
- typename std::enable_if<std::is_arithmetic<U>::value, size_t>::type
- const {
- return FnvHasher::Combine(x);
- }
+// Returns a status object which represents the Ok status.
+inline Status OkStatus() {
+ return Status();
+}
- // Version for non-ints, falling back to std::hash.
- template <typename U = T>
- auto operator()(const U& x) ->
- typename std::enable_if<!std::is_arithmetic<U>::value, size_t>::type
- const {
- return std::hash<U>()(x);
- }
-};
+Status ErrStatus(const char* format, ...) PERFETTO_PRINTF_FORMAT(1, 2);
-} // namespace perfetto::base
+} // namespace base
+} // namespace perfetto
-#endif // INCLUDE_PERFETTO_EXT_BASE_FNV_HASH_H_
+#endif // INCLUDE_PERFETTO_BASE_STATUS_H_
+// gen_amalgamated begin header: include/perfetto/ext/base/scoped_file.h
/*
- * Copyright (C) 2018 The Android Open Source Project
+ * 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.
@@ -439,203 +429,189 @@ struct FnvHash {
* limitations under the License.
*/
-#ifndef INCLUDE_PERFETTO_EXT_BASE_STRING_VIEW_H_
-#define INCLUDE_PERFETTO_EXT_BASE_STRING_VIEW_H_
+#ifndef INCLUDE_PERFETTO_EXT_BASE_SCOPED_FILE_H_
+#define INCLUDE_PERFETTO_EXT_BASE_SCOPED_FILE_H_
-#include <string.h>
+// gen_amalgamated expanded: #include "perfetto/base/build_config.h"
+
+#include <stdio.h>
+
+#if !PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
+#include <dirent.h> // For DIR* / opendir().
+#endif
-#include <algorithm>
#include <string>
-#include <vector>
-// gen_amalgamated expanded: #include "perfetto/base/build_config.h"
+// gen_amalgamated expanded: #include "perfetto/base/export.h"
// gen_amalgamated expanded: #include "perfetto/base/logging.h"
-// gen_amalgamated expanded: #include "perfetto/ext/base/fnv_hash.h"
+// gen_amalgamated expanded: #include "perfetto/base/platform_handle.h"
namespace perfetto {
namespace base {
-// A string-like object that refers to a non-owned piece of memory.
-// Strings are internally NOT null terminated.
-class StringView {
+namespace internal {
+// Used for the most common cases of ScopedResource where there is only one
+// invalid value.
+template <typename T, T InvalidValue>
+struct DefaultValidityChecker {
+ static bool IsValid(T t) { return t != InvalidValue; }
+};
+} // namespace internal
+
+// RAII classes for auto-releasing fds and dirs.
+// if T is a pointer type, InvalidValue must be nullptr. Doing otherwise
+// causes weird unexpected behaviors (See https://godbolt.org/z/5nGMW4).
+template <typename T,
+ int (*CloseFunction)(T),
+ T InvalidValue,
+ bool CheckClose = true,
+ class Checker = internal::DefaultValidityChecker<T, InvalidValue>>
+class ScopedResource {
public:
- // Allow hashing with base::FnvHash.
- static constexpr bool kHashable = true;
- static constexpr size_t npos = static_cast<size_t>(-1);
+ using ValidityChecker = Checker;
+ static constexpr T kInvalid = InvalidValue;
- StringView() : data_(nullptr), size_(0) {}
- StringView(const StringView&) = default;
- StringView& operator=(const StringView&) = default;
- StringView(const char* data, size_t size) : data_(data), size_(size) {
- PERFETTO_DCHECK(size == 0 || data != nullptr);
+ explicit ScopedResource(T t = InvalidValue) : t_(t) {}
+ ScopedResource(ScopedResource&& other) noexcept : t_(other.t_) {
+ other.t_ = InvalidValue;
}
-
- // Allow implicit conversion from any class that has a |data| and |size| field
- // and has the kConvertibleToStringView trait (e.g., protozero::ConstChars).
- template <typename T, typename = std::enable_if<T::kConvertibleToStringView>>
- StringView(const T& x) : StringView(x.data, x.size) {
- PERFETTO_DCHECK(x.size == 0 || x.data != nullptr);
+ ScopedResource& operator=(ScopedResource&& other) {
+ reset(other.t_);
+ other.t_ = InvalidValue;
+ return *this;
}
-
- // Creates a StringView from a null-terminated C string.
- // Deliberately not "explicit".
- StringView(const char* cstr) : data_(cstr), size_(strlen(cstr)) {
- PERFETTO_DCHECK(cstr != nullptr);
+ T get() const { return t_; }
+ T operator*() const { return t_; }
+ explicit operator bool() const { return Checker::IsValid(t_); }
+ void reset(T r = InvalidValue) {
+ if (Checker::IsValid(t_)) {
+ int res = CloseFunction(t_);
+ if (CheckClose)
+ PERFETTO_CHECK(res == 0);
+ }
+ t_ = r;
+ }
+ T release() {
+ T t = t_;
+ t_ = InvalidValue;
+ return t;
}
+ ~ScopedResource() { reset(InvalidValue); }
- StringView(std::string_view str) : data_(str.data()), size_(str.size()) {}
+ private:
+ ScopedResource(const ScopedResource&) = delete;
+ ScopedResource& operator=(const ScopedResource&) = delete;
+ T t_;
+};
- // This instead has to be explicit, as creating a StringView out of a
- // std::string can be subtle.
- explicit StringView(const std::string& str)
- : data_(str.data()), size_(str.size()) {}
+// Declared in file_utils.h. Forward declared to avoid #include cycles.
+int PERFETTO_EXPORT_COMPONENT CloseFile(int fd);
- bool empty() const { return size_ == 0; }
- size_t size() const { return size_; }
- const char* data() const { return data_; }
- const char* begin() const { return data_; }
- const char* end() const { return data_ + size_; }
+// Use this for file resources obtained via open() and similar APIs.
+using ScopedFile = ScopedResource<int, CloseFile, -1>;
+using ScopedFstream = ScopedResource<FILE*, fclose, nullptr>;
- char at(size_t pos) const {
- PERFETTO_DCHECK(pos < size_);
- return data_[pos];
- }
+// Use this for resources that are HANDLE on Windows. See comments in
+// platform_handle.h
+#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
+using ScopedPlatformHandle = ScopedResource<PlatformHandle,
+ ClosePlatformHandle,
+ /*InvalidValue=*/nullptr,
+ /*CheckClose=*/true,
+ PlatformHandleChecker>;
+#else
+// On non-windows systems we alias ScopedPlatformHandle to ScopedFile because
+// they are really the same. This is to allow assignments between the two in
+// Linux-specific code paths that predate ScopedPlatformHandle.
+static_assert(std::is_same<int, PlatformHandle>::value, "");
+using ScopedPlatformHandle = ScopedFile;
- size_t find(char c, size_t start_pos = 0) const {
- for (size_t i = start_pos; i < size_; ++i) {
- if (data_[i] == c)
- return i;
- }
- return npos;
- }
+// DIR* does not exist on Windows.
+using ScopedDir = ScopedResource<DIR*, closedir, nullptr>;
+#endif
- size_t find(const StringView& str, size_t start_pos = 0) const {
- if (start_pos > size())
- return npos;
- auto it = std::search(begin() + start_pos, end(), str.begin(), str.end());
- size_t pos = static_cast<size_t>(it - begin());
- return pos + str.size() <= size() ? pos : npos;
- }
+} // namespace base
+} // namespace perfetto
- size_t find(const char* str, size_t start_pos = 0) const {
- return find(StringView(str), start_pos);
- }
+#endif // INCLUDE_PERFETTO_EXT_BASE_SCOPED_FILE_H_
+// gen_amalgamated begin header: include/perfetto/ext/base/sys_types.h
+/*
+ * 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.
+ */
- size_t rfind(char c) const {
- for (size_t i = size_; i > 0; --i) {
- if (data_[i - 1] == c)
- return i - 1;
- }
- return npos;
- }
+#ifndef INCLUDE_PERFETTO_EXT_BASE_SYS_TYPES_H_
+#define INCLUDE_PERFETTO_EXT_BASE_SYS_TYPES_H_
- StringView substr(size_t pos, size_t count = npos) const {
- if (pos >= size_)
- return StringView("", 0);
- size_t rcount = std::min(count, size_ - pos);
- return StringView(data_ + pos, rcount);
- }
+// This headers deals with sys types commonly used in the codebase that are
+// missing on Windows.
- bool CaseInsensitiveEq(const StringView& other) const {
- if (size() != other.size())
- return false;
- if (size() == 0)
- return true;
-#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
- return _strnicmp(data(), other.data(), size()) == 0;
-#else
- return strncasecmp(data(), other.data(), size()) == 0;
-#endif
- }
+#include <sys/types.h> // IWYU pragma: export
+#include <cstdint>
- bool CaseInsensitiveOneOf(const std::vector<StringView>& others) const {
- for (const StringView& other : others) {
- if (CaseInsensitiveEq(other)) {
- return true;
- }
- }
- return false;
- }
+// gen_amalgamated expanded: #include "perfetto/base/build_config.h"
- bool StartsWith(const StringView& other) const {
- if (other.size() == 0)
- return true;
- if (size() == 0)
- return false;
- if (other.size() > size())
- return false;
- return memcmp(data(), other.data(), other.size()) == 0;
- }
+#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
- bool EndsWith(const StringView& other) const {
- if (other.size() == 0)
- return true;
- if (size() == 0)
- return false;
- if (other.size() > size())
- return false;
- size_t off = size() - other.size();
- return memcmp(data() + off, other.data(), other.size()) == 0;
- }
+#ifdef __MINGW32__
- std::string ToStdString() const {
- return size_ == 0 ? "" : std::string(data_, size_);
- }
+using uid_t = int;
+using gid_t = int;
- uint64_t Hash() const {
- base::FnvHasher hasher;
- hasher.Update(data_, size_);
- return hasher.digest();
- }
+#else
- private:
- const char* data_ = nullptr;
- size_t size_ = 0;
-};
+#if !PERFETTO_BUILDFLAG(PERFETTO_COMPILER_GCC)
+// MinGW has these. clang-cl and MSVC, which use just the Windows SDK, don't.
+using uid_t = int;
+using gid_t = int;
+using pid_t = int;
+#endif // !GCC
-inline bool operator==(const StringView& x, const StringView& y) {
- if (x.size() != y.size())
- return false;
- if (x.size() == 0)
- return true;
- return memcmp(x.data(), y.data(), x.size()) == 0;
-}
+using ssize_t = intptr_t;
-inline bool operator!=(const StringView& x, const StringView& y) {
- return !(x == y);
-}
+#endif // __MINGW32__
-inline bool operator<(const StringView& x, const StringView& y) {
- auto size = std::min(x.size(), y.size());
- if (size == 0)
- return x.size() < y.size();
- int result = memcmp(x.data(), y.data(), size);
- return result < 0 || (result == 0 && x.size() < y.size());
-}
+#endif // OS_WIN
-inline bool operator>=(const StringView& x, const StringView& y) {
- return !(x < y);
-}
+#if PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID)
+// From libcutils' android_filesystem_config.h
+#ifndef AID_ROOT
+#define AID_ROOT 0
+#endif
+#ifndef AID_STATSD
+#define AID_STATSD 1066
+#endif
+#ifndef AID_SHELL
+#define AID_SHELL 2000
+#endif
+#endif
-inline bool operator>(const StringView& x, const StringView& y) {
- return y < x;
-}
+namespace perfetto {
+namespace base {
-inline bool operator<=(const StringView& x, const StringView& y) {
- return !(y < x);
-}
+// The machine ID used in the tracing core.
+using MachineID = uint32_t;
+// The default value reserved for the host trace.
+constexpr MachineID kDefaultMachineID = 0;
+
+constexpr uid_t kInvalidUid = static_cast<uid_t>(-1);
+constexpr pid_t kInvalidPid = static_cast<pid_t>(-1);
} // namespace base
} // namespace perfetto
-template <>
-struct std::hash<::perfetto::base::StringView> {
- size_t operator()(const ::perfetto::base::StringView& sv) const {
- return static_cast<size_t>(sv.Hash());
- }
-};
-
-#endif // INCLUDE_PERFETTO_EXT_BASE_STRING_VIEW_H_
+#endif // INCLUDE_PERFETTO_EXT_BASE_SYS_TYPES_H_
/*
* Copyright (C) 2018 The Android Open Source Project
*
@@ -652,311 +628,245 @@ struct std::hash<::perfetto::base::StringView> {
* limitations under the License.
*/
-#ifndef INCLUDE_PERFETTO_EXT_BASE_STRING_UTILS_H_
-#define INCLUDE_PERFETTO_EXT_BASE_STRING_UTILS_H_
+#ifndef INCLUDE_PERFETTO_EXT_BASE_FILE_UTILS_H_
+#define INCLUDE_PERFETTO_EXT_BASE_FILE_UTILS_H_
-#include <stdarg.h>
-#include <stdlib.h>
-#include <string.h>
+#include <fcntl.h> // For mode_t & O_RDONLY/RDWR. Exists also on Windows.
+#include <stddef.h>
+#include <stdint.h>
-#include <charconv>
-#include <cinttypes>
+#include <functional>
+#include <memory>
#include <optional>
#include <string>
-#include <string_view>
-#include <system_error>
#include <vector>
-// gen_amalgamated expanded: #include "perfetto/ext/base/string_view.h"
-
-namespace perfetto {
+// gen_amalgamated expanded: #include "perfetto/base/build_config.h"
+// gen_amalgamated expanded: #include "perfetto/base/export.h"
+// gen_amalgamated expanded: #include "perfetto/base/status.h"
+// gen_amalgamated expanded: #include "perfetto/ext/base/scoped_file.h"
+// gen_amalgamated expanded: #include "perfetto/ext/base/sys_types.h"
+
+namespace perfetto {
namespace base {
-inline char Lowercase(char c) {
- return ('A' <= c && c <= 'Z') ? static_cast<char>(c - ('A' - 'a')) : c;
-}
+class TaskRunner;
-inline char Uppercase(char c) {
- return ('a' <= c && c <= 'z') ? static_cast<char>(c + ('A' - 'a')) : c;
-}
+#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
+using FileOpenMode = int;
+inline constexpr char kDevNull[] = "NUL";
+inline constexpr char kFopenReadFlag[] = "r";
+#else
+using FileOpenMode = mode_t;
+inline constexpr char kDevNull[] = "/dev/null";
+inline constexpr char kFopenReadFlag[] = "re";
+#endif
-// Returns true if the character is an ASCII whitespace character.
-// This is a locale-independent version that only considers ASCII whitespace:
-// space (0x20), tab (0x09), newline (0x0A), vertical tab (0x0B),
-// form feed (0x0C), and carriage return (0x0D).
-inline bool IsSpace(char c) {
- return c == ' ' || c == '\t' || c == '\n' || c == '\v' || c == '\f' ||
- c == '\r';
-}
+constexpr FileOpenMode kFileModeInvalid = static_cast<FileOpenMode>(-1);
-inline std::optional<uint32_t> CStringToUInt32(const char* s, int base = 10) {
- char* endptr = nullptr;
- auto value = static_cast<uint32_t>(strtoul(s, &endptr, base));
- return (*s && !*endptr) ? std::make_optional(value) : std::nullopt;
-}
+// Cross-platform variant of ReadFileDescriptor() that takes a PlatformHandle.
+// On Windows normalizes ERROR_BROKEN_PIPE to EOF so behavior matches POSIX.
+bool ReadPlatformHandle(PlatformHandle, std::string* out);
-inline std::optional<int32_t> CStringToInt32(const char* s, int base = 10) {
- char* endptr = nullptr;
- auto value = static_cast<int32_t>(strtol(s, &endptr, base));
- return (*s && !*endptr) ? std::make_optional(value) : std::nullopt;
-}
+// Reads from |fd|, appending what is currently available into |*out|.
+// Returns:
+// True: EOF reached (all writers of |fd| have closed their end).
+// False: read error. On a non-blocking |fd| this includes EAGAIN (no data
+// currently available but writers are still alive); callers can check
+// IsAgain(errno) and retry on the next readability notification.
+bool ReadFileDescriptor(int fd, std::string* out);
-// Note: it saturates to 7fffffffffffffff if parsing a hex number >= 0x8000...
-inline std::optional<int64_t> CStringToInt64(const char* s, int base = 10) {
- char* endptr = nullptr;
- auto value = static_cast<int64_t>(strtoll(s, &endptr, base));
- return (*s && !*endptr) ? std::make_optional(value) : std::nullopt;
-}
+// Convenience wrapper around ReadFileDescriptor() that takes a FILE*.
+bool ReadFileStream(FILE* f, std::string* out);
-inline std::optional<uint64_t> CStringToUInt64(const char* s, int base = 10) {
- char* endptr = nullptr;
- auto value = static_cast<uint64_t>(strtoull(s, &endptr, base));
- return (*s && !*endptr) ? std::make_optional(value) : std::nullopt;
-}
+// Opens |path| read-only and reads its contents into |*out|.
+// Returns false if the file cannot be opened.
+bool ReadFile(const std::string& path, std::string* out);
-double StrToD(const char* nptr, char** endptr);
+// A wrapper around read(2). It deals with Linux vs Windows includes. It also
+// deals with handling EINTR. Has the same semantics of UNIX's read(2).
+ssize_t Read(int fd, void* dst, size_t dst_size);
-inline std::optional<double> CStringToDouble(const char* s) {
- char* endptr = nullptr;
- double value = StrToD(s, &endptr);
- std::optional<double> result(std::nullopt);
- if (*s != '\0' && *endptr == '\0')
- result = value;
- return result;
-}
+// Call write until all data is written or an error is detected.
+//
+// man 2 write:
+// If a write() is interrupted by a signal handler before any bytes are
+// written, then the call fails with the error EINTR; if it is
+// interrupted after at least one byte has been written, the call
+// succeeds, and returns the number of bytes written.
+ssize_t WriteAll(int fd, const void* buf, size_t count);
-inline std::optional<uint32_t> StringToUInt32(const std::string& s,
- int base = 10) {
- return CStringToUInt32(s.c_str(), base);
-}
+// Copies all data from |fd_in| to |fd_out|. Saves the offset of |fd_in|,
+// rewinds it to the beginning, copies the content, and restores the offset.
+// |fd_in| can't be a pipe, socket of FIFO.
+base::Status CopyFileContents(int fd_in, int fd_out);
-inline std::optional<int32_t> StringToInt32(const std::string& s,
- int base = 10) {
- return CStringToInt32(s.c_str(), base);
-}
+ssize_t WriteAllHandle(PlatformHandle, const void* buf, size_t count);
-inline std::optional<uint64_t> StringToUInt64(const std::string& s,
- int base = 10) {
- return CStringToUInt64(s.c_str(), base);
-}
+ScopedFile OpenFile(const std::string& path,
+ int flags,
+ FileOpenMode = kFileModeInvalid);
+ScopedFstream OpenFstream(const std::string& path, const std::string& mode);
-inline std::optional<int64_t> StringToInt64(const std::string& s,
- int base = 10) {
- return CStringToInt64(s.c_str(), base);
-}
+// This is an alias for close(). It's to avoid leaking windows.h in headers.
+// Exported because ScopedFile is used in the /include/ext API by Chromium
+// component builds.
+int PERFETTO_EXPORT_COMPONENT CloseFile(int fd);
-inline std::optional<double> StringToDouble(const std::string& s) {
- return CStringToDouble(s.c_str());
-}
+bool FlushFile(int fd);
-template <typename T>
-inline std::optional<T> StringViewToNumber(const base::StringView& sv,
- int base = 10) {
- // std::from_chars() does not regonize the leading '+' character and only
- // recognizes '-' so remove the '+' if it exists to avoid errors and match
- // the behavior of the other string conversion utilities above.
- size_t start_offset = !sv.empty() && sv.at(0) == '+' ? 1 : 0;
- T value;
- auto result =
- std::from_chars(sv.begin() + start_offset, sv.end(), value, base);
- if (result.ec == std::errc() && result.ptr == sv.end()) {
- return value;
- } else {
- return std::nullopt;
- }
-}
+// Duplicates an open descriptor. The duplicate is not inherited across exec.
+ScopedFile DupFile(int fd);
-inline std::optional<uint32_t> StringViewToUInt32(const base::StringView& sv,
- int base = 10) {
- // std::from_chars() does not recognize the leading '-' character for
- // unsigned conversions, but strtol does. To Mimic the behavior of strtol,
- // attempt a signed converion if we see a leading '-', and then cast the
- // result back to unsigned.
- if (sv.size() > 0 && sv.at(0) == '-') {
- return static_cast<std::optional<uint32_t> >(
- StringViewToNumber<int32_t>(sv, base));
- } else {
- return StringViewToNumber<uint32_t>(sv, base);
- }
-}
+// These queries follow symbolic links. False also means a path could not be
+// inspected. IsSameFile compares file identities, so it detects hard links.
+bool IsRegularFile(const std::string& path);
+bool IsSameFile(const std::string& first, const std::string& second);
-inline std::optional<int32_t> StringViewToInt32(const base::StringView& sv,
- int base = 10) {
- return StringViewToNumber<int32_t>(sv, base);
-}
+// Moves the file offset to |offset| bytes from the beginning of the file.
+// Returns false if |offset| cannot be represented by the platform or the seek
+// fails.
+bool SeekFile(int fd, uint64_t offset);
-inline std::optional<uint64_t> StringViewToUInt64(const base::StringView& sv,
- int base = 10) {
- // std::from_chars() does not recognize the leading '-' character for
- // unsigned conversions, but strtol does. To Mimic the behavior of strtol,
- // attempt a signed converion if we see a leading '-', and then cast the
- // result back to unsigned.
- if (sv.size() > 0 && sv.at(0) == '-') {
- return static_cast<std::optional<uint64_t> >(
- StringViewToNumber<int64_t>(sv, base));
- } else {
- return StringViewToNumber<uint64_t>(sv, base);
- }
-}
+// Changes the size of an open file to |size| bytes.
+// Returns false if |size| cannot be represented by the platform or truncation
+// fails.
+bool TruncateFile(int fd, uint64_t size);
-inline std::optional<int64_t> StringViewToInt64(const base::StringView& sv,
- int base = 10) {
- return StringViewToNumber<int64_t>(sv, base);
-}
+// Returns true if mkdir succeeds, false if it fails (see errno in that case).
+// `mode` is the permission bits for the new directory; it is ignored on
+// Windows.
+bool Mkdir(const std::string& path, uint32_t mode = 0755);
-// TODO: As of Clang 19.0 std::from_chars is unimplemented for type double
-// despite being part of C++17 standard, and already being supported by GCC and
-// MSVC. Enable this once we have double support in Clang.
-// inline std::optional<double> StringViewToDouble(const base::StringView& sv) {
-// return StringViewToNumber<double>(sv);
-// }
+// Calls rmdir() on UNIX, _rmdir() on Windows.
+bool Rmdir(const std::string& path);
-bool StartsWith(const std::string& str, const std::string& prefix);
-bool EndsWith(const std::string& str, const std::string& suffix);
-bool StartsWithAny(const std::string& str,
- const std::vector<std::string>& prefixes);
-bool Contains(const std::string& haystack, const std::string& needle);
-bool Contains(const std::string& haystack, char needle);
-bool Contains(const std::vector<std::string>& haystack,
- const std::string& needle);
-size_t Find(const StringView& needle, const StringView& haystack);
-bool CaseInsensitiveEqual(const std::string& first, const std::string& second);
-std::string Join(const std::vector<std::string>& parts,
- const std::string& delim);
-std::vector<std::string> SplitString(const std::string& text,
- const std::string& delimiter);
-std::string StripPrefix(const std::string& str, const std::string& prefix);
-std::string StripSuffix(const std::string& str, const std::string& suffix);
-std::string_view TrimWhitespace(std::string_view str);
-std::string TrimWhitespace(const std::string& str);
-std::string_view TrimWhitespace(const char* str);
-std::string ToLower(const std::string& str);
-std::string ToUpper(const std::string& str);
-std::string StripChars(const std::string& str,
- const std::string& chars,
- char replacement);
-std::string ToHex(const char* data, size_t size);
-inline std::string ToHex(const std::string& s) {
- return ToHex(s.c_str(), s.size());
-}
-std::string IntToHexString(uint32_t number);
-std::string Uint64ToHexString(uint64_t number);
-std::string Uint64ToHexStringNoPrefix(uint64_t number);
-std::string ReplaceAll(std::string str,
- const std::string& to_replace,
- const std::string& replacement);
+// Removes a file: unlink() on UNIX, _unlink() on Windows. Takes a const char*
+// and is async-signal-safe on POSIX, so it's callable from a signal handler.
+bool Unlink(const char* path);
-// Checks if all characters in the input string view `str` are ASCII.
-//
-// If so, the function returns true and `output` is not modified.
-// If `str` contains non-ASCII characters, the function returns false,
-// removes invalid UTF-8 characters from `str`, and stores the result in
-// `output`.
-bool CheckAsciiAndRemoveInvalidUTF8(base::StringView str, std::string& output);
+// Wrapper around access(path, F_OK).
+bool FileExists(const std::string& path);
-#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
-bool WideToUTF8(const std::wstring& source, std::string& output);
-bool UTF8ToWide(const std::string& source, std::wstring& output);
-#endif // PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
+// Returns true if the path exists and is a directory.
+bool DirectoryExists(const std::string& path);
-// A BSD-style strlcpy without the return value.
-// Copies at most |dst_size|-1 characters. Unlike strncpy, it always \0
-// terminates |dst|, as long as |dst_size| is not 0.
-// Unlike strncpy and like strlcpy it does not zero-pad the rest of |dst|.
-// Returns nothing. The BSD strlcpy returns the size of |src|, which might
-// be > |dst_size|. Anecdotal experience suggests people assume the return value
-// is the number of bytes written in |dst|. That assumption can lead to
-// dangerous bugs.
-// In order to avoid being subtly uncompliant with strlcpy AND avoid misuse,
-// the choice here is to return nothing.
-inline void StringCopy(char* dst, const char* src, size_t dst_size) {
- for (size_t i = 0; i < dst_size; ++i) {
- if ((dst[i] = src[i]) == '\0') {
- return; // We hit and copied the null terminator.
- }
- }
+// Gets the extension for a filename. If the file has two extensions, returns
+// only the last one (foo.pb.gz => .gz). Returns empty string if there is no
+// extension.
+std::string GetFileExtension(const std::string& filename);
- // We were left off at dst_size. We over copied 1 byte. Null terminate.
- if (PERFETTO_LIKELY(dst_size > 0))
- dst[dst_size - 1] = 0;
-}
+// Returns the basename component of a path (the final component after the last
+// directory separator). Behaves like man 2 basename, but works with both '/'
+// and '\' separators for cross-platform compatibility.
+// Examples:
+// Basename("/usr/bin/ls") => "ls"
+// Basename("/usr/bin/") => "bin"
+// Basename("/") => "/"
+// Basename("foo") => "foo"
+// Basename("") => "."
+// Basename("C:\\Windows\\System32") => "System32"
+std::string Basename(const std::string& path);
-// Like snprintf() but returns the number of chars *actually* written (without
-// counting the null terminator) NOT "the number of chars which would have been
-// written to the final string if enough space had been available".
-// This should be used in almost all cases when the caller uses the return value
-// of snprintf(). If the return value is not used, there is no benefit in using
-// this wrapper, as this just calls snprintf() and mangles the return value.
-// It always null-terminates |dst| (even in case of errors), unless
-// |dst_size| == 0.
+// Returns the directory component of a path (everything up to but not
+// including the final component). Behaves like man 2 dirname, but works with
+// both '/' and '\' separators for cross-platform compatibility.
// Examples:
-// SprintfTrunc(x, 4, "123whatever"): returns 3 and writes "123\0".
-// SprintfTrunc(x, 4, "123"): returns 3 and writes "123\0".
-// SprintfTrunc(x, 3, "123"): returns 2 and writes "12\0".
-// SprintfTrunc(x, 2, "123"): returns 1 and writes "1\0".
-// SprintfTrunc(x, 1, "123"): returns 0 and writes "\0".
-// SprintfTrunc(x, 0, "123"): returns 0 and writes nothing.
-// NOTE: This means that the caller has no way to tell when truncation happens
-// vs the edge case of *just* fitting in the buffer.
-size_t SprintfTrunc(char* dst, size_t dst_size, const char* fmt, ...)
- PERFETTO_PRINTF_FORMAT(3, 4);
+// Dirname("/usr/bin/ls") => "/usr/bin"
+// Dirname("/usr/bin") => "/usr"
+// Dirname("/") => "/"
+// Dirname("foo") => "."
+// Dirname("") => "."
+// Dirname("C:\\Windows\\System32") => "C:\\Windows"
+std::string Dirname(const std::string& path);
-// Line number starts from 1
-struct LineWithOffset {
- base::StringView line;
- uint32_t line_offset;
- uint32_t line_num;
-};
+// Returns the length of the leading root component of a path: "/" on UNIX,
+// "C:\" or "\\" (UNC) on Windows. Returns 0 if the path is relative. Like
+// Basename() and Dirname(), both '/' and '\' are recognized on all platforms.
+// Stripping the returned prefix turns the path into a relative one.
+// Examples:
+// PathRootPrefixLength("/usr/bin/ls") => 1
+// PathRootPrefixLength("//usr/bin") => 2
+// PathRootPrefixLength("C:\\Windows") => 3
+// PathRootPrefixLength("C:foo") => 0 (relative to the current dir of drive
+// C:) PathRootPrefixLength("foo/bar") => 0
+size_t PathRootPrefixLength(const std::string& path);
-// For given string and offset Pfinds a line with character for
-// which offset points, what number is this line (starts from 1), and the offset
-// inside this line. returns std::nullopt if the offset points to
-// line break character or exceeds string length.
-std::optional<LineWithOffset> FindLineWithOffset(base::StringView str,
- uint32_t offset);
+// Returns true if the path starts with a root component. See
+// PathRootPrefixLength().
+bool IsAbsolutePath(const std::string& path);
-// A helper class to facilitate construction and usage of write-once stack
-// strings.
-// Example usage:
-// StackString<32> x("format %d %s", 42, string_arg);
-// TakeString(x.c_str() | x.string_view() | x.ToStdString());
-// Rather than char x[32] + sprintf.
-// Advantages:
-// - Avoids useless zero-fills caused by people doing `char buf[32] {}` (mainly
-// by fearing unknown snprintf failure modes).
-// - Makes the code more robust in case of snprintf truncations (len() and
-// string_view() will return the truncated length, unlike snprintf).
-template <size_t N>
-class StackString {
+// Puts the path to all files under |dir_path| in |output|, recursively walking
+// subdirectories. File paths are relative to |dir_path|. Only files are
+// included, not directories. Path separator is always '/', even on windows (not
+// '\').
+base::Status ListFilesRecursive(const std::string& dir_path,
+ std::vector<std::string>& output);
+
+// Lists immediate subdirectories in |dir_path| (non-recursive). Directory names
+// are relative to |dir_path| and do not include the path separator. Returns
+// only directories, not files. Works on both Unix and Windows.
+base::Status ListDirectories(const std::string& dir_path,
+ std::vector<std::string>& output);
+
+// Sets |path|'s owner group to |group_name| and permission mode bits to
+// |mode_bits|.
+base::Status SetFilePermissions(const std::string& path,
+ const std::string& group_name,
+ const std::string& mode_bits);
+
+// Returns the size of the file located at |path|, or nullopt in case of error.
+std::optional<uint64_t> GetFileSize(const std::string& path);
+
+// Returns the size of the open file |fd|, or nullopt in case of error.
+std::optional<uint64_t> GetFileSize(PlatformHandle fd);
+
+#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
+// On Windows PlatformHandle is a HANDLE, not a file descriptor. This overload
+// accepts the CRT file descriptors returned by base::OpenFile(). On other
+// platforms PlatformHandle is an int, so the overload above already covers it.
+std::optional<uint64_t> GetFileSize(int fd);
+#endif
+
+// This class uses inotify (on Linux/Android) to watch for the creation of
+// files in the filesystem. When the specified file is created, it triggers a
+// callback function.
+// Destroying the returned unique_ptr will automatically unregister the watch.
+//
+// Note: This only works with filesystem paths (not abstract sockets or other
+// special file types).
+// It's only supported on Linux and Android, it's a no-op (returns nullptr) on
+// other platforms.
+//
+// Usage:
+// auto watch = LinuxFileWatch::WatchFileCreation(
+// task_runner, "/tmp/my_file", []() {
+// // Called when /tmp/my_file is created
+// });
+class LinuxFileWatch {
public:
- explicit PERFETTO_PRINTF_FORMAT(/* 1=this */ 2, 3)
- StackString(const char* fmt, ...) {
- buf_[0] = '\0';
- va_list args;
- va_start(args, fmt);
- int res = vsnprintf(buf_, sizeof(buf_), fmt, args);
- va_end(args);
- buf_[sizeof(buf_) - 1] = '\0';
- len_ = res < 0 ? 0 : std::min(static_cast<size_t>(res), sizeof(buf_) - 1);
- }
+ // Creates a watcher for file creation. Returns nullptr if the path is not a
+ // valid filesystem path or if the platform doesn't support inotify. The
+ // callback will be invoked on the provided TaskRunner when the file is
+ // created.
+ static std::unique_ptr<LinuxFileWatch> WatchFileCreation(
+ TaskRunner*,
+ const char* path,
+ std::function<void()> callback);
- StringView string_view() const { return StringView(buf_, len_); }
- std::string ToStdString() const { return std::string(buf_, len_); }
- const char* c_str() const { return buf_; }
- size_t len() const { return len_; }
- char* mutable_data() { return buf_; }
+ virtual ~LinuxFileWatch();
- private:
- char buf_[N];
- size_t len_ = 0; // Does not include the \0.
+ protected:
+ LinuxFileWatch() = default;
};
} // namespace base
} // namespace perfetto
-#endif // INCLUDE_PERFETTO_EXT_BASE_STRING_UTILS_H_
+#endif // INCLUDE_PERFETTO_EXT_BASE_FILE_UTILS_H_
+// gen_amalgamated begin header: include/perfetto/ext/base/string_splitter.h
/*
- * Copyright (C) 2021 The Android Open Source Project
+ * 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.
@@ -971,185 +881,239 @@ class StackString {
* limitations under the License.
*/
-// gen_amalgamated expanded: #include "perfetto/ext/base/android_utils.h"
-
-// gen_amalgamated expanded: #include "perfetto/base/build_config.h"
+#ifndef INCLUDE_PERFETTO_EXT_BASE_STRING_SPLITTER_H_
+#define INCLUDE_PERFETTO_EXT_BASE_STRING_SPLITTER_H_
#include <string>
-#if PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID)
-#include <sys/system_properties.h>
-#endif
-
-// gen_amalgamated expanded: #include "perfetto/base/compiler.h"
-// gen_amalgamated expanded: #include "perfetto/base/logging.h"
-// gen_amalgamated expanded: #include "perfetto/base/time.h"
-// gen_amalgamated expanded: #include "perfetto/ext/base/string_utils.h"
+namespace perfetto {
+namespace base {
-#if !PERFETTO_BUILDFLAG(PERFETTO_OS_WIN) && \
- !PERFETTO_BUILDFLAG(PERFETTO_OS_NACL) && \
- !PERFETTO_BUILDFLAG(PERFETTO_OS_WASM)
-#include <sys/utsname.h>
-#include <unistd.h>
-#endif
+// C++ version of strtok(). Splits a string without making copies or any heap
+// allocations. Destructs the original string passed in input.
+// Supports the special case of using \0 as a delimiter.
+// The token returned in output are valid as long as the input string is valid.
+class StringSplitter {
+ public:
+ // Whether an empty string (two delimiters side-to-side) is a valid token.
+ enum class EmptyTokenMode {
+ DISALLOW_EMPTY_TOKENS,
+ ALLOW_EMPTY_TOKENS,
-#if PERFETTO_BUILDFLAG(PERFETTO_OS_LINUX_BUT_NOT_QNX) || \
- PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID)
-#include <sys/sysinfo.h>
-#endif
+ DEFAULT = DISALLOW_EMPTY_TOKENS,
+ };
-namespace perfetto {
-namespace base {
+ // Can take ownership of the string if passed via std::move(), e.g.:
+ // StringSplitter(std::move(str), '\n');
+ StringSplitter(std::string,
+ char delimiter,
+ EmptyTokenMode empty_token_mode = EmptyTokenMode::DEFAULT);
-#if PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID)
+ // Splits a C-string. The input string will be forcefully null-terminated (so
+ // str[size - 1] should be == '\0' or the last char will be truncated).
+ StringSplitter(char* str,
+ size_t size,
+ char delimiter,
+ EmptyTokenMode empty_token_mode = EmptyTokenMode::DEFAULT);
-std::string GetAndroidProp(const char* name) {
- std::string ret;
-#if __ANDROID_API__ >= 26
- const prop_info* pi = __system_property_find(name);
- if (!pi) {
- return ret;
- }
- __system_property_read_callback(
- pi,
- [](void* dst_void, const char*, const char* value, uint32_t) {
- std::string& dst = *static_cast<std::string*>(dst_void);
- dst = value;
- },
- &ret);
-#else // __ANDROID_API__ < 26
- char value_buf[PROP_VALUE_MAX];
- int len = __system_property_get(name, value_buf);
- if (len > 0 && static_cast<size_t>(len) < sizeof(value_buf)) {
- ret = std::string(value_buf, static_cast<size_t>(len));
- }
-#endif
- return ret;
-}
+ // Splits the current token from an outer StringSplitter instance. This is to
+ // chain splitters as follows:
+ // for (base::StringSplitter lines(x, '\n'); ss.Next();)
+ // for (base::StringSplitter words(&lines, ' '); words.Next();)
+ StringSplitter(StringSplitter*,
+ char delimiter,
+ EmptyTokenMode empty_token_mode = EmptyTokenMode::DEFAULT);
-#endif // PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID)
+ // Returns true if a token is found (in which case it will be stored in
+ // cur_token()), false if no more tokens are found.
+ bool Next();
-Utsname GetUtsname() {
- Utsname utsname_info;
-#if !PERFETTO_BUILDFLAG(PERFETTO_OS_WIN) && \
- !PERFETTO_BUILDFLAG(PERFETTO_OS_NACL) && \
- !PERFETTO_BUILDFLAG(PERFETTO_OS_WASM)
- struct utsname uname_info;
- if (uname(&uname_info) == 0) {
- utsname_info.sysname = uname_info.sysname;
- utsname_info.version = uname_info.version;
- utsname_info.machine = uname_info.machine;
- utsname_info.release = uname_info.release;
- } else {
- PERFETTO_ELOG("Unable to read Utsname information");
- }
-#endif // !PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
- return utsname_info;
-}
+ // Returns the next token if found (in which case it will be stored in
+ // cur_token()), nullptr if no more tokens are found.
+ char* NextToken() { return Next() ? cur_token() : nullptr; }
-SystemInfo GetSystemInfo() {
- SystemInfo info;
+ // Returns the current token iff last call to Next() returned true. In this
+ // case it guarantees that the returned string is always null terminated.
+ // In all other cases (before the 1st call to Next() and after Next() returns
+ // false) returns nullptr.
+ char* cur_token() { return cur_; }
- info.timezone_off_mins = GetTimezoneOffsetMins();
+ // Returns the length of the current token (excluding the null terminator).
+ size_t cur_token_size() const { return cur_size_; }
-#if !PERFETTO_BUILDFLAG(PERFETTO_OS_WIN) && \
- !PERFETTO_BUILDFLAG(PERFETTO_OS_NACL) && \
- !PERFETTO_BUILDFLAG(PERFETTO_OS_WASM)
+ // Return the untokenized remainder of the input string that occurs after the
+ // current token.
+ char* remainder() { return next_; }
- info.utsname_info = GetUtsname();
- info.page_size = static_cast<uint32_t>(sysconf(_SC_PAGESIZE));
- info.num_cpus = static_cast<uint32_t>(sysconf(_SC_NPROCESSORS_CONF));
+ // Returns the size of the untokenized input
+ size_t remainder_size() { return static_cast<size_t>(end_ - next_); }
-#if PERFETTO_BUILDFLAG(PERFETTO_OS_LINUX_BUT_NOT_QNX) || \
- PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID)
- // Use the Linux-specific sysinfo() system call on Linux and Android.
- // https://man7.org/linux/man-pages/man2/sysinfo.2.html
- struct sysinfo sys_info;
- if (sysinfo(&sys_info) == 0) {
- info.system_ram_bytes =
- static_cast<uint64_t>(sys_info.totalram) * sys_info.mem_unit;
- }
-#else
- // POSIX Fallback (macOS, BSD, etc.): Use sysconf() to get physical pages.
- long pages = sysconf(_SC_PHYS_PAGES);
- if (pages > 0 && info.page_size.has_value()) {
- info.system_ram_bytes = static_cast<uint64_t>(pages) * (*info.page_size);
- }
-#endif
-#endif // !PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
-#if PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID)
- info.android_build_fingerprint = GetAndroidProp("ro.build.fingerprint");
- if (info.android_build_fingerprint.empty()) {
- PERFETTO_ELOG("Unable to read ro.build.fingerprint");
+ private:
+ StringSplitter(const StringSplitter&) = delete;
+ StringSplitter& operator=(const StringSplitter&) = delete;
+ void Initialize(char* str, size_t size);
+
+ std::string str_;
+ char* cur_;
+ size_t cur_size_;
+ char* next_;
+ char* end_; // STL-style, points one past the last char.
+ const char delimiter_;
+ const EmptyTokenMode empty_token_mode_;
+};
+
+} // namespace base
+} // namespace perfetto
+
+#endif // INCLUDE_PERFETTO_EXT_BASE_STRING_SPLITTER_H_
+// gen_amalgamated begin header: include/perfetto/ext/base/string_utils.h
+// gen_amalgamated begin header: include/perfetto/ext/base/string_view.h
+// gen_amalgamated begin header: include/perfetto/ext/base/fnv_hash.h
+/*
+ * 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.
+ */
+
+#ifndef INCLUDE_PERFETTO_EXT_BASE_FNV_HASH_H_
+#define INCLUDE_PERFETTO_EXT_BASE_FNV_HASH_H_
+
+#include <stddef.h>
+#include <stdint.h>
+#include <string_view>
+#include <type_traits>
+#include <utility>
+
+namespace perfetto::base {
+
+// A helper class which computes a 64-bit hash of the input data.
+// The algorithm used is FNV-1a as it is fast and easy to implement and has
+// relatively few collisions.
+// WARNING: This hash function should not be used for any cryptographic purpose.
+class FnvHasher {
+ public:
+ // Creates an empty hash object
+ constexpr FnvHasher() = default;
+
+ // Hashes a numeric value.
+ template <
+ typename T,
+ typename std::enable_if<std::is_arithmetic<T>::value, bool>::type = true>
+ void Update(T data) {
+ Update(reinterpret_cast<const char*>(&data), sizeof(data));
}
- info.android_device_manufacturer = GetAndroidProp("ro.product.manufacturer");
- if (info.android_device_manufacturer.empty()) {
- PERFETTO_ELOG("Unable to read ro.product.manufacturer");
+ constexpr void Update(char c) { return Update(&c, 1); }
+
+ // Using the loop instead of "Update(str, strlen(str))" to avoid looping twice
+ constexpr void Update(const char* str) {
+ for (const auto* p = str; *p; ++p)
+ Update(*p);
}
- std::string sdk_str_value = GetAndroidProp("ro.build.version.sdk");
- info.android_sdk_version = StringToUInt64(sdk_str_value);
- if (!info.android_sdk_version.has_value()) {
- PERFETTO_ELOG("Unable to read ro.build.version.sdk");
+ // Hashes a byte array.
+ constexpr void Update(const char* data, size_t size) {
+ for (size_t i = 0; i < size; i++) {
+ result_ ^= static_cast<uint8_t>(data[i]);
+ // Note: Arithmetic overflow of unsigned integers is well defined in C++
+ // standard unlike signed integers.
+ // https://stackoverflow.com/a/41280273
+ result_ *= kFnv1a64Prime;
+ }
}
- info.android_soc_model = GetAndroidProp("ro.soc.model");
- if (info.android_soc_model.empty()) {
- PERFETTO_ELOG("Unable to read ro.soc.model");
+ // Allow hashing anything that has `data` and `size` and has the kHashable
+ // trait (e.g., base::StringView).
+ template <typename T, typename = std::enable_if_t<T::kHashable>>
+ constexpr void Update(const T& t) {
+ if constexpr (std::is_member_function_pointer_v<decltype(&T::data)>) {
+ Update(t.data(), t.size());
+ } else {
+ Update(t.data, t.size);
+ }
}
- // guest_soc model is not always present
- info.android_guest_soc_model = GetAndroidProp("ro.boot.guest_soc.model");
+ constexpr void Update(std::string_view s) { Update(s.data(), s.size()); }
- info.android_hardware_revision = GetAndroidProp("ro.boot.hardware.revision");
- if (info.android_hardware_revision.empty()) {
- PERFETTO_ELOG("Unable to read ro.boot.hardware.revision");
- }
+ constexpr uint64_t digest() const { return result_; }
- info.android_storage_model = GetAndroidProp("ro.boot.hardware.ufs");
- if (info.android_storage_model.empty()) {
- PERFETTO_ELOG("Unable to read ro.boot.hardware.ufs");
+ // Usage:
+ // uint64_t hashed_value =
+ // FnvHasher::Combine(33, false, "ABC", 458L, 3u, 'x');
+ template <typename... Ts>
+ static constexpr uint64_t Combine(Ts&&... args) {
+ FnvHasher hasher;
+ hasher.UpdateAll(std::forward<Ts>(args)...);
+ return hasher.digest();
}
- info.android_ram_model = GetAndroidProp("ro.boot.hardware.ddr");
- if (info.android_ram_model.empty()) {
- PERFETTO_ELOG("Unable to read ro.boot.hardware.ddr");
+ // Creates a hasher with `args` already hashed.
+ //
+ // Usage:
+ // FnvHasher partial = FnvHasher::CreatePartial(33, false, "ABC", 458L);
+ template <typename... Ts>
+ static constexpr FnvHasher CreatePartial(Ts&&... args) {
+ FnvHasher hasher;
+ hasher.UpdateAll(std::forward<Ts>(args)...);
+ return hasher;
}
- info.android_serial_console = GetAndroidProp("init.svc.console");
- if (info.android_serial_console.empty()) {
- PERFETTO_ELOG("Unable to read init.svc.console");
+ // `hasher.UpdateAll(33, false, "ABC")` is shorthand for:
+ // `hasher.Update(33); hasher.Update(false); hasher.Update("ABC");`
+ constexpr void UpdateAll() {}
+
+ template <typename T, typename... Ts>
+ constexpr void UpdateAll(T&& arg, Ts&&... args) {
+ Update(arg);
+ UpdateAll(std::forward<Ts>(args)...);
}
-#endif // PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID)
- return info;
-}
+ private:
+ static constexpr uint64_t kFnv1a64OffsetBasis = 0xcbf29ce484222325;
+ static constexpr uint64_t kFnv1a64Prime = 0x100000001b3;
-std::string GetPerfettoMachineName() {
- const char* env_name = getenv("PERFETTO_MACHINE_NAME");
- if (env_name) {
- return env_name;
+ uint64_t result_ = kFnv1a64OffsetBasis;
+};
+
+// base::FnvHash uses base::FnvHasher for integer values and falls back to
+// std::hash for other types. This is needed as std::hash for integers is just
+// the identity function and Perfetto uses open-addressing hash table, which are
+// very sensitive to hash quality and are known to degrade in performance
+// when using std::hash.
+template <typename T>
+struct FnvHash {
+ // Version for ints, using base::FnvHasher.
+ template <typename U = T>
+ auto operator()(const U& x) ->
+ typename std::enable_if<std::is_arithmetic<U>::value, size_t>::type
+ const {
+ return FnvHasher::Combine(x);
}
-#if PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID)
- std::string name = base::GetAndroidProp("traced.machine_name");
- if (name.empty()) {
- name = GetUtsname().sysname;
+
+ // Version for non-ints, falling back to std::hash.
+ template <typename U = T>
+ auto operator()(const U& x) ->
+ typename std::enable_if<!std::is_arithmetic<U>::value, size_t>::type
+ const {
+ return std::hash<U>()(x);
}
- return name;
-#else
- return GetUtsname().sysname;
-#endif
-}
+};
-} // namespace base
-} // namespace perfetto
-// gen_amalgamated begin source: src/base/base64.cc
-// gen_amalgamated begin header: include/perfetto/ext/base/base64.h
-// gen_amalgamated begin header: include/perfetto/ext/base/utils.h
-// gen_amalgamated begin header: include/perfetto/ext/base/sys_types.h
+} // namespace perfetto::base
+
+#endif // INCLUDE_PERFETTO_EXT_BASE_FNV_HASH_H_
/*
- * Copyright (C) 2022 The Android Open Source Project
+ * 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.
@@ -1164,73 +1128,205 @@ std::string GetPerfettoMachineName() {
* limitations under the License.
*/
-#ifndef INCLUDE_PERFETTO_EXT_BASE_SYS_TYPES_H_
-#define INCLUDE_PERFETTO_EXT_BASE_SYS_TYPES_H_
+#ifndef INCLUDE_PERFETTO_EXT_BASE_STRING_VIEW_H_
+#define INCLUDE_PERFETTO_EXT_BASE_STRING_VIEW_H_
-// This headers deals with sys types commonly used in the codebase that are
-// missing on Windows.
+#include <string.h>
-#include <sys/types.h> // IWYU pragma: export
-#include <cstdint>
+#include <algorithm>
+#include <string>
+#include <vector>
// gen_amalgamated expanded: #include "perfetto/base/build_config.h"
+// gen_amalgamated expanded: #include "perfetto/base/logging.h"
+// gen_amalgamated expanded: #include "perfetto/ext/base/fnv_hash.h"
-#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
+namespace perfetto {
+namespace base {
-#ifdef __MINGW32__
+// A string-like object that refers to a non-owned piece of memory.
+// Strings are internally NOT null terminated.
+class StringView {
+ public:
+ // Allow hashing with base::FnvHash.
+ static constexpr bool kHashable = true;
+ static constexpr size_t npos = static_cast<size_t>(-1);
-using uid_t = int;
-using gid_t = int;
+ StringView() : data_(nullptr), size_(0) {}
+ StringView(const StringView&) = default;
+ StringView& operator=(const StringView&) = default;
+ StringView(const char* data, size_t size) : data_(data), size_(size) {
+ PERFETTO_DCHECK(size == 0 || data != nullptr);
+ }
-#else
+ // Allow implicit conversion from any class that has a |data| and |size| field
+ // and has the kConvertibleToStringView trait (e.g., protozero::ConstChars).
+ template <typename T, typename = std::enable_if<T::kConvertibleToStringView>>
+ StringView(const T& x) : StringView(x.data, x.size) {
+ PERFETTO_DCHECK(x.size == 0 || x.data != nullptr);
+ }
-#if !PERFETTO_BUILDFLAG(PERFETTO_COMPILER_GCC)
-// MinGW has these. clang-cl and MSVC, which use just the Windows SDK, don't.
-using uid_t = int;
-using gid_t = int;
-using pid_t = int;
-#endif // !GCC
+ // Creates a StringView from a null-terminated C string.
+ // Deliberately not "explicit".
+ StringView(const char* cstr) : data_(cstr), size_(strlen(cstr)) {
+ PERFETTO_DCHECK(cstr != nullptr);
+ }
-#if defined(_WIN64)
-using ssize_t = int64_t;
-#else
-using ssize_t = long;
-#endif // _WIN64
+ StringView(std::string_view str) : data_(str.data()), size_(str.size()) {}
-#endif // __MINGW32__
+ // This instead has to be explicit, as creating a StringView out of a
+ // std::string can be subtle.
+ explicit StringView(const std::string& str)
+ : data_(str.data()), size_(str.size()) {}
-#endif // OS_WIN
+ bool empty() const { return size_ == 0; }
+ size_t size() const { return size_; }
+ const char* data() const { return data_; }
+ const char* begin() const { return data_; }
+ const char* end() const { return data_ + size_; }
-#if PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID)
-// From libcutils' android_filesystem_config.h
-#ifndef AID_ROOT
-#define AID_ROOT 0
-#endif
-#ifndef AID_STATSD
-#define AID_STATSD 1066
-#endif
-#ifndef AID_SHELL
-#define AID_SHELL 2000
-#endif
+ char at(size_t pos) const {
+ PERFETTO_DCHECK(pos < size_);
+ return data_[pos];
+ }
+
+ size_t find(char c, size_t start_pos = 0) const {
+ for (size_t i = start_pos; i < size_; ++i) {
+ if (data_[i] == c)
+ return i;
+ }
+ return npos;
+ }
+
+ size_t find(const StringView& str, size_t start_pos = 0) const {
+ if (start_pos > size())
+ return npos;
+ auto it = std::search(begin() + start_pos, end(), str.begin(), str.end());
+ size_t pos = static_cast<size_t>(it - begin());
+ return pos + str.size() <= size() ? pos : npos;
+ }
+
+ size_t find(const char* str, size_t start_pos = 0) const {
+ return find(StringView(str), start_pos);
+ }
+
+ size_t rfind(char c) const {
+ for (size_t i = size_; i > 0; --i) {
+ if (data_[i - 1] == c)
+ return i - 1;
+ }
+ return npos;
+ }
+
+ StringView substr(size_t pos, size_t count = npos) const {
+ if (pos >= size_)
+ return StringView("", 0);
+ size_t rcount = std::min(count, size_ - pos);
+ return StringView(data_ + pos, rcount);
+ }
+
+ bool CaseInsensitiveEq(const StringView& other) const {
+ if (size() != other.size())
+ return false;
+ if (size() == 0)
+ return true;
+#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
+ return _strnicmp(data(), other.data(), size()) == 0;
+#else
+ return strncasecmp(data(), other.data(), size()) == 0;
#endif
+ }
-namespace perfetto {
-namespace base {
+ bool CaseInsensitiveOneOf(const std::vector<StringView>& others) const {
+ for (const StringView& other : others) {
+ if (CaseInsensitiveEq(other)) {
+ return true;
+ }
+ }
+ return false;
+ }
-// The machine ID used in the tracing core.
-using MachineID = uint32_t;
-// The default value reserved for the host trace.
-constexpr MachineID kDefaultMachineID = 0;
+ bool StartsWith(const StringView& other) const {
+ if (other.size() == 0)
+ return true;
+ if (size() == 0)
+ return false;
+ if (other.size() > size())
+ return false;
+ return memcmp(data(), other.data(), other.size()) == 0;
+ }
-constexpr uid_t kInvalidUid = static_cast<uid_t>(-1);
-constexpr pid_t kInvalidPid = static_cast<pid_t>(-1);
+ bool EndsWith(const StringView& other) const {
+ if (other.size() == 0)
+ return true;
+ if (size() == 0)
+ return false;
+ if (other.size() > size())
+ return false;
+ size_t off = size() - other.size();
+ return memcmp(data() + off, other.data(), other.size()) == 0;
+ }
+
+ std::string ToStdString() const {
+ return size_ == 0 ? "" : std::string(data_, size_);
+ }
+
+ uint64_t Hash() const {
+ base::FnvHasher hasher;
+ hasher.Update(data_, size_);
+ return hasher.digest();
+ }
+
+ private:
+ const char* data_ = nullptr;
+ size_t size_ = 0;
+};
+
+inline bool operator==(const StringView& x, const StringView& y) {
+ if (x.size() != y.size())
+ return false;
+ if (x.size() == 0)
+ return true;
+ return memcmp(x.data(), y.data(), x.size()) == 0;
+}
+
+inline bool operator!=(const StringView& x, const StringView& y) {
+ return !(x == y);
+}
+
+inline bool operator<(const StringView& x, const StringView& y) {
+ auto size = std::min(x.size(), y.size());
+ if (size == 0)
+ return x.size() < y.size();
+ int result = memcmp(x.data(), y.data(), size);
+ return result < 0 || (result == 0 && x.size() < y.size());
+}
+
+inline bool operator>=(const StringView& x, const StringView& y) {
+ return !(x < y);
+}
+
+inline bool operator>(const StringView& x, const StringView& y) {
+ return y < x;
+}
+
+inline bool operator<=(const StringView& x, const StringView& y) {
+ return !(y < x);
+}
} // namespace base
} // namespace perfetto
-#endif // INCLUDE_PERFETTO_EXT_BASE_SYS_TYPES_H_
+template <>
+struct std::hash<::perfetto::base::StringView> {
+ size_t operator()(const ::perfetto::base::StringView& sv) const {
+ return static_cast<size_t>(sv.Hash());
+ }
+};
+
+#endif // INCLUDE_PERFETTO_EXT_BASE_STRING_VIEW_H_
/*
- * Copyright (C) 2017 The Android Open Source Project
+ * 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.
@@ -1245,275 +1341,312 @@ constexpr pid_t kInvalidPid = static_cast<pid_t>(-1);
* limitations under the License.
*/
-#ifndef INCLUDE_PERFETTO_EXT_BASE_UTILS_H_
-#define INCLUDE_PERFETTO_EXT_BASE_UTILS_H_
+#ifndef INCLUDE_PERFETTO_EXT_BASE_STRING_UTILS_H_
+#define INCLUDE_PERFETTO_EXT_BASE_STRING_UTILS_H_
-#include <errno.h>
-#include <stddef.h>
-#include <stdint.h>
-#include <stdio.h>
+#include <stdarg.h>
#include <stdlib.h>
+#include <string.h>
-#include <atomic>
-#include <functional>
-#include <limits>
-#include <memory>
+#include <charconv>
+#include <cinttypes>
+#include <optional>
#include <string>
+#include <string_view>
+#include <system_error>
+#include <vector>
-// gen_amalgamated expanded: #include "perfetto/base/build_config.h"
-// gen_amalgamated expanded: #include "perfetto/base/compiler.h"
-// gen_amalgamated expanded: #include "perfetto/ext/base/sys_types.h"
-
-#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
-// Even if Windows has errno.h, the all syscall-restart behavior does not apply.
-// Trying to handle EINTR can cause more harm than good if errno is left stale.
-// Chromium does the same.
-#define PERFETTO_EINTR(x) (x)
-#else
-#define PERFETTO_EINTR(x) \
- ([&] { \
- decltype(x) eintr_wrapper_result; \
- do { \
- eintr_wrapper_result = (x); \
- } while (eintr_wrapper_result == -1 && errno == EINTR); \
- return eintr_wrapper_result; \
- }())
-#endif
+// gen_amalgamated expanded: #include "perfetto/ext/base/string_view.h"
namespace perfetto {
namespace base {
-namespace internal {
-extern std::atomic<uint32_t> g_cached_page_size;
-uint32_t GetSysPageSizeSlowpath();
-} // namespace internal
+inline char Lowercase(char c) {
+ return ('A' <= c && c <= 'Z') ? static_cast<char>(c - ('A' - 'a')) : c;
+}
-// Returns the system's page size. Use this when dealing with mmap, madvise and
-// similar mm-related syscalls.
-// This function might be called in hot paths. Avoid calling getpagesize() all
-// the times, in many implementations getpagesize() calls sysconf() which is
-// not cheap.
-inline uint32_t GetSysPageSize() {
- const uint32_t page_size =
- internal::g_cached_page_size.load(std::memory_order_relaxed);
- return page_size != 0 ? page_size : internal::GetSysPageSizeSlowpath();
+inline char Uppercase(char c) {
+ return ('a' <= c && c <= 'z') ? static_cast<char>(c + ('A' - 'a')) : c;
}
-template <typename T, size_t TSize>
-constexpr size_t ArraySize(const T (&)[TSize]) {
- return TSize;
+// Returns true if the character is an ASCII whitespace character.
+// This is a locale-independent version that only considers ASCII whitespace:
+// space (0x20), tab (0x09), newline (0x0A), vertical tab (0x0B),
+// form feed (0x0C), and carriage return (0x0D).
+inline bool IsSpace(char c) {
+ return c == ' ' || c == '\t' || c == '\n' || c == '\v' || c == '\f' ||
+ c == '\r';
}
-// Adds `a` and `b`, clamping to INT64_MIN / INT64_MAX on overflow instead of
-// wrapping (which is UB and can flip the sign of the result).
-inline int64_t SaturatingAdd(int64_t a, int64_t b) {
- constexpr int64_t kMax = std::numeric_limits<int64_t>::max();
- constexpr int64_t kMin = std::numeric_limits<int64_t>::min();
-#if defined(__clang__) || defined(__GNUC__)
- int64_t result;
- if (PERFETTO_UNLIKELY(__builtin_add_overflow(a, b, &result)))
- return a < 0 ? kMin : kMax;
- return result;
-#else
- if (b > 0 && a > kMax - b)
- return kMax;
- if (b < 0 && a < kMin - b)
- return kMin;
- return a + b;
-#endif
+inline std::optional<uint32_t> CStringToUInt32(const char* s, int base = 10) {
+ char* endptr = nullptr;
+ auto value = static_cast<uint32_t>(strtoul(s, &endptr, base));
+ return (*s && !*endptr) ? std::make_optional(value) : std::nullopt;
}
-// Multiplies `a` by `b`, clamping to INT64_MIN / INT64_MAX on overflow instead
-// of wrapping (which is UB and can flip the sign of the result).
-inline int64_t SaturatingMultiply(int64_t a, int64_t b) {
- constexpr int64_t kMax = std::numeric_limits<int64_t>::max();
- constexpr int64_t kMin = std::numeric_limits<int64_t>::min();
-#if defined(__clang__) || defined(__GNUC__)
- int64_t result;
- if (PERFETTO_UNLIKELY(__builtin_mul_overflow(a, b, &result))) {
- // On overflow the true product's sign is the XOR of the operands' signs.
- // Neither operand can be zero here (0 never overflows).
- return ((a < 0) == (b < 0)) ? kMax : kMin;
- }
+inline std::optional<int32_t> CStringToInt32(const char* s, int base = 10) {
+ char* endptr = nullptr;
+ auto value = static_cast<int32_t>(strtol(s, &endptr, base));
+ return (*s && !*endptr) ? std::make_optional(value) : std::nullopt;
+}
+
+// Note: it saturates to 7fffffffffffffff if parsing a hex number >= 0x8000...
+inline std::optional<int64_t> CStringToInt64(const char* s, int base = 10) {
+ char* endptr = nullptr;
+ auto value = static_cast<int64_t>(strtoll(s, &endptr, base));
+ return (*s && !*endptr) ? std::make_optional(value) : std::nullopt;
+}
+
+inline std::optional<uint64_t> CStringToUInt64(const char* s, int base = 10) {
+ char* endptr = nullptr;
+ auto value = static_cast<uint64_t>(strtoull(s, &endptr, base));
+ return (*s && !*endptr) ? std::make_optional(value) : std::nullopt;
+}
+
+double StrToD(const char* nptr, char** endptr);
+
+inline std::optional<double> CStringToDouble(const char* s) {
+ char* endptr = nullptr;
+ double value = StrToD(s, &endptr);
+ std::optional<double> result(std::nullopt);
+ if (*s != '\0' && *endptr == '\0')
+ result = value;
return result;
-#else
- // Portable fallback (e.g. MSVC cl.exe): detect overflow *before* multiplying
- // by dividing a limit by one operand, which never itself overflows.
- if (a == 0 || b == 0)
- return 0;
- if ((a < 0) == (b < 0)) { // Same sign: product is positive.
- if (a > 0 ? (a > kMax / b) : (a < kMax / b))
- return kMax;
- } else { // Opposite signs: product is negative.
- if (a > 0 ? (b < kMin / a) : (a < kMin / b))
- return kMin;
- }
- return a * b;
-#endif
}
-// Function object which invokes 'free' on its parameter, which must be
-// a pointer. Can be used to store malloc-allocated pointers in std::unique_ptr:
-//
-// std::unique_ptr<int, base::FreeDeleter> foo_ptr(
-// static_cast<int*>(malloc(sizeof(int))));
-struct FreeDeleter {
- inline void operator()(void* ptr) const { free(ptr); }
-};
+inline std::optional<uint32_t> StringToUInt32(const std::string& s,
+ int base = 10) {
+ return CStringToUInt32(s.c_str(), base);
+}
-template <typename T>
-constexpr T AssumeLittleEndian(T value) {
-#if !PERFETTO_IS_LITTLE_ENDIAN()
- static_assert(false, "Unimplemented on big-endian archs");
-#endif
- return value;
+inline std::optional<int32_t> StringToInt32(const std::string& s,
+ int base = 10) {
+ return CStringToInt32(s.c_str(), base);
}
-// Round up |size| to a multiple of |alignment| (must be a power of two).
-inline constexpr size_t AlignUp(size_t size, size_t alignment) {
- return (size + alignment - 1) & ~(alignment - 1);
+inline std::optional<uint64_t> StringToUInt64(const std::string& s,
+ int base = 10) {
+ return CStringToUInt64(s.c_str(), base);
}
-// Round down |size| to a multiple of |alignment| (must be a power of two).
-inline constexpr size_t AlignDown(size_t size, size_t alignment) {
- return size & ~(alignment - 1);
+inline std::optional<int64_t> StringToInt64(const std::string& s,
+ int base = 10) {
+ return CStringToInt64(s.c_str(), base);
}
-template <typename T>
-inline constexpr bool IsPowerOfTwo(T x) {
- static_assert(std::is_unsigned_v<T> && std::is_integral_v<T>,
- "T must be an unsigned integer");
- return x != 0 && (x & (x - 1)) == 0;
+inline std::optional<double> StringToDouble(const std::string& s) {
+ return CStringToDouble(s.c_str());
}
-// Returns the smallest power of two greater than or equal to |x|. Returns zero
-// for zero or when the result is not representable by T.
template <typename T>
-inline constexpr T RoundUpToPowerOfTwo(T x) {
- static_assert(std::is_unsigned_v<T> && std::is_integral_v<T>,
- "T must be an unsigned integer");
- if (x == 0) {
- return 0;
- }
- --x;
- for (size_t shift = 1; shift < sizeof(T) * 8; shift *= 2) {
- x |= x >> shift;
+inline std::optional<T> StringViewToNumber(const base::StringView& sv,
+ int base = 10) {
+ // std::from_chars() does not regonize the leading '+' character and only
+ // recognizes '-' so remove the '+' if it exists to avoid errors and match
+ // the behavior of the other string conversion utilities above.
+ size_t start_offset = !sv.empty() && sv.at(0) == '+' ? 1 : 0;
+ T value;
+ auto result =
+ std::from_chars(sv.begin() + start_offset, sv.end(), value, base);
+ if (result.ec == std::errc() && result.ptr == sv.end()) {
+ return value;
+ } else {
+ return std::nullopt;
}
- return ++x;
}
-// TODO(primiano): clean this up and move all existing usages to the constexpr
-// version above.
-template <size_t alignment>
-constexpr size_t AlignUp(size_t size) {
- static_assert(IsPowerOfTwo(alignment), "alignment must be a pow2");
- return AlignUp(size, alignment);
+inline std::optional<uint32_t> StringViewToUInt32(const base::StringView& sv,
+ int base = 10) {
+ // std::from_chars() does not recognize the leading '-' character for
+ // unsigned conversions, but strtol does. To Mimic the behavior of strtol,
+ // attempt a signed converion if we see a leading '-', and then cast the
+ // result back to unsigned.
+ if (sv.size() > 0 && sv.at(0) == '-') {
+ return static_cast<std::optional<uint32_t> >(
+ StringViewToNumber<int32_t>(sv, base));
+ } else {
+ return StringViewToNumber<uint32_t>(sv, base);
+ }
}
-inline bool IsAgain(int err) {
- return err == EAGAIN || err == EWOULDBLOCK;
+inline std::optional<int32_t> StringViewToInt32(const base::StringView& sv,
+ int base = 10) {
+ return StringViewToNumber<int32_t>(sv, base);
}
-// setenv(2)-equivalent. Deals with Windows vs Posix discrepancies.
-void SetEnv(const std::string& key, const std::string& value);
-
-// unsetenv(2)-equivalent. Deals with Windows vs Posix discrepancies.
-void UnsetEnv(const std::string& key);
-
-// Returns true if |fd| is connected to an interactive terminal (TTY). Deals
-// with Windows vs Posix discrepancies (isatty() vs _isatty()).
-bool IsTty(int fd);
+inline std::optional<uint64_t> StringViewToUInt64(const base::StringView& sv,
+ int base = 10) {
+ // std::from_chars() does not recognize the leading '-' character for
+ // unsigned conversions, but strtol does. To Mimic the behavior of strtol,
+ // attempt a signed converion if we see a leading '-', and then cast the
+ // result back to unsigned.
+ if (sv.size() > 0 && sv.at(0) == '-') {
+ return static_cast<std::optional<uint64_t> >(
+ StringViewToNumber<int64_t>(sv, base));
+ } else {
+ return StringViewToNumber<uint64_t>(sv, base);
+ }
+}
-// Convenience overload for C stdio streams (e.g. stdin/stdout/stderr).
-bool IsTty(FILE* stream);
+inline std::optional<int64_t> StringViewToInt64(const base::StringView& sv,
+ int base = 10) {
+ return StringViewToNumber<int64_t>(sv, base);
+}
-// Calls mallopt(M_PURGE, 0) on Android. Does nothing on other platforms.
-// This forces the allocator to release freed memory. This is used to work
-// around various Scudo inefficiencies. See b/170217718.
-void MaybeReleaseAllocatorMemToOS();
+// TODO: As of Clang 19.0 std::from_chars is unimplemented for type double
+// despite being part of C++17 standard, and already being supported by GCC and
+// MSVC. Enable this once we have double support in Clang.
+// inline std::optional<double> StringViewToDouble(const base::StringView& sv) {
+// return StringViewToNumber<double>(sv);
+// }
-// geteuid() on POSIX OSes, returns 0 on Windows (See comment in utils.cc).
-uid_t GetCurrentUserId();
+bool StartsWith(const std::string& str, const std::string& prefix);
+bool EndsWith(const std::string& str, const std::string& suffix);
+bool StartsWithAny(const std::string& str,
+ const std::vector<std::string>& prefixes);
+bool Contains(const std::string& haystack, const std::string& needle);
+bool Contains(const std::string& haystack, char needle);
+bool Contains(const std::vector<std::string>& haystack,
+ const std::string& needle);
+size_t Find(const StringView& needle, const StringView& haystack);
+bool CaseInsensitiveEqual(std::string_view first, std::string_view second);
+std::string Join(const std::vector<std::string>& parts,
+ const std::string& delim);
+std::vector<std::string> SplitString(const std::string& text,
+ const std::string& delimiter);
+std::string StripPrefix(const std::string& str, const std::string& prefix);
+std::string StripSuffix(const std::string& str, const std::string& suffix);
+std::string_view TrimWhitespace(std::string_view str);
+std::string TrimWhitespace(const std::string& str);
+std::string_view TrimWhitespace(const char* str);
+std::string ToLower(const std::string& str);
+std::string ToUpper(const std::string& str);
+std::string StripChars(const std::string& str,
+ const std::string& chars,
+ char replacement);
+std::string ToHex(const char* data, size_t size);
+inline std::string ToHex(const std::string& s) {
+ return ToHex(s.c_str(), s.size());
+}
+std::string IntToHexString(uint32_t number);
+std::string Uint64ToHexString(uint64_t number);
+std::string Uint64ToHexStringNoPrefix(uint64_t number);
+std::string ReplaceAll(std::string str,
+ const std::string& to_replace,
+ const std::string& replacement);
-// Forks the process.
-// Parent: calls |parent_cb| with the child's PID and exits with its return
-// value. The callback owns any startup output (e.g. printing the PID).
-// Child: redirects stdio onto /dev/null, chdirs into / and returns.
-void Daemonize(std::function<int(pid_t)> parent_cb);
+// Checks if all characters in the input string view `str` are ASCII.
+//
+// If so, the function returns true and `output` is not modified.
+// If `str` contains non-ASCII characters, the function returns false,
+// removes invalid UTF-8 characters from `str`, and stores the result in
+// `output`.
+bool CheckAsciiAndRemoveInvalidUTF8(base::StringView str, std::string& output);
-// Returns the path of the current executable, e.g. /foo/bar/exe.
-std::string GetCurExecutablePath();
+#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
+bool WideToUTF8(const std::wstring& source, std::string& output);
+bool UTF8ToWide(const std::string& source, std::wstring& output);
+#endif // PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
-// Returns the directory where the current executable lives in, e.g. /foo/bar.
-// This is independent of cwd().
-std::string GetCurExecutableDir();
+// A BSD-style strlcpy without the return value.
+// Copies at most |dst_size|-1 characters. Unlike strncpy, it always \0
+// terminates |dst|, as long as |dst_size| is not 0.
+// Unlike strncpy and like strlcpy it does not zero-pad the rest of |dst|.
+// Returns nothing. The BSD strlcpy returns the size of |src|, which might
+// be > |dst_size|. Anecdotal experience suggests people assume the return value
+// is the number of bytes written in |dst|. That assumption can lead to
+// dangerous bugs.
+// In order to avoid being subtly uncompliant with strlcpy AND avoid misuse,
+// the choice here is to return nothing.
+inline void StringCopy(char* dst, const char* src, size_t dst_size) {
+ for (size_t i = 0; i < dst_size; ++i) {
+ if ((dst[i] = src[i]) == '\0') {
+ return; // We hit and copied the null terminator.
+ }
+ }
-// Memory returned by AlignedAlloc() must be freed via AlignedFree() not just
-// free. It makes a difference on Windows where _aligned_malloc() and
-// _aligned_free() must be paired.
-// Prefer using the AlignedAllocTyped() below which takes care of the pairing.
-void* AlignedAlloc(size_t alignment, size_t size);
-void AlignedFree(void*);
+ // We were left off at dst_size. We over copied 1 byte. Null terminate.
+ if (PERFETTO_LIKELY(dst_size > 0))
+ dst[dst_size - 1] = 0;
+}
-// Detects Sync-mode MTE (currently being tested in some Android builds).
-// This is known to use extra memory for the stack history buffer.
-bool IsSyncMemoryTaggingEnabled();
+// Like snprintf() but returns the number of chars *actually* written (without
+// counting the null terminator) NOT "the number of chars which would have been
+// written to the final string if enough space had been available".
+// This should be used in almost all cases when the caller uses the return value
+// of snprintf(). If the return value is not used, there is no benefit in using
+// this wrapper, as this just calls snprintf() and mangles the return value.
+// It always null-terminates |dst| (even in case of errors), unless
+// |dst_size| == 0.
+// Examples:
+// SprintfTrunc(x, 4, "123whatever"): returns 3 and writes "123\0".
+// SprintfTrunc(x, 4, "123"): returns 3 and writes "123\0".
+// SprintfTrunc(x, 3, "123"): returns 2 and writes "12\0".
+// SprintfTrunc(x, 2, "123"): returns 1 and writes "1\0".
+// SprintfTrunc(x, 1, "123"): returns 0 and writes "\0".
+// SprintfTrunc(x, 0, "123"): returns 0 and writes nothing.
+// NOTE: This means that the caller has no way to tell when truncation happens
+// vs the edge case of *just* fitting in the buffer.
+size_t SprintfTrunc(char* dst, size_t dst_size, const char* fmt, ...)
+ PERFETTO_PRINTF_FORMAT(3, 4);
-// A RAII version of the above, which takes care of pairing Aligned{Alloc,Free}.
-template <typename T>
-struct AlignedDeleter {
- inline void operator()(T* ptr) const { AlignedFree(ptr); }
+// Line number starts from 1
+struct LineWithOffset {
+ base::StringView line;
+ uint32_t line_offset;
+ uint32_t line_num;
};
-// The remove_extent<T> here and below is to allow defining unique_ptr<T[]>.
-// As per https://en.cppreference.com/w/cpp/memory/unique_ptr the Deleter takes
-// always a T*, not a T[]*.
-template <typename T>
-using AlignedUniquePtr =
- std::unique_ptr<T, AlignedDeleter<typename std::remove_extent<T>::type>>;
-
-template <typename T>
-AlignedUniquePtr<T> AlignedAllocTyped(size_t n_membs) {
- using TU = typename std::remove_extent<T>::type;
- return AlignedUniquePtr<T>(
- static_cast<TU*>(AlignedAlloc(alignof(TU), sizeof(TU) * n_membs)));
-}
+// For given string and offset Pfinds a line with character for
+// which offset points, what number is this line (starts from 1), and the offset
+// inside this line. returns std::nullopt if the offset points to
+// line break character or exceeds string length.
+std::optional<LineWithOffset> FindLineWithOffset(base::StringView str,
+ uint32_t offset);
-// A RAII wrapper to invoke a function when leaving a function/scope.
-template <typename Func>
-class OnScopeExitWrapper {
+// A helper class to facilitate construction and usage of write-once stack
+// strings.
+// Example usage:
+// StackString<32> x("format %d %s", 42, string_arg);
+// TakeString(x.c_str() | x.string_view() | x.ToStdString());
+// Rather than char x[32] + sprintf.
+// Advantages:
+// - Avoids useless zero-fills caused by people doing `char buf[32] {}` (mainly
+// by fearing unknown snprintf failure modes).
+// - Makes the code more robust in case of snprintf truncations (len() and
+// string_view() will return the truncated length, unlike snprintf).
+template <size_t N>
+class StackString {
public:
- explicit OnScopeExitWrapper(Func f) : f_(std::move(f)), active_(true) {}
- OnScopeExitWrapper(OnScopeExitWrapper&& other) noexcept
- : f_(std::move(other.f_)), active_(other.active_) {
- other.active_ = false;
+ explicit PERFETTO_PRINTF_FORMAT(/* 1=this */ 2, 3)
+ StackString(const char* fmt, ...) {
+ buf_[0] = '\0';
+ va_list args;
+ va_start(args, fmt);
+ int res = vsnprintf(buf_, sizeof(buf_), fmt, args);
+ va_end(args);
+ buf_[sizeof(buf_) - 1] = '\0';
+ len_ = res < 0 ? 0 : std::min(static_cast<size_t>(res), sizeof(buf_) - 1);
}
- ~OnScopeExitWrapper() {
- if (active_)
- f_();
+
+ StringView string_view() const { return StringView(buf_, len_); }
+ std::string_view ToStdStringView() const {
+ return std::string_view(buf_, len_);
}
+ std::string ToStdString() const { return std::string(buf_, len_); }
+ const char* c_str() const { return buf_; }
+ size_t len() const { return len_; }
+ char* mutable_data() { return buf_; }
private:
- Func f_;
- bool active_;
+ char buf_[N];
+ size_t len_ = 0; // Does not include the \0.
};
-template <typename Func>
-PERFETTO_WARN_UNUSED_RESULT OnScopeExitWrapper<Func> OnScopeExit(Func f) {
- return OnScopeExitWrapper<Func>(std::move(f));
-}
-
-// Returns a xxd-style hex dump (hex + ascii chars) of the input data.
-std::string HexDump(const void* data, size_t len, size_t bytes_per_line = 16);
-inline std::string HexDump(const std::string& data,
- size_t bytes_per_line = 16) {
- return HexDump(data.data(), data.size(), bytes_per_line);
-}
-
} // namespace base
} // namespace perfetto
-#endif // INCLUDE_PERFETTO_EXT_BASE_UTILS_H_
+#endif // INCLUDE_PERFETTO_EXT_BASE_STRING_UTILS_H_
/*
* Copyright (C) 2021 The Android Open Source Project
*
@@ -1530,213 +1663,200 @@ inline std::string HexDump(const std::string& data,
* limitations under the License.
*/
-#ifndef INCLUDE_PERFETTO_EXT_BASE_BASE64_H_
-#define INCLUDE_PERFETTO_EXT_BASE_BASE64_H_
+// gen_amalgamated expanded: #include "perfetto/ext/base/android_utils.h"
+// gen_amalgamated expanded: #include "perfetto/ext/base/file_utils.h"
+// gen_amalgamated expanded: #include "perfetto/ext/base/string_splitter.h"
+
+// gen_amalgamated expanded: #include "perfetto/base/build_config.h"
-#include <optional>
#include <string>
-// gen_amalgamated expanded: #include "perfetto/ext/base/string_view.h"
-// gen_amalgamated expanded: #include "perfetto/ext/base/utils.h" // For ssize_t.
+#if PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID)
+#include <sys/system_properties.h>
+#endif
+
+// gen_amalgamated expanded: #include "perfetto/base/compiler.h"
+// gen_amalgamated expanded: #include "perfetto/base/logging.h"
+// gen_amalgamated expanded: #include "perfetto/base/time.h"
+// gen_amalgamated expanded: #include "perfetto/ext/base/string_utils.h"
+
+#if !PERFETTO_BUILDFLAG(PERFETTO_OS_WIN) && \
+ !PERFETTO_BUILDFLAG(PERFETTO_OS_NACL) && \
+ !PERFETTO_BUILDFLAG(PERFETTO_OS_WASM)
+#include <sys/utsname.h>
+#include <unistd.h>
+#endif
+
+#if PERFETTO_BUILDFLAG(PERFETTO_OS_LINUX_BUT_NOT_QNX) || \
+ PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID)
+#include <sys/sysinfo.h>
+#endif
namespace perfetto {
namespace base {
-// Returns the length of the destination string (included '=' padding).
-// Does NOT include the size of the string null terminator.
-inline size_t Base64EncSize(size_t src_size) {
- return (src_size + 2) / 3 * 4;
-}
+#if PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID)
-// Returns the upper bound on the length of the destination buffer.
-// The actual decoded length might be <= the number returned here.
-inline size_t Base64DecSize(size_t src_size) {
- return (src_size + 3) / 4 * 3;
+std::string GetAndroidProp(const char* name) {
+ std::string ret;
+#if __ANDROID_API__ >= 26
+ const prop_info* pi = __system_property_find(name);
+ if (!pi) {
+ return ret;
+ }
+ __system_property_read_callback(
+ pi,
+ [](void* dst_void, const char*, const char* value, uint32_t) {
+ std::string& dst = *static_cast<std::string*>(dst_void);
+ dst = value;
+ },
+ &ret);
+#else // __ANDROID_API__ < 26
+ char value_buf[PROP_VALUE_MAX];
+ int len = __system_property_get(name, value_buf);
+ if (len > 0 && static_cast<size_t>(len) < sizeof(value_buf)) {
+ ret = std::string(value_buf, static_cast<size_t>(len));
+ }
+#endif
+ return ret;
}
-// Does NOT null-terminate |dst|.
-ssize_t Base64Encode(const void* src,
- size_t src_size,
- char* dst,
- size_t dst_size);
-
-std::string Base64Encode(const void* src, size_t src_size);
+#endif // PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID)
-inline std::string Base64Encode(StringView sv) {
- return Base64Encode(sv.data(), sv.size());
+Utsname GetUtsname() {
+ Utsname utsname_info;
+#if !PERFETTO_BUILDFLAG(PERFETTO_OS_WIN) && \
+ !PERFETTO_BUILDFLAG(PERFETTO_OS_NACL) && \
+ !PERFETTO_BUILDFLAG(PERFETTO_OS_WASM)
+ struct utsname uname_info;
+ if (uname(&uname_info) == 0) {
+ utsname_info.sysname = uname_info.sysname;
+ utsname_info.version = uname_info.version;
+ utsname_info.machine = uname_info.machine;
+ utsname_info.release = uname_info.release;
+ } else {
+ PERFETTO_ELOG("Unable to read Utsname information");
+ }
+#endif // !PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
+ return utsname_info;
}
-// Returns -1 in case of failure.
-ssize_t Base64Decode(const char* src,
- size_t src_size,
- uint8_t* dst,
- size_t dst_size);
+SystemInfo GetSystemInfo() {
+ SystemInfo info;
-std::optional<std::string> Base64Decode(const char* src, size_t src_size);
-
-inline std::optional<std::string> Base64Decode(StringView sv) {
- return Base64Decode(sv.data(), sv.size());
-}
-
-} // namespace base
-} // namespace perfetto
-
-#endif // INCLUDE_PERFETTO_EXT_BASE_BASE64_H_
-/*
- * Copyright (C) 2021 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.
- */
-
-// gen_amalgamated expanded: #include "perfetto/ext/base/base64.h"
-
-namespace perfetto {
-namespace base {
-
-namespace {
+ info.timezone_off_mins = GetTimezoneOffsetMins();
-constexpr char kPadding = '=';
+#if !PERFETTO_BUILDFLAG(PERFETTO_OS_WIN) && \
+ !PERFETTO_BUILDFLAG(PERFETTO_OS_NACL) && \
+ !PERFETTO_BUILDFLAG(PERFETTO_OS_WASM)
-constexpr char kEncTable[] =
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
-static_assert(sizeof(kEncTable) == (1u << 6) + sizeof('\0'), "Bad table size");
+ info.utsname_info = GetUtsname();
+ info.page_size = static_cast<uint32_t>(sysconf(_SC_PAGESIZE));
+ info.num_cpus = static_cast<uint32_t>(sysconf(_SC_NPROCESSORS_CONF));
-// Maps an ASCII character to its 6-bit value. It only contains translations
-// from '+' to 'z'. Supports the standard (+/) and URL-safe (-_) alphabets.
-constexpr uint8_t kX = 0xff; // Value used for invalid characters
-constexpr uint8_t kDecTable[] = {
- 62, kX, 62, kX, 63, 52, 53, 54, 55, 56, // 00 - 09
- 57, 58, 59, 60, 61, kX, kX, kX, 0, kX, // 10 - 19
- kX, kX, 0, 1, 2, 3, 4, 5, 6, 7, // 20 - 29
- 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, // 30 - 39
- 18, 19, 20, 21, 22, 23, 24, 25, kX, kX, // 40 - 49
- kX, kX, 63, kX, 26, 27, 28, 29, 30, 31, // 50 - 59
- 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, // 60 - 69
- 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, // 70 - 79
-};
-constexpr char kMinDecChar = '+';
-constexpr char kMaxDecChar = 'z';
-static_assert(kMaxDecChar - kMinDecChar <= sizeof(kDecTable), "Bad table size");
+#if PERFETTO_BUILDFLAG(PERFETTO_OS_LINUX_BUT_NOT_QNX) || \
+ PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID)
+ // Use the Linux-specific sysinfo() system call on Linux and Android.
+ // https://man7.org/linux/man-pages/man2/sysinfo.2.html
+ struct sysinfo sys_info;
+ if (sysinfo(&sys_info) == 0) {
+ info.system_ram_bytes =
+ static_cast<uint64_t>(sys_info.totalram) * sys_info.mem_unit;
+ }
+#else
+ // POSIX Fallback (macOS, BSD, etc.): Use sysconf() to get physical pages.
+ long pages = sysconf(_SC_PHYS_PAGES);
+ if (pages > 0 && info.page_size.has_value()) {
+ info.system_ram_bytes = static_cast<uint64_t>(pages) * (*info.page_size);
+ }
+#endif
-inline uint8_t DecodeChar(char c) {
- if (c < kMinDecChar || c > kMaxDecChar)
- return kX;
- return kDecTable[c - kMinDecChar];
-}
+#if PERFETTO_BUILDFLAG(PERFETTO_OS_LINUX_BUT_NOT_QNX)
+ // Extract the device compatible strings from the device tree (if available)
+ const std::string path = "/sys/firmware/devicetree/base/compatible";
+ std::string device_compatible_data;
+ if (ReadFile(path, &device_compatible_data)) {
+ for (base::StringSplitter ss(std::move(device_compatible_data), '\0');
+ ss.Next();) {
+ info.device_tree_compatibles.emplace_back(ss.cur_token(),
+ ss.cur_token_size());
+ PERFETTO_DLOG("Found linux device compatible: %s", ss.cur_token());
+ }
+ } else {
+ PERFETTO_DLOG("No linux device compatible found in path: %s", path.c_str());
+ }
+#endif
+#endif // !PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
-} // namespace
+#if PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID)
+ info.android_build_fingerprint = GetAndroidProp("ro.build.fingerprint");
+ if (info.android_build_fingerprint.empty()) {
+ PERFETTO_ELOG("Unable to read ro.build.fingerprint");
+ }
-ssize_t Base64Encode(const void* src,
- size_t src_size,
- char* dst,
- size_t dst_size) {
- const size_t padded_dst_size = Base64EncSize(src_size);
- if (dst_size < padded_dst_size)
- return -1; // Not enough space in output.
+ info.android_device_manufacturer = GetAndroidProp("ro.product.manufacturer");
+ if (info.android_device_manufacturer.empty()) {
+ PERFETTO_ELOG("Unable to read ro.product.manufacturer");
+ }
- const uint8_t* rd = static_cast<const uint8_t*>(src);
- const uint8_t* const end = rd + src_size;
- size_t wr_size = 0;
- while (rd < end) {
- uint8_t s[3]{};
- s[0] = *(rd++);
- dst[wr_size++] = kEncTable[s[0] >> 2];
+ std::string sdk_str_value = GetAndroidProp("ro.build.version.sdk");
+ info.android_sdk_version = StringToUInt64(sdk_str_value);
+ if (!info.android_sdk_version.has_value()) {
+ PERFETTO_ELOG("Unable to read ro.build.version.sdk");
+ }
- uint8_t carry0 = static_cast<uint8_t>((s[0] & 0x03) << 4);
- if (PERFETTO_LIKELY(rd < end)) {
- s[1] = *(rd++);
- dst[wr_size++] = kEncTable[carry0 | (s[1] >> 4)];
- } else {
- dst[wr_size++] = kEncTable[carry0];
- dst[wr_size++] = kPadding;
- dst[wr_size++] = kPadding;
- break;
- }
+ info.android_soc_model = GetAndroidProp("ro.soc.model");
+ if (info.android_soc_model.empty()) {
+ PERFETTO_ELOG("Unable to read ro.soc.model");
+ }
- uint8_t carry1 = static_cast<uint8_t>((s[1] & 0x0f) << 2);
- if (PERFETTO_LIKELY(rd < end)) {
- s[2] = *(rd++);
- dst[wr_size++] = kEncTable[carry1 | (s[2] >> 6)];
- } else {
- dst[wr_size++] = kEncTable[carry1];
- dst[wr_size++] = kPadding;
- break;
- }
+ // guest_soc model is not always present
+ info.android_guest_soc_model = GetAndroidProp("ro.boot.guest_soc.model");
- dst[wr_size++] = kEncTable[s[2] & 0x3f];
+ info.android_hardware_revision = GetAndroidProp("ro.boot.hardware.revision");
+ if (info.android_hardware_revision.empty()) {
+ PERFETTO_ELOG("Unable to read ro.boot.hardware.revision");
}
- PERFETTO_DCHECK(wr_size == padded_dst_size);
- return static_cast<ssize_t>(padded_dst_size);
-}
-
-std::string Base64Encode(const void* src, size_t src_size) {
- std::string dst;
- dst.resize(Base64EncSize(src_size));
- auto res = Base64Encode(src, src_size, &dst[0], dst.size());
- PERFETTO_CHECK(res == static_cast<ssize_t>(dst.size()));
- return dst;
-}
-ssize_t Base64Decode(const char* src,
- size_t src_size,
- uint8_t* dst,
- size_t dst_size) {
- const size_t min_dst_size = Base64DecSize(src_size);
- if (dst_size < min_dst_size)
- return -1;
+ info.android_storage_model = GetAndroidProp("ro.boot.hardware.ufs");
+ if (info.android_storage_model.empty()) {
+ PERFETTO_ELOG("Unable to read ro.boot.hardware.ufs");
+ }
- const char* rd = src;
- const char* const end = src + src_size;
- size_t wr_size = 0;
+ info.android_ram_model = GetAndroidProp("ro.boot.hardware.ddr");
+ if (info.android_ram_model.empty()) {
+ PERFETTO_ELOG("Unable to read ro.boot.hardware.ddr");
+ }
- char s[4]{};
- while (rd < end) {
- uint8_t d[4];
- for (uint32_t j = 0; j < 4; j++) {
- // Padding is only feasible for the last 2 chars of each group of 4.
- s[j] = rd < end ? *(rd++) : (j < 2 ? '\0' : kPadding);
- d[j] = DecodeChar(s[j]);
- if (d[j] == kX)
- return -1; // Invalid input char.
- }
- dst[wr_size] = static_cast<uint8_t>((d[0] << 2) | (d[1] >> 4));
- dst[wr_size + 1] = static_cast<uint8_t>((d[1] << 4) | (d[2] >> 2));
- dst[wr_size + 2] = static_cast<uint8_t>((d[2] << 6) | (d[3]));
- wr_size += 3;
+ info.android_serial_console = GetAndroidProp("init.svc.console");
+ if (info.android_serial_console.empty()) {
+ PERFETTO_ELOG("Unable to read init.svc.console");
}
+#endif // PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID)
- PERFETTO_CHECK(wr_size <= dst_size);
- wr_size -= (s[3] == kPadding ? 1 : 0) + (s[2] == kPadding ? 1 : 0);
- return static_cast<ssize_t>(wr_size);
+ return info;
}
-std::optional<std::string> Base64Decode(const char* src, size_t src_size) {
- std::string dst;
- dst.resize(Base64DecSize(src_size));
- auto res = Base64Decode(src, src_size, reinterpret_cast<uint8_t*>(&dst[0]),
- dst.size());
- if (res < 0)
- return std::nullopt; // Decoding error.
-
- PERFETTO_CHECK(res <= static_cast<ssize_t>(dst.size()));
- dst.resize(static_cast<size_t>(res));
- return std::make_optional(dst);
+std::string GetPerfettoMachineName() {
+ const char* env_name = getenv("PERFETTO_MACHINE_NAME");
+ if (env_name) {
+ return env_name;
+ }
+#if PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID)
+ std::string name = base::GetAndroidProp("traced.machine_name");
+ if (name.empty()) {
+ name = GetUtsname().sysname;
+ }
+ return name;
+#else
+ return GetUtsname().sysname;
+#endif
}
} // namespace base
} // namespace perfetto
-// gen_amalgamated begin source: src/base/cpu_info.cc
-// gen_amalgamated begin header: include/perfetto/ext/base/cpu_info.h
+// gen_amalgamated begin source: src/base/atomic_file.cc
+// gen_amalgamated begin header: include/perfetto/ext/base/atomic_file.h
/*
* Copyright (C) 2026 The Android Open Source Project
*
@@ -1753,42 +1873,45 @@ std::optional<std::string> Base64Decode(const char* src, size_t src_size) {
* limitations under the License.
*/
-#ifndef INCLUDE_PERFETTO_EXT_BASE_CPU_INFO_H_
-#define INCLUDE_PERFETTO_EXT_BASE_CPU_INFO_H_
+#ifndef INCLUDE_PERFETTO_EXT_BASE_ATOMIC_FILE_H_
+#define INCLUDE_PERFETTO_EXT_BASE_ATOMIC_FILE_H_
-#include <stdint.h>
-#include <optional>
#include <string>
-#include <vector>
-
-namespace perfetto {
-namespace base {
-
-struct CpuInfo {
- std::string processor;
- uint32_t cpu_index = 0;
- std::optional<uint32_t> implementer;
- std::optional<uint32_t> architecture;
- std::optional<uint32_t> variant;
- std::optional<uint32_t> part;
- std::optional<uint32_t> revision;
- uint64_t features = 0;
- char arm_cpuid[32] = {};
-};
+// gen_amalgamated expanded: #include "perfetto/base/status.h"
+// gen_amalgamated expanded: #include "perfetto/ext/base/scoped_file.h"
-// Parses the contents of the input string into per-CPU entries.
-std::vector<CpuInfo> ParseCpuInfo(std::string proc_cpu_info);
+namespace perfetto::base {
-// Reads /proc/cpuinfo and parses it into per-CPU entries.
-std::vector<CpuInfo> ReadCpuInfo();
+// Writes a sibling temporary file and atomically replaces the destination on
+// Commit(). Until then an existing destination is untouched. Does not follow
+// destination symlinks. An uncommitted temporary file is deleted on
+// destruction.
+class AtomicFile {
+ public:
+ explicit AtomicFile(const std::string& destination);
+ ~AtomicFile();
+ AtomicFile(const AtomicFile&) = delete;
+ AtomicFile& operator=(const AtomicFile&) = delete;
+
+ Status Open();
+ ScopedFile DuplicateFD() const;
+ // Final operation: close all DuplicateFD() handles before committing.
+ // On failure, destruction still attempts to remove the temporary file.
+ Status Commit() &&;
+ const std::string& temp_path() const { return temp_path_; }
-} // namespace base
-} // namespace perfetto
+ private:
+ const std::string destination_;
+ const std::string temp_path_;
+ ScopedFile fd_;
+ bool owns_temp_file_ = false;
+};
-#endif // INCLUDE_PERFETTO_EXT_BASE_CPU_INFO_H_
-// gen_amalgamated begin header: include/perfetto/ext/base/cpu_info_features_allowlist.h
+} // namespace perfetto::base
+#endif // INCLUDE_PERFETTO_EXT_BASE_ATOMIC_FILE_H_
+// gen_amalgamated begin header: include/perfetto/ext/base/uuid.h
/*
- * Copyright (C) 2025 The Android Open Source Project
+ * 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.
@@ -1803,29 +1926,75 @@ std::vector<CpuInfo> ReadCpuInfo();
* limitations under the License.
*/
-#ifndef INCLUDE_PERFETTO_EXT_BASE_CPU_INFO_FEATURES_ALLOWLIST_H_
-#define INCLUDE_PERFETTO_EXT_BASE_CPU_INFO_FEATURES_ALLOWLIST_H_
+#ifndef INCLUDE_PERFETTO_EXT_BASE_UUID_H_
+#define INCLUDE_PERFETTO_EXT_BASE_UUID_H_
+
+#include <string.h>
+#include <array>
+#include <cstdint>
+#include <string>
+
+// gen_amalgamated expanded: #include "perfetto/base/endian.h"
+// gen_amalgamated expanded: #include "perfetto/base/export.h"
namespace perfetto {
namespace base {
-// APPEND ONLY. DO NOT EVER REMOVE ENTRIES FROM THIS ARRAY OR REORDER.
-// This array is used both by traced_probes and trace_processor to index the
-// cpuinfo flags. Changing the order will break trace_processor compatibility
-// with old traces.
-constexpr const char* kCpuInfoFeatures[] = {
- "mte", // DO NOT REMOVE/REODER.
- "mte3", // DO NOT REMOVE/REODER.
+class PERFETTO_EXPORT_COMPONENT Uuid {
+ public:
+ explicit Uuid(const std::string& s);
+ explicit Uuid(int64_t lsb, int64_t msb);
+ Uuid();
+
+ std::array<uint8_t, 16>* data() { return &data_; }
+ const std::array<uint8_t, 16>* data() const { return &data_; }
+
+ bool operator==(const Uuid& other) const { return data_ == other.data_; }
+
+ bool operator!=(const Uuid& other) const { return !(*this == other); }
+
+ explicit operator bool() const { return *this != Uuid(); }
+
+ int64_t msb() const {
+ uint64_t result;
+ memcpy(&result, data_.data() + 8, 8);
+ return static_cast<int64_t>(LE64ToHost(result));
+ }
+
+ int64_t lsb() const {
+ uint64_t result;
+ memcpy(&result, data_.data(), 8);
+ return static_cast<int64_t>(LE64ToHost(result));
+ }
+
+ void set_lsb_msb(int64_t lsb, int64_t msb) {
+ set_lsb(lsb);
+ set_msb(msb);
+ }
+ void set_msb(int64_t msb) {
+ uint64_t le = HostToLE64(static_cast<uint64_t>(msb));
+ memcpy(data_.data() + 8, &le, 8);
+ }
+ void set_lsb(int64_t lsb) {
+ uint64_t le = HostToLE64(static_cast<uint64_t>(lsb));
+ memcpy(data_.data(), &le, 8);
+ }
+
+ std::string ToString() const;
+ std::string ToPrettyString() const;
+
+ private:
+ std::array<uint8_t, 16> data_{};
};
+Uuid Uuidv4();
+
} // namespace base
} // namespace perfetto
-#endif // INCLUDE_PERFETTO_EXT_BASE_CPU_INFO_FEATURES_ALLOWLIST_H_
-// gen_amalgamated begin header: include/perfetto/ext/base/file_utils.h
-// gen_amalgamated begin header: include/perfetto/base/status.h
+#endif // INCLUDE_PERFETTO_EXT_BASE_UUID_H_
/*
- * Copyright (C) 2019 The Android Open Source Project
+ * Copyright (C) 2026 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.
@@ -1840,108 +2009,108 @@ constexpr const char* kCpuInfoFeatures[] = {
* limitations under the License.
*/
-#ifndef INCLUDE_PERFETTO_BASE_STATUS_H_
-#define INCLUDE_PERFETTO_BASE_STATUS_H_
+// gen_amalgamated expanded: #include "perfetto/ext/base/atomic_file.h"
-#include <optional>
-#include <string>
-#include <string_view>
-#include <vector>
+#include <cerrno>
+#include <cstdio>
+#include <cstring>
+// gen_amalgamated expanded: #include "perfetto/base/build_config.h"
// gen_amalgamated expanded: #include "perfetto/base/compiler.h"
-// gen_amalgamated expanded: #include "perfetto/base/export.h"
// gen_amalgamated expanded: #include "perfetto/base/logging.h"
+// gen_amalgamated expanded: #include "perfetto/ext/base/file_utils.h"
+// gen_amalgamated expanded: #include "perfetto/ext/base/uuid.h"
-namespace perfetto {
-namespace base {
-
-// Represents either the success or the failure message of a function.
-// This can used as the return type of functions which would usually return an
-// bool for success or int for errno but also wants to add some string context
-// (ususally for logging).
-//
-// Similar to absl::Status, an optional "payload" can also be included with more
-// context about the error. This allows passing additional metadata about the
-// error (e.g. location of errors, potential mitigations etc).
-class PERFETTO_EXPORT_COMPONENT Status {
- public:
- Status() : ok_(true) {}
- explicit Status(std::string msg) : ok_(false), message_(std::move(msg)) {
- PERFETTO_CHECK(!message_.empty());
- }
-
- // Copy operations.
- Status(const Status&) = default;
- Status& operator=(const Status&) = default;
-
- // Move operations. The moved-from state is valid but unspecified.
- Status(Status&&) noexcept = default;
- Status& operator=(Status&&) = default;
-
- bool ok() const { return ok_; }
-
- // When ok() is false this returns the error message. Returns the empty string
- // otherwise.
- const std::string& message() const { return message_; }
- const char* c_message() const { return message_.c_str(); }
-
- //////////////////////////////////////////////////////////////////////////////
- // Payload Management APIs
- //////////////////////////////////////////////////////////////////////////////
-
- // Payloads can be attached to error statuses to provide additional context.
- //
- // Payloads are (key, value) pairs, where the key is a string acting as a
- // unique "type URL" and the value is an opaque string. The "type URL" should
- // be unique, follow the format of a URL and, ideally, documentation on how to
- // interpret its associated data should be available.
- //
- // To attach a payload to a status object, call `Status::SetPayload()`.
- // Similarly, to extract the payload from a status, call
- // `Status::GetPayload()`.
- //
- // Note: the payload APIs are only meaningful to call when the status is an
- // error. Otherwise, all methods are noops.
-
- // Gets the payload for the given |type_url| if one exists.
- //
- // Will always return std::nullopt if |ok()|.
- std::optional<std::string_view> GetPayload(std::string_view type_url) const;
-
- // Sets the payload for the given key. The key should
- //
- // Will always do nothing if |ok()|.
- void SetPayload(std::string_view type_url, std::string value);
-
- // Erases the payload for the given string and returns true if the payload
- // existed and was erased.
- //
- // Will always do nothing if |ok()|.
- bool ErasePayload(std::string_view type_url);
+#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
+#include <io.h>
+#include <windows.h>
+#else
+#include <sys/stat.h>
+#include <unistd.h>
+#endif
- private:
- struct Payload {
- std::string type_url;
- std::string payload;
- };
+namespace perfetto::base {
- bool ok_ = false;
- std::string message_;
- std::vector<Payload> payloads_;
-};
+AtomicFile::AtomicFile(const std::string& destination)
+ : destination_(destination),
+ temp_path_(destination + ".tmp." + Uuidv4().ToPrettyString()) {}
-// Returns a status object which represents the Ok status.
-inline Status OkStatus() {
- return Status();
+AtomicFile::~AtomicFile() {
+ fd_.reset();
+ if (owns_temp_file_)
+ Unlink(temp_path_.c_str());
}
-Status ErrStatus(const char* format, ...) PERFETTO_PRINTF_FORMAT(1, 2);
+base::Status AtomicFile::Open() {
+ PERFETTO_CHECK(!fd_ && !owns_temp_file_);
+#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
+ DWORD attributes = GetFileAttributesA(destination_.c_str());
+ if (attributes != INVALID_FILE_ATTRIBUTES &&
+ (attributes & (FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_REPARSE_POINT)))
+ return base::ErrStatus(
+ "output must be a regular file, not a directory or link");
+ HANDLE handle =
+ CreateFileA(temp_path_.c_str(), GENERIC_READ | GENERIC_WRITE,
+ FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
+ nullptr, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, nullptr);
+ if (handle == INVALID_HANDLE_VALUE)
+ return base::ErrStatus(
+ "cannot create temporary output beside '%s' (Windows error %lu)",
+ destination_.c_str(), GetLastError());
+ owns_temp_file_ = true;
+ fd_.reset(_open_osfhandle(reinterpret_cast<intptr_t>(handle), _O_BINARY));
+ if (!fd_)
+ CloseHandle(handle);
+#else
+ struct stat output{};
+ bool exists = lstat(destination_.c_str(), &output) == 0;
+ PERFETTO_MSAN_UNPOISON(&output, sizeof(output));
+ if (exists && !S_ISREG(output.st_mode))
+ return base::ErrStatus(
+ "output must be a regular file, not a directory or link: '%s'. Specify "
+ "the target path directly.",
+ destination_.c_str());
+ fd_ = base::OpenFile(temp_path_, O_CREAT | O_EXCL | O_RDWR, 0644);
+ owns_temp_file_ = static_cast<bool>(fd_);
+ if (fd_ && exists && fchmod(*fd_, output.st_mode & 0777) != 0)
+ return base::ErrStatus("cannot preserve output permissions: %s",
+ strerror(errno));
+#endif
+ if (!fd_)
+ return base::ErrStatus(
+ "cannot create temporary output beside '%s': %s. Check that the parent "
+ "directory exists and is writable.",
+ destination_.c_str(), strerror(errno));
+ return base::OkStatus();
+}
-} // namespace base
-} // namespace perfetto
+base::ScopedFile AtomicFile::DuplicateFD() const {
+ PERFETTO_CHECK(fd_);
+ return DupFile(*fd_);
+}
-#endif // INCLUDE_PERFETTO_BASE_STATUS_H_
-// gen_amalgamated begin header: include/perfetto/ext/base/scoped_file.h
+base::Status AtomicFile::Commit() && {
+ PERFETTO_CHECK(fd_);
+ if (!base::FlushFile(*fd_))
+ return base::ErrStatus("failed to flush output: %s", strerror(errno));
+ fd_.reset();
+#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
+ if (!MoveFileExA(temp_path_.c_str(), destination_.c_str(),
+ MOVEFILE_REPLACE_EXISTING))
+ return base::ErrStatus("failed to publish '%s' (Windows error %lu)",
+ destination_.c_str(), GetLastError());
+#else
+ if (rename(temp_path_.c_str(), destination_.c_str()) != 0)
+ return base::ErrStatus("failed to publish '%s': %s", destination_.c_str(),
+ strerror(errno));
+#endif
+ owns_temp_file_ = false;
+ return base::OkStatus();
+}
+} // namespace perfetto::base
+// gen_amalgamated begin source: src/base/base64.cc
+// gen_amalgamated begin header: include/perfetto/ext/base/base64.h
+// gen_amalgamated begin header: include/perfetto/ext/base/utils.h
/*
* Copyright (C) 2017 The Android Open Source Project
*
@@ -1958,358 +2127,346 @@ Status ErrStatus(const char* format, ...) PERFETTO_PRINTF_FORMAT(1, 2);
* limitations under the License.
*/
-#ifndef INCLUDE_PERFETTO_EXT_BASE_SCOPED_FILE_H_
-#define INCLUDE_PERFETTO_EXT_BASE_SCOPED_FILE_H_
-
-// gen_amalgamated expanded: #include "perfetto/base/build_config.h"
+#ifndef INCLUDE_PERFETTO_EXT_BASE_UTILS_H_
+#define INCLUDE_PERFETTO_EXT_BASE_UTILS_H_
+#include <errno.h>
+#include <stddef.h>
+#include <stdint.h>
#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
-#if !PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
-#include <dirent.h> // For DIR* / opendir().
-#endif
-
+#include <atomic>
+#include <functional>
+#include <limits>
+#include <memory>
#include <string>
-// gen_amalgamated expanded: #include "perfetto/base/export.h"
-// gen_amalgamated expanded: #include "perfetto/base/logging.h"
-// gen_amalgamated expanded: #include "perfetto/base/platform_handle.h"
+// gen_amalgamated expanded: #include "perfetto/base/build_config.h"
+// gen_amalgamated expanded: #include "perfetto/base/compiler.h"
+// gen_amalgamated expanded: #include "perfetto/ext/base/sys_types.h"
+
+#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
+// Even if Windows has errno.h, the all syscall-restart behavior does not apply.
+// Trying to handle EINTR can cause more harm than good if errno is left stale.
+// Chromium does the same.
+#define PERFETTO_EINTR(x) (x)
+#else
+#define PERFETTO_EINTR(x) \
+ ([&] { \
+ decltype(x) eintr_wrapper_result; \
+ do { \
+ eintr_wrapper_result = (x); \
+ } while (eintr_wrapper_result == -1 && errno == EINTR); \
+ return eintr_wrapper_result; \
+ }())
+#endif
namespace perfetto {
namespace base {
namespace internal {
-// Used for the most common cases of ScopedResource where there is only one
-// invalid value.
-template <typename T, T InvalidValue>
-struct DefaultValidityChecker {
- static bool IsValid(T t) { return t != InvalidValue; }
-};
+extern std::atomic<uint32_t> g_cached_page_size;
+uint32_t GetSysPageSizeSlowpath();
} // namespace internal
-// RAII classes for auto-releasing fds and dirs.
-// if T is a pointer type, InvalidValue must be nullptr. Doing otherwise
-// causes weird unexpected behaviors (See https://godbolt.org/z/5nGMW4).
-template <typename T,
- int (*CloseFunction)(T),
- T InvalidValue,
- bool CheckClose = true,
- class Checker = internal::DefaultValidityChecker<T, InvalidValue>>
-class ScopedResource {
- public:
- using ValidityChecker = Checker;
- static constexpr T kInvalid = InvalidValue;
-
- explicit ScopedResource(T t = InvalidValue) : t_(t) {}
- ScopedResource(ScopedResource&& other) noexcept : t_(other.t_) {
- other.t_ = InvalidValue;
- }
- ScopedResource& operator=(ScopedResource&& other) {
- reset(other.t_);
- other.t_ = InvalidValue;
- return *this;
- }
- T get() const { return t_; }
- T operator*() const { return t_; }
- explicit operator bool() const { return Checker::IsValid(t_); }
- void reset(T r = InvalidValue) {
- if (Checker::IsValid(t_)) {
- int res = CloseFunction(t_);
- if (CheckClose)
- PERFETTO_CHECK(res == 0);
- }
- t_ = r;
- }
- T release() {
- T t = t_;
- t_ = InvalidValue;
- return t;
- }
- ~ScopedResource() { reset(InvalidValue); }
-
- private:
- ScopedResource(const ScopedResource&) = delete;
- ScopedResource& operator=(const ScopedResource&) = delete;
- T t_;
-};
-
-// Declared in file_utils.h. Forward declared to avoid #include cycles.
-int PERFETTO_EXPORT_COMPONENT CloseFile(int fd);
+// Returns the system's page size. Use this when dealing with mmap, madvise and
+// similar mm-related syscalls.
+// This function might be called in hot paths. Avoid calling getpagesize() all
+// the times, in many implementations getpagesize() calls sysconf() which is
+// not cheap.
+inline uint32_t GetSysPageSize() {
+ const uint32_t page_size =
+ internal::g_cached_page_size.load(std::memory_order_relaxed);
+ return page_size != 0 ? page_size : internal::GetSysPageSizeSlowpath();
+}
-// Use this for file resources obtained via open() and similar APIs.
-using ScopedFile = ScopedResource<int, CloseFile, -1>;
-using ScopedFstream = ScopedResource<FILE*, fclose, nullptr>;
+template <typename T, size_t TSize>
+constexpr size_t ArraySize(const T (&)[TSize]) {
+ return TSize;
+}
-// Use this for resources that are HANDLE on Windows. See comments in
-// platform_handle.h
-#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
-using ScopedPlatformHandle = ScopedResource<PlatformHandle,
- ClosePlatformHandle,
- /*InvalidValue=*/nullptr,
- /*CheckClose=*/true,
- PlatformHandleChecker>;
+// Adds `a` and `b` into `*result`, returning false on overflow. The value of
+// `*result` is unspecified when false is returned.
+inline bool CheckedAdd(int64_t a, int64_t b, int64_t* result) {
+#if defined(__clang__) || defined(__GNUC__)
+ return !__builtin_add_overflow(a, b, result);
#else
-// On non-windows systems we alias ScopedPlatformHandle to ScopedFile because
-// they are really the same. This is to allow assignments between the two in
-// Linux-specific code paths that predate ScopedPlatformHandle.
-static_assert(std::is_same<int, PlatformHandle>::value, "");
-using ScopedPlatformHandle = ScopedFile;
-
-// DIR* does not exist on Windows.
-using ScopedDir = ScopedResource<DIR*, closedir, nullptr>;
+ constexpr int64_t kMax = std::numeric_limits<int64_t>::max();
+ constexpr int64_t kMin = std::numeric_limits<int64_t>::min();
+ if ((b > 0 && a > kMax - b) || (b < 0 && a < kMin - b))
+ return false;
+ *result = a + b;
+ return true;
#endif
+}
-} // namespace base
-} // namespace perfetto
-
-#endif // INCLUDE_PERFETTO_EXT_BASE_SCOPED_FILE_H_
-/*
- * 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.
- */
-
-#ifndef INCLUDE_PERFETTO_EXT_BASE_FILE_UTILS_H_
-#define INCLUDE_PERFETTO_EXT_BASE_FILE_UTILS_H_
-
-#include <fcntl.h> // For mode_t & O_RDONLY/RDWR. Exists also on Windows.
-#include <stddef.h>
-#include <stdint.h>
-
-#include <functional>
-#include <memory>
-#include <optional>
-#include <string>
-#include <vector>
-
-// gen_amalgamated expanded: #include "perfetto/base/build_config.h"
-// gen_amalgamated expanded: #include "perfetto/base/export.h"
-// gen_amalgamated expanded: #include "perfetto/base/status.h"
-// gen_amalgamated expanded: #include "perfetto/ext/base/scoped_file.h"
-// gen_amalgamated expanded: #include "perfetto/ext/base/sys_types.h"
-
-namespace perfetto {
-namespace base {
-
-class TaskRunner;
-
-#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
-using FileOpenMode = int;
-inline constexpr char kDevNull[] = "NUL";
-inline constexpr char kFopenReadFlag[] = "r";
+// Subtracts `b` from `a` into `*result`, returning false on overflow. The
+// value of `*result` is unspecified when false is returned.
+inline bool CheckedSub(int64_t a, int64_t b, int64_t* result) {
+#if defined(__clang__) || defined(__GNUC__)
+ return !__builtin_sub_overflow(a, b, result);
#else
-using FileOpenMode = mode_t;
-inline constexpr char kDevNull[] = "/dev/null";
-inline constexpr char kFopenReadFlag[] = "re";
+ constexpr int64_t kMax = std::numeric_limits<int64_t>::max();
+ constexpr int64_t kMin = std::numeric_limits<int64_t>::min();
+ if ((b < 0 && a > kMax + b) || (b > 0 && a < kMin + b))
+ return false;
+ *result = a - b;
+ return true;
#endif
+}
-constexpr FileOpenMode kFileModeInvalid = static_cast<FileOpenMode>(-1);
-
-// Cross-platform variant of ReadFileDescriptor() that takes a PlatformHandle.
-// On Windows normalizes ERROR_BROKEN_PIPE to EOF so behavior matches POSIX.
-bool ReadPlatformHandle(PlatformHandle, std::string* out);
-
-// Reads from |fd|, appending what is currently available into |*out|.
-// Returns:
-// True: EOF reached (all writers of |fd| have closed their end).
-// False: read error. On a non-blocking |fd| this includes EAGAIN (no data
-// currently available but writers are still alive); callers can check
-// IsAgain(errno) and retry on the next readability notification.
-bool ReadFileDescriptor(int fd, std::string* out);
+// Returns whether `value` is positive or negative zero. Compares the bit
+// pattern so it can be used in translation units compiled with -Wfloat-equal.
+inline bool IsZero(double value) {
+ uint64_t bits;
+ memcpy(&bits, &value, sizeof(bits));
+ return (bits << 1) == 0;
+}
+inline bool IsZero(int64_t value) {
+ return value == 0;
+}
-// Convenience wrapper around ReadFileDescriptor() that takes a FILE*.
-bool ReadFileStream(FILE* f, std::string* out);
+// Returns the bits of `value` with -0.0 turned into 0.0 and every NaN into
+// the same NaN, so equal values, and all NaNs, have the same bits.
+inline uint64_t CanonicalFloatBits(double value) {
+ uint64_t bits;
+ memcpy(&bits, &value, sizeof(bits));
+ if (PERFETTO_UNLIKELY((bits << 1) == 0)) {
+ return 0;
+ }
+ if (PERFETTO_UNLIKELY((bits << 1) > (uint64_t{0x7FF} << 53))) {
+ double nan = std::numeric_limits<double>::quiet_NaN();
+ memcpy(&bits, &nan, sizeof(bits));
+ }
+ return bits;
+}
+inline uint32_t CanonicalFloatBits(float value) {
+ uint32_t bits;
+ memcpy(&bits, &value, sizeof(bits));
+ if (PERFETTO_UNLIKELY((bits << 1) == 0)) {
+ return 0;
+ }
+ if (PERFETTO_UNLIKELY((bits << 1) > (uint32_t{0xFF} << 24))) {
+ float nan = std::numeric_limits<float>::quiet_NaN();
+ memcpy(&bits, &nan, sizeof(bits));
+ }
+ return bits;
+}
-// Opens |path| read-only and reads its contents into |*out|.
-// Returns false if the file cannot be opened.
-bool ReadFile(const std::string& path, std::string* out);
+// Adds `a` and `b`, clamping to INT64_MIN / INT64_MAX on overflow instead of
+// wrapping (which is UB and can flip the sign of the result).
+inline int64_t SaturatingAdd(int64_t a, int64_t b) {
+ constexpr int64_t kMax = std::numeric_limits<int64_t>::max();
+ constexpr int64_t kMin = std::numeric_limits<int64_t>::min();
+#if defined(__clang__) || defined(__GNUC__)
+ int64_t result;
+ if (PERFETTO_UNLIKELY(__builtin_add_overflow(a, b, &result)))
+ return a < 0 ? kMin : kMax;
+ return result;
+#else
+ if (b > 0 && a > kMax - b)
+ return kMax;
+ if (b < 0 && a < kMin - b)
+ return kMin;
+ return a + b;
+#endif
+}
-// A wrapper around read(2). It deals with Linux vs Windows includes. It also
-// deals with handling EINTR. Has the same semantics of UNIX's read(2).
-ssize_t Read(int fd, void* dst, size_t dst_size);
+// Multiplies `a` by `b`, clamping to INT64_MIN / INT64_MAX on overflow instead
+// of wrapping (which is UB and can flip the sign of the result).
+inline int64_t SaturatingMultiply(int64_t a, int64_t b) {
+ constexpr int64_t kMax = std::numeric_limits<int64_t>::max();
+ constexpr int64_t kMin = std::numeric_limits<int64_t>::min();
+#if defined(__clang__) || defined(__GNUC__)
+ int64_t result;
+ if (PERFETTO_UNLIKELY(__builtin_mul_overflow(a, b, &result))) {
+ // On overflow the true product's sign is the XOR of the operands' signs.
+ // Neither operand can be zero here (0 never overflows).
+ return ((a < 0) == (b < 0)) ? kMax : kMin;
+ }
+ return result;
+#else
+ // Portable fallback (e.g. MSVC cl.exe): detect overflow *before* multiplying
+ // by dividing a limit by one operand, which never itself overflows.
+ if (a == 0 || b == 0)
+ return 0;
+ if ((a < 0) == (b < 0)) { // Same sign: product is positive.
+ if (a > 0 ? (a > kMax / b) : (a < kMax / b))
+ return kMax;
+ } else { // Opposite signs: product is negative.
+ if (a > 0 ? (b < kMin / a) : (a < kMin / b))
+ return kMin;
+ }
+ return a * b;
+#endif
+}
-// Call write until all data is written or an error is detected.
+// Function object which invokes 'free' on its parameter, which must be
+// a pointer. Can be used to store malloc-allocated pointers in std::unique_ptr:
//
-// man 2 write:
-// If a write() is interrupted by a signal handler before any bytes are
-// written, then the call fails with the error EINTR; if it is
-// interrupted after at least one byte has been written, the call
-// succeeds, and returns the number of bytes written.
-ssize_t WriteAll(int fd, const void* buf, size_t count);
-
-// Copies all data from |fd_in| to |fd_out|. Saves the offset of |fd_in|,
-// rewinds it to the beginning, copies the content, and restores the offset.
-// |fd_in| can't be a pipe, socket of FIFO.
-base::Status CopyFileContents(int fd_in, int fd_out);
-
-ssize_t WriteAllHandle(PlatformHandle, const void* buf, size_t count);
+// std::unique_ptr<int, base::FreeDeleter> foo_ptr(
+// static_cast<int*>(malloc(sizeof(int))));
+struct FreeDeleter {
+ inline void operator()(void* ptr) const { free(ptr); }
+};
-ScopedFile OpenFile(const std::string& path,
- int flags,
- FileOpenMode = kFileModeInvalid);
-ScopedFstream OpenFstream(const std::string& path, const std::string& mode);
+template <typename T>
+constexpr T AssumeLittleEndian(T value) {
+#if !PERFETTO_IS_LITTLE_ENDIAN()
+ static_assert(false, "Unimplemented on big-endian archs");
+#endif
+ return value;
+}
-// This is an alias for close(). It's to avoid leaking windows.h in headers.
-// Exported because ScopedFile is used in the /include/ext API by Chromium
-// component builds.
-int PERFETTO_EXPORT_COMPONENT CloseFile(int fd);
+// Round up |size| to a multiple of |alignment| (must be a power of two).
+inline constexpr size_t AlignUp(size_t size, size_t alignment) {
+ return (size + alignment - 1) & ~(alignment - 1);
+}
-bool FlushFile(int fd);
+// Round down |size| to a multiple of |alignment| (must be a power of two).
+inline constexpr size_t AlignDown(size_t size, size_t alignment) {
+ return size & ~(alignment - 1);
+}
-// Moves the file offset to |offset| bytes from the beginning of the file.
-// Returns false if |offset| cannot be represented by the platform or the seek
-// fails.
-bool SeekFile(int fd, uint64_t offset);
+template <typename T>
+inline constexpr bool IsPowerOfTwo(T x) {
+ static_assert(std::is_unsigned_v<T> && std::is_integral_v<T>,
+ "T must be an unsigned integer");
+ return x != 0 && (x & (x - 1)) == 0;
+}
-// Changes the size of an open file to |size| bytes.
-// Returns false if |size| cannot be represented by the platform or truncation
-// fails.
-bool TruncateFile(int fd, uint64_t size);
+// Returns the smallest power of two greater than or equal to |x|. Returns zero
+// for zero or when the result is not representable by T.
+template <typename T>
+inline constexpr T RoundUpToPowerOfTwo(T x) {
+ static_assert(std::is_unsigned_v<T> && std::is_integral_v<T>,
+ "T must be an unsigned integer");
+ if (x == 0) {
+ return 0;
+ }
+ --x;
+ for (size_t shift = 1; shift < sizeof(T) * 8; shift *= 2) {
+ x |= x >> shift;
+ }
+ return ++x;
+}
-// Returns true if mkdir succeeds, false if it fails (see errno in that case).
-// `mode` is the permission bits for the new directory; it is ignored on
-// Windows.
-bool Mkdir(const std::string& path, uint32_t mode = 0755);
+// TODO(primiano): clean this up and move all existing usages to the constexpr
+// version above.
+template <size_t alignment>
+constexpr size_t AlignUp(size_t size) {
+ static_assert(IsPowerOfTwo(alignment), "alignment must be a pow2");
+ return AlignUp(size, alignment);
+}
-// Calls rmdir() on UNIX, _rmdir() on Windows.
-bool Rmdir(const std::string& path);
+inline bool IsAgain(int err) {
+ return err == EAGAIN || err == EWOULDBLOCK;
+}
-// Removes a file: unlink() on UNIX, _unlink() on Windows. Takes a const char*
-// and is async-signal-safe on POSIX, so it's callable from a signal handler.
-bool Unlink(const char* path);
+// setenv(2)-equivalent. Deals with Windows vs Posix discrepancies.
+void SetEnv(const std::string& key, const std::string& value);
-// Wrapper around access(path, F_OK).
-bool FileExists(const std::string& path);
+// unsetenv(2)-equivalent. Deals with Windows vs Posix discrepancies.
+void UnsetEnv(const std::string& key);
-// Returns true if the path exists and is a directory.
-bool DirectoryExists(const std::string& path);
+// Returns true if |fd| is connected to an interactive terminal (TTY). Deals
+// with Windows vs Posix discrepancies (isatty() vs _isatty()).
+bool IsTty(int fd);
-// Gets the extension for a filename. If the file has two extensions, returns
-// only the last one (foo.pb.gz => .gz). Returns empty string if there is no
-// extension.
-std::string GetFileExtension(const std::string& filename);
+// Convenience overload for C stdio streams (e.g. stdin/stdout/stderr).
+bool IsTty(FILE* stream);
-// Returns the basename component of a path (the final component after the last
-// directory separator). Behaves like man 2 basename, but works with both '/'
-// and '\' separators for cross-platform compatibility.
-// Examples:
-// Basename("/usr/bin/ls") => "ls"
-// Basename("/usr/bin/") => "bin"
-// Basename("/") => "/"
-// Basename("foo") => "foo"
-// Basename("") => "."
-// Basename("C:\\Windows\\System32") => "System32"
-std::string Basename(const std::string& path);
+// Calls mallopt(M_PURGE, 0) on Android. Does nothing on other platforms.
+// This forces the allocator to release freed memory. This is used to work
+// around various Scudo inefficiencies. See b/170217718.
+void MaybeReleaseAllocatorMemToOS();
-// Returns the directory component of a path (everything up to but not
-// including the final component). Behaves like man 2 dirname, but works with
-// both '/' and '\' separators for cross-platform compatibility.
-// Examples:
-// Dirname("/usr/bin/ls") => "/usr/bin"
-// Dirname("/usr/bin") => "/usr"
-// Dirname("/") => "/"
-// Dirname("foo") => "."
-// Dirname("") => "."
-// Dirname("C:\\Windows\\System32") => "C:\\Windows"
-std::string Dirname(const std::string& path);
+// geteuid() on POSIX OSes, returns 0 on Windows (See comment in utils.cc).
+uid_t GetCurrentUserId();
-// Returns the length of the leading root component of a path: "/" on UNIX,
-// "C:\" or "\\" (UNC) on Windows. Returns 0 if the path is relative. Like
-// Basename() and Dirname(), both '/' and '\' are recognized on all platforms.
-// Stripping the returned prefix turns the path into a relative one.
-// Examples:
-// PathRootPrefixLength("/usr/bin/ls") => 1
-// PathRootPrefixLength("//usr/bin") => 2
-// PathRootPrefixLength("C:\\Windows") => 3
-// PathRootPrefixLength("C:foo") => 0 (relative to the current dir of drive
-// C:) PathRootPrefixLength("foo/bar") => 0
-size_t PathRootPrefixLength(const std::string& path);
+// Forks the process.
+// Parent: calls |parent_cb| with the child's PID and exits with its return
+// value. The callback owns any startup output (e.g. printing the PID).
+// Child: redirects stdio onto /dev/null, chdirs into / and returns.
+void Daemonize(std::function<int(pid_t)> parent_cb);
-// Returns true if the path starts with a root component. See
-// PathRootPrefixLength().
-bool IsAbsolutePath(const std::string& path);
+// Returns the path of the current executable, e.g. /foo/bar/exe.
+std::string GetCurExecutablePath();
-// Puts the path to all files under |dir_path| in |output|, recursively walking
-// subdirectories. File paths are relative to |dir_path|. Only files are
-// included, not directories. Path separator is always '/', even on windows (not
-// '\').
-base::Status ListFilesRecursive(const std::string& dir_path,
- std::vector<std::string>& output);
+// Returns the directory where the current executable lives in, e.g. /foo/bar.
+// This is independent of cwd().
+std::string GetCurExecutableDir();
-// Lists immediate subdirectories in |dir_path| (non-recursive). Directory names
-// are relative to |dir_path| and do not include the path separator. Returns
-// only directories, not files. Works on both Unix and Windows.
-base::Status ListDirectories(const std::string& dir_path,
- std::vector<std::string>& output);
+// Memory returned by AlignedAlloc() must be freed via AlignedFree() not just
+// free. It makes a difference on Windows where _aligned_malloc() and
+// _aligned_free() must be paired.
+// Prefer using the AlignedAllocTyped() below which takes care of the pairing.
+void* AlignedAlloc(size_t alignment, size_t size);
+void AlignedFree(void*);
-// Sets |path|'s owner group to |group_name| and permission mode bits to
-// |mode_bits|.
-base::Status SetFilePermissions(const std::string& path,
- const std::string& group_name,
- const std::string& mode_bits);
+// Detects Sync-mode MTE (currently being tested in some Android builds).
+// This is known to use extra memory for the stack history buffer.
+bool IsSyncMemoryTaggingEnabled();
-// Returns the size of the file located at |path|, or nullopt in case of error.
-std::optional<uint64_t> GetFileSize(const std::string& path);
+// A RAII version of the above, which takes care of pairing Aligned{Alloc,Free}.
+template <typename T>
+struct AlignedDeleter {
+ inline void operator()(T* ptr) const { AlignedFree(ptr); }
+};
-// Returns the size of the open file |fd|, or nullopt in case of error.
-std::optional<uint64_t> GetFileSize(PlatformHandle fd);
+// The remove_extent<T> here and below is to allow defining unique_ptr<T[]>.
+// As per https://en.cppreference.com/w/cpp/memory/unique_ptr the Deleter takes
+// always a T*, not a T[]*.
+template <typename T>
+using AlignedUniquePtr =
+ std::unique_ptr<T, AlignedDeleter<typename std::remove_extent<T>::type>>;
-#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
-// On Windows PlatformHandle is a HANDLE, not a file descriptor. This overload
-// accepts the CRT file descriptors returned by base::OpenFile(). On other
-// platforms PlatformHandle is an int, so the overload above already covers it.
-std::optional<uint64_t> GetFileSize(int fd);
-#endif
+template <typename T>
+AlignedUniquePtr<T> AlignedAllocTyped(size_t n_membs) {
+ using TU = typename std::remove_extent<T>::type;
+ return AlignedUniquePtr<T>(
+ static_cast<TU*>(AlignedAlloc(alignof(TU), sizeof(TU) * n_membs)));
+}
-// This class uses inotify (on Linux/Android) to watch for the creation of
-// files in the filesystem. When the specified file is created, it triggers a
-// callback function.
-// Destroying the returned unique_ptr will automatically unregister the watch.
-//
-// Note: This only works with filesystem paths (not abstract sockets or other
-// special file types).
-// It's only supported on Linux and Android, it's a no-op (returns nullptr) on
-// other platforms.
-//
-// Usage:
-// auto watch = LinuxFileWatch::WatchFileCreation(
-// task_runner, "/tmp/my_file", []() {
-// // Called when /tmp/my_file is created
-// });
-class LinuxFileWatch {
+// A RAII wrapper to invoke a function when leaving a function/scope.
+template <typename Func>
+class OnScopeExitWrapper {
public:
- // Creates a watcher for file creation. Returns nullptr if the path is not a
- // valid filesystem path or if the platform doesn't support inotify. The
- // callback will be invoked on the provided TaskRunner when the file is
- // created.
- static std::unique_ptr<LinuxFileWatch> WatchFileCreation(
- TaskRunner*,
- const char* path,
- std::function<void()> callback);
-
- virtual ~LinuxFileWatch();
+ explicit OnScopeExitWrapper(Func f) : f_(std::move(f)), active_(true) {}
+ OnScopeExitWrapper(OnScopeExitWrapper&& other) noexcept
+ : f_(std::move(other.f_)), active_(other.active_) {
+ other.active_ = false;
+ }
+ ~OnScopeExitWrapper() {
+ if (active_)
+ f_();
+ }
- protected:
- LinuxFileWatch() = default;
+ private:
+ Func f_;
+ bool active_;
};
+template <typename Func>
+PERFETTO_WARN_UNUSED_RESULT OnScopeExitWrapper<Func> OnScopeExit(Func f) {
+ return OnScopeExitWrapper<Func>(std::move(f));
+}
+
+// Returns a xxd-style hex dump (hex + ascii chars) of the input data.
+std::string HexDump(const void* data, size_t len, size_t bytes_per_line = 16);
+inline std::string HexDump(const std::string& data,
+ size_t bytes_per_line = 16) {
+ return HexDump(data.data(), data.size(), bytes_per_line);
+}
+
} // namespace base
} // namespace perfetto
-#endif // INCLUDE_PERFETTO_EXT_BASE_FILE_UTILS_H_
-// gen_amalgamated begin header: include/perfetto/ext/base/string_splitter.h
+#endif // INCLUDE_PERFETTO_EXT_BASE_UTILS_H_
/*
- * Copyright (C) 2018 The Android Open Source Project
+ * Copyright (C) 2021 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.
@@ -2324,91 +2481,298 @@ class LinuxFileWatch {
* limitations under the License.
*/
-#ifndef INCLUDE_PERFETTO_EXT_BASE_STRING_SPLITTER_H_
-#define INCLUDE_PERFETTO_EXT_BASE_STRING_SPLITTER_H_
+#ifndef INCLUDE_PERFETTO_EXT_BASE_BASE64_H_
+#define INCLUDE_PERFETTO_EXT_BASE_BASE64_H_
+#include <optional>
#include <string>
+// gen_amalgamated expanded: #include "perfetto/ext/base/string_view.h"
+// gen_amalgamated expanded: #include "perfetto/ext/base/utils.h" // For ssize_t.
+
namespace perfetto {
namespace base {
-// C++ version of strtok(). Splits a string without making copies or any heap
-// allocations. Destructs the original string passed in input.
-// Supports the special case of using \0 as a delimiter.
-// The token returned in output are valid as long as the input string is valid.
-class StringSplitter {
- public:
- // Whether an empty string (two delimiters side-to-side) is a valid token.
- enum class EmptyTokenMode {
- DISALLOW_EMPTY_TOKENS,
- ALLOW_EMPTY_TOKENS,
+// Returns the length of the destination string (included '=' padding).
+// Does NOT include the size of the string null terminator.
+inline size_t Base64EncSize(size_t src_size) {
+ return (src_size + 2) / 3 * 4;
+}
- DEFAULT = DISALLOW_EMPTY_TOKENS,
- };
+// Returns the upper bound on the length of the destination buffer.
+// The actual decoded length might be <= the number returned here.
+inline size_t Base64DecSize(size_t src_size) {
+ return (src_size + 3) / 4 * 3;
+}
- // Can take ownership of the string if passed via std::move(), e.g.:
- // StringSplitter(std::move(str), '\n');
- StringSplitter(std::string,
- char delimiter,
- EmptyTokenMode empty_token_mode = EmptyTokenMode::DEFAULT);
+// Does NOT null-terminate |dst|.
+ssize_t Base64Encode(const void* src,
+ size_t src_size,
+ char* dst,
+ size_t dst_size);
- // Splits a C-string. The input string will be forcefully null-terminated (so
- // str[size - 1] should be == '\0' or the last char will be truncated).
- StringSplitter(char* str,
- size_t size,
- char delimiter,
- EmptyTokenMode empty_token_mode = EmptyTokenMode::DEFAULT);
+std::string Base64Encode(const void* src, size_t src_size);
- // Splits the current token from an outer StringSplitter instance. This is to
- // chain splitters as follows:
- // for (base::StringSplitter lines(x, '\n'); ss.Next();)
- // for (base::StringSplitter words(&lines, ' '); words.Next();)
- StringSplitter(StringSplitter*,
- char delimiter,
- EmptyTokenMode empty_token_mode = EmptyTokenMode::DEFAULT);
+inline std::string Base64Encode(StringView sv) {
+ return Base64Encode(sv.data(), sv.size());
+}
- // Returns true if a token is found (in which case it will be stored in
- // cur_token()), false if no more tokens are found.
- bool Next();
+// Returns -1 in case of failure.
+ssize_t Base64Decode(const char* src,
+ size_t src_size,
+ uint8_t* dst,
+ size_t dst_size);
- // Returns the next token if found (in which case it will be stored in
- // cur_token()), nullptr if no more tokens are found.
- char* NextToken() { return Next() ? cur_token() : nullptr; }
+std::optional<std::string> Base64Decode(const char* src, size_t src_size);
- // Returns the current token iff last call to Next() returned true. In this
- // case it guarantees that the returned string is always null terminated.
- // In all other cases (before the 1st call to Next() and after Next() returns
- // false) returns nullptr.
- char* cur_token() { return cur_; }
+inline std::optional<std::string> Base64Decode(StringView sv) {
+ return Base64Decode(sv.data(), sv.size());
+}
- // Returns the length of the current token (excluding the null terminator).
- size_t cur_token_size() const { return cur_size_; }
+} // namespace base
+} // namespace perfetto
- // Return the untokenized remainder of the input string that occurs after the
- // current token.
- char* remainder() { return next_; }
+#endif // INCLUDE_PERFETTO_EXT_BASE_BASE64_H_
+/*
+ * Copyright (C) 2021 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.
+ */
- // Returns the size of the untokenized input
- size_t remainder_size() { return static_cast<size_t>(end_ - next_); }
+// gen_amalgamated expanded: #include "perfetto/ext/base/base64.h"
- private:
- StringSplitter(const StringSplitter&) = delete;
- StringSplitter& operator=(const StringSplitter&) = delete;
- void Initialize(char* str, size_t size);
+namespace perfetto {
+namespace base {
- std::string str_;
- char* cur_;
- size_t cur_size_;
- char* next_;
- char* end_; // STL-style, points one past the last char.
- const char delimiter_;
- const EmptyTokenMode empty_token_mode_;
+namespace {
+
+constexpr char kPadding = '=';
+
+constexpr char kEncTable[] =
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+static_assert(sizeof(kEncTable) == (1u << 6) + sizeof('\0'), "Bad table size");
+
+// Maps an ASCII character to its 6-bit value. It only contains translations
+// from '+' to 'z'. Supports the standard (+/) and URL-safe (-_) alphabets.
+constexpr uint8_t kX = 0xff; // Value used for invalid characters
+constexpr uint8_t kDecTable[] = {
+ 62, kX, 62, kX, 63, 52, 53, 54, 55, 56, // 00 - 09
+ 57, 58, 59, 60, 61, kX, kX, kX, 0, kX, // 10 - 19
+ kX, kX, 0, 1, 2, 3, 4, 5, 6, 7, // 20 - 29
+ 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, // 30 - 39
+ 18, 19, 20, 21, 22, 23, 24, 25, kX, kX, // 40 - 49
+ kX, kX, 63, kX, 26, 27, 28, 29, 30, 31, // 50 - 59
+ 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, // 60 - 69
+ 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, // 70 - 79
+};
+constexpr char kMinDecChar = '+';
+constexpr char kMaxDecChar = 'z';
+static_assert(kMaxDecChar - kMinDecChar <= sizeof(kDecTable), "Bad table size");
+
+inline uint8_t DecodeChar(char c) {
+ if (c < kMinDecChar || c > kMaxDecChar)
+ return kX;
+ return kDecTable[c - kMinDecChar];
+}
+
+} // namespace
+
+ssize_t Base64Encode(const void* src,
+ size_t src_size,
+ char* dst,
+ size_t dst_size) {
+ const size_t padded_dst_size = Base64EncSize(src_size);
+ if (dst_size < padded_dst_size)
+ return -1; // Not enough space in output.
+
+ const uint8_t* rd = static_cast<const uint8_t*>(src);
+ const uint8_t* const end = rd + src_size;
+ size_t wr_size = 0;
+ while (rd < end) {
+ uint8_t s[3]{};
+ s[0] = *(rd++);
+ dst[wr_size++] = kEncTable[s[0] >> 2];
+
+ uint8_t carry0 = static_cast<uint8_t>((s[0] & 0x03) << 4);
+ if (PERFETTO_LIKELY(rd < end)) {
+ s[1] = *(rd++);
+ dst[wr_size++] = kEncTable[carry0 | (s[1] >> 4)];
+ } else {
+ dst[wr_size++] = kEncTable[carry0];
+ dst[wr_size++] = kPadding;
+ dst[wr_size++] = kPadding;
+ break;
+ }
+
+ uint8_t carry1 = static_cast<uint8_t>((s[1] & 0x0f) << 2);
+ if (PERFETTO_LIKELY(rd < end)) {
+ s[2] = *(rd++);
+ dst[wr_size++] = kEncTable[carry1 | (s[2] >> 6)];
+ } else {
+ dst[wr_size++] = kEncTable[carry1];
+ dst[wr_size++] = kPadding;
+ break;
+ }
+
+ dst[wr_size++] = kEncTable[s[2] & 0x3f];
+ }
+ PERFETTO_DCHECK(wr_size == padded_dst_size);
+ return static_cast<ssize_t>(padded_dst_size);
+}
+
+std::string Base64Encode(const void* src, size_t src_size) {
+ std::string dst;
+ dst.resize(Base64EncSize(src_size));
+ auto res = Base64Encode(src, src_size, &dst[0], dst.size());
+ PERFETTO_CHECK(res == static_cast<ssize_t>(dst.size()));
+ return dst;
+}
+
+ssize_t Base64Decode(const char* src,
+ size_t src_size,
+ uint8_t* dst,
+ size_t dst_size) {
+ const size_t min_dst_size = Base64DecSize(src_size);
+ if (dst_size < min_dst_size)
+ return -1;
+
+ const char* rd = src;
+ const char* const end = src + src_size;
+ size_t wr_size = 0;
+
+ char s[4]{};
+ while (rd < end) {
+ uint8_t d[4];
+ for (uint32_t j = 0; j < 4; j++) {
+ // Padding is only feasible for the last 2 chars of each group of 4.
+ s[j] = rd < end ? *(rd++) : (j < 2 ? '\0' : kPadding);
+ d[j] = DecodeChar(s[j]);
+ if (d[j] == kX)
+ return -1; // Invalid input char.
+ }
+ dst[wr_size] = static_cast<uint8_t>((d[0] << 2) | (d[1] >> 4));
+ dst[wr_size + 1] = static_cast<uint8_t>((d[1] << 4) | (d[2] >> 2));
+ dst[wr_size + 2] = static_cast<uint8_t>((d[2] << 6) | (d[3]));
+ wr_size += 3;
+ }
+
+ PERFETTO_CHECK(wr_size <= dst_size);
+ wr_size -= (s[3] == kPadding ? 1 : 0) + (s[2] == kPadding ? 1 : 0);
+ return static_cast<ssize_t>(wr_size);
+}
+
+std::optional<std::string> Base64Decode(const char* src, size_t src_size) {
+ std::string dst;
+ dst.resize(Base64DecSize(src_size));
+ auto res = Base64Decode(src, src_size, reinterpret_cast<uint8_t*>(&dst[0]),
+ dst.size());
+ if (res < 0)
+ return std::nullopt; // Decoding error.
+
+ PERFETTO_CHECK(res <= static_cast<ssize_t>(dst.size()));
+ dst.resize(static_cast<size_t>(res));
+ return std::make_optional(dst);
+}
+
+} // namespace base
+} // namespace perfetto
+// gen_amalgamated begin source: src/base/cpu_info.cc
+// gen_amalgamated begin header: include/perfetto/ext/base/cpu_info.h
+/*
+ * Copyright (C) 2026 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_CPU_INFO_H_
+#define INCLUDE_PERFETTO_EXT_BASE_CPU_INFO_H_
+
+#include <stdint.h>
+#include <optional>
+#include <string>
+#include <vector>
+
+namespace perfetto {
+namespace base {
+
+struct CpuInfo {
+ std::string processor;
+ uint32_t cpu_index = 0;
+ std::optional<uint32_t> implementer;
+ std::optional<uint32_t> architecture;
+ std::optional<uint32_t> variant;
+ std::optional<uint32_t> part;
+ std::optional<uint32_t> revision;
+ uint64_t features = 0;
+ char arm_cpuid[32] = {};
};
+// Parses the contents of the input string into per-CPU entries.
+std::vector<CpuInfo> ParseCpuInfo(std::string proc_cpu_info);
+
+// Reads /proc/cpuinfo and parses it into per-CPU entries.
+std::vector<CpuInfo> ReadCpuInfo();
+
} // namespace base
} // namespace perfetto
-#endif // INCLUDE_PERFETTO_EXT_BASE_STRING_SPLITTER_H_
+#endif // INCLUDE_PERFETTO_EXT_BASE_CPU_INFO_H_
+// gen_amalgamated begin header: include/perfetto/ext/base/cpu_info_features_allowlist.h
+/*
+ * Copyright (C) 2025 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_CPU_INFO_FEATURES_ALLOWLIST_H_
+#define INCLUDE_PERFETTO_EXT_BASE_CPU_INFO_FEATURES_ALLOWLIST_H_
+
+namespace perfetto {
+namespace base {
+
+// APPEND ONLY. DO NOT EVER REMOVE ENTRIES FROM THIS ARRAY OR REORDER.
+// This array is used both by traced_probes and trace_processor to index the
+// cpuinfo flags. Changing the order will break trace_processor compatibility
+// with old traces.
+constexpr const char* kCpuInfoFeatures[] = {
+ "mte", // DO NOT REMOVE/REODER.
+ "mte3", // DO NOT REMOVE/REODER.
+};
+
+} // namespace base
+} // namespace perfetto
+
+#endif // INCLUDE_PERFETTO_EXT_BASE_CPU_INFO_FEATURES_ALLOWLIST_H_
/*
* Copyright (C) 2026 The Android Open Source Project
*
@@ -3991,6 +4355,51 @@ bool FlushFile(int fd) {
#endif
}
+ScopedFile DupFile(int fd) {
+#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
+ ScopedFile duplicate(_dup(fd));
+ if (duplicate && !SetHandleInformation(
+ reinterpret_cast<HANDLE>(_get_osfhandle(*duplicate)),
+ HANDLE_FLAG_INHERIT, 0))
+ return ScopedFile();
+ return duplicate;
+#else
+ return ScopedFile(fcntl(fd, F_DUPFD_CLOEXEC, 0));
+#endif
+}
+
+bool IsRegularFile(const std::string& path) {
+ struct stat st{};
+ if (stat(path.c_str(), &st) != 0)
+ return false;
+ PERFETTO_MSAN_UNPOISON(&st, sizeof(st));
+ return (st.st_mode & S_IFMT) == S_IFREG;
+}
+
+bool IsSameFile(const std::string& first, const std::string& second) {
+#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
+ auto identity = [](const std::string& path,
+ BY_HANDLE_FILE_INFORMATION* info) {
+ ScopedPlatformHandle file(CreateFileA(
+ path.c_str(), 0, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
+ nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr));
+ return file && GetFileInformationByHandle(*file, info);
+ };
+ BY_HANDLE_FILE_INFORMATION a{}, b{};
+ return identity(first, &a) && identity(second, &b) &&
+ a.dwVolumeSerialNumber == b.dwVolumeSerialNumber &&
+ a.nFileIndexHigh == b.nFileIndexHigh &&
+ a.nFileIndexLow == b.nFileIndexLow;
+#else
+ struct stat a{}, b{};
+ if (stat(first.c_str(), &a) != 0 || stat(second.c_str(), &b) != 0)
+ return false;
+ PERFETTO_MSAN_UNPOISON(&a, sizeof(a));
+ PERFETTO_MSAN_UNPOISON(&b, sizeof(b));
+ return a.st_dev == b.st_dev && a.st_ino == b.st_ino;
+#endif
+}
+
bool SeekFile(int fd, uint64_t offset) {
#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
if (fd < 0) {
@@ -4082,15 +4491,6 @@ ScopedFile OpenFile(const std::string& path, int flags, FileOpenMode mode) {
ScopedFstream OpenFstream(const std::string& path, const std::string& mode) {
ScopedFstream file;
- // On Windows fopen interprets filename using the ANSI or OEM codepage but
- // sqlite3_value_text returns a UTF-8 string. To make sure we interpret the
- // filename correctly we use _wfopen and a UTF-16 string on windows.
- //
- // On Windows fopen also open files in the text mode by default, but we want
- // to open them in the binary mode, to avoid silly EOL translations (and to be
- // consistent with base::OpenFile). So we check the mode first and append 'b'
- // mode only when it makes sense.
-#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
std::string s_mode(mode);
// Windows supports non-standard mode extension that sets encoding in text
// mode. If you need to open a FILE* in text mode, use the fopen API directly.
@@ -4100,13 +4500,22 @@ ScopedFstream OpenFstream(const std::string& path, const std::string& mode) {
if (!is_binary_mode)
s_mode += 'b';
+#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
+ // On Windows fopen interprets filename using the ANSI or OEM codepage but
+ // sqlite3_value_text returns a UTF-8 string. To make sure we interpret the
+ // filename correctly we use _wfopen and a UTF-16 string on windows.
+ //
+ // On Windows fopen also open files in the text mode by default, but we want
+ // to open them in the binary mode, to avoid silly EOL translations (and to be
+ // consistent with base::OpenFile). So we check the mode first and append 'b'
+ // mode only when it makes sense.
auto w_path = ToUtf16(path);
auto w_mode = ToUtf16(s_mode);
if (w_path && w_mode) {
file.reset(_wfopen(w_path->c_str(), w_mode->c_str()));
}
#else
- file.reset(fopen(path.c_str(), mode.c_str()));
+ file.reset(fopen(path.c_str(), s_mode.c_str()));
#endif
return file;
}
@@ -4569,10 +4978,11 @@ LinuxFileWatch::~LinuxFileWatch() = default;
} // namespace base
} // namespace perfetto
-// gen_amalgamated begin source: src/base/getopt_compat.cc
-// gen_amalgamated begin header: include/perfetto/ext/base/getopt_compat.h
+// gen_amalgamated begin source: src/base/flat_hash_map.cc
+// gen_amalgamated begin header: include/perfetto/ext/base/flat_hash_map.h
+// gen_amalgamated begin header: include/perfetto/ext/base/bits.h
/*
- * Copyright (C) 2021 The Android Open Source Project
+ * Copyright (C) 2025 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.
@@ -4587,63 +4997,95 @@ LinuxFileWatch::~LinuxFileWatch() = default;
* limitations under the License.
*/
-#ifndef INCLUDE_PERFETTO_EXT_BASE_GETOPT_COMPAT_H_
-#define INCLUDE_PERFETTO_EXT_BASE_GETOPT_COMPAT_H_
+#ifndef INCLUDE_PERFETTO_EXT_BASE_BITS_H_
+#define INCLUDE_PERFETTO_EXT_BASE_BITS_H_
-#include <cstddef> // For std::nullptr_t
+#include <cstddef>
+#include <cstdint>
-// No translation units other than base/getopt.h and getopt_compat_unittest.cc
-// should directly include this file. Use base/getopt.h instead.
+// gen_amalgamated expanded: #include "perfetto/base/build_config.h"
+// gen_amalgamated expanded: #include "perfetto/base/compiler.h"
+
+#if PERFETTO_BUILDFLAG(PERFETTO_X64_CPU_OPT)
+#include <immintrin.h>
+#endif
namespace perfetto {
namespace base {
-namespace getopt_compat {
-// A tiny getopt() replacement for Windows, which doesn't have <getopt.h>.
-// This implementation is based on the subset of features that we use in the
-// Perfetto codebase. It doesn't even try to deal with the full surface of GNU's
-// getopt().
-// Limitations:
-// - getopt_long_only() is not supported.
-// - optional_argument is not supported. That is extremely subtle and caused us
-// problems in the past with GNU's getopt.
-// - It does not reorder non-option arguments. It behaves like MacOS getopt, or
-// GNU's when POSIXLY_CORRECT=1.
-// - Doesn't expose optopt or opterr.
-// - option.flag and longindex are not supported and must be nullptr.
+inline PERFETTO_ALWAYS_INLINE uint32_t CountLeadZeros32(uint32_t value) {
+#if PERFETTO_BUILDFLAG(PERFETTO_X64_CPU_OPT)
+ return static_cast<uint32_t>(_lzcnt_u32(value));
+#elif defined(__GNUC__) || defined(__clang__)
+ return value ? static_cast<uint32_t>(__builtin_clz(value)) : 32u;
+#else
+ unsigned long out;
+ return _BitScanReverse(&out, value) ? 31 - out : 32u;
+#endif
+}
-enum {
- no_argument = 0,
- required_argument = 1,
-};
+inline PERFETTO_ALWAYS_INLINE uint32_t CountLeadZeros64(uint64_t value) {
+#if PERFETTO_BUILDFLAG(PERFETTO_X64_CPU_OPT)
+ return static_cast<uint32_t>(_lzcnt_u64(value));
+#elif defined(__GNUC__) || defined(__clang__)
+ return value ? static_cast<uint32_t>(__builtin_clzll(value)) : 64u;
+#else
+ unsigned long out;
+ return _BitScanReverse64(&out, value) ? 63 - out : 64u;
+#endif
+}
-struct option {
- const char* name;
- int has_arg;
- std::nullptr_t flag; // Only nullptr is supported.
- int val;
-};
+template <typename T>
+uint32_t CountLeadZeros(T value) {
+ if constexpr (sizeof(T) == 8)
+ return CountLeadZeros64(static_cast<uint64_t>(value));
+ return CountLeadZeros32(static_cast<uint32_t>(value));
+}
-extern char* optarg;
-extern int optind;
-extern int optopt;
-extern int opterr;
+inline PERFETTO_ALWAYS_INLINE uint32_t CountTrailZeros64(uint64_t value) {
+#if PERFETTO_BUILDFLAG(PERFETTO_X64_CPU_OPT)
+ return static_cast<uint32_t>(_tzcnt_u64(value));
+#elif defined(__GNUC__) || defined(__clang__)
+ return value ? static_cast<uint32_t>(__builtin_ctzll(value)) : 64u;
+#else
+ unsigned long out;
+ return _BitScanForward64(&out, value) ? static_cast<uint32_t>(out) : 64u;
+#endif
+}
-int getopt_long(int argc,
- char** argv,
- const char* shortopts,
- const option* longopts,
- std::nullptr_t /*longindex is not supported*/);
+inline PERFETTO_ALWAYS_INLINE uint32_t CountTrailZeros32(uint32_t value) {
+#if PERFETTO_BUILDFLAG(PERFETTO_X64_CPU_OPT)
+ return _tzcnt_u32(value);
+#elif defined(__GNUC__) || defined(__clang__)
+ return value ? static_cast<uint32_t>(__builtin_ctz(value)) : 32u;
+#else
+ unsigned long out;
+ return _BitScanForward(&out, value) ? out : 32u;
+#endif
+}
-int getopt(int argc, char** argv, const char* shortopts);
+template <typename T>
+inline PERFETTO_ALWAYS_INLINE uint32_t CountTrailZeros(T value) {
+ if (sizeof(T) == 8) {
+ return CountTrailZeros64(static_cast<uint64_t>(value));
+ }
+ return CountTrailZeros32(static_cast<uint32_t>(value));
+}
+
+template <typename T>
+constexpr bool AllBitsSet(T v) {
+ return v == static_cast<T>(-1);
+}
-} // namespace getopt_compat
} // namespace base
} // namespace perfetto
-#endif // INCLUDE_PERFETTO_EXT_BASE_GETOPT_COMPAT_H_
+#endif // INCLUDE_PERFETTO_EXT_BASE_BITS_H_
+// gen_amalgamated begin header: include/perfetto/ext/base/flat_hash_map_v1.h
+// gen_amalgamated begin header: include/perfetto/ext/base/murmur_hash.h
+// gen_amalgamated begin header: include/perfetto/ext/base/hash.h
/*
- * Copyright (C) 2021 The Android Open Source Project
+ * 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.
@@ -4658,289 +5100,90 @@ int getopt(int argc, char** argv, const char* shortopts);
* limitations under the License.
*/
-// gen_amalgamated expanded: #include "perfetto/ext/base/getopt_compat.h"
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include <vector>
-
-// gen_amalgamated expanded: #include "perfetto/base/logging.h"
+#ifndef INCLUDE_PERFETTO_EXT_BASE_HASH_H_
+#define INCLUDE_PERFETTO_EXT_BASE_HASH_H_
-namespace perfetto {
-namespace base {
-namespace getopt_compat {
+#include <cstddef>
+#include <cstdint>
+#include <memory>
+#include <optional>
+#include <tuple>
+#include <utility>
-char* optarg = nullptr;
-int optind = 0;
-int optopt = 0;
-int opterr = 1;
+namespace perfetto::base {
-namespace {
+// ============================================================================
+// Absl-style hash customization point
+// ============================================================================
+//
+// To make a type hashable with Perfetto hash functions, define a friend
+// function template:
+//
+// template <typename H>
+// friend H PerfettoHashValue(H h, const MyType& value) {
+// return H::Combine(std::move(h), value.field1, value.field2);
+// }
+//
+// This function will be found via ADL (Argument Dependent Lookup) when hashing
+// your type. No forward declaration is needed - ADL finds it in your type's
+// namespace.
-char* nextchar = nullptr;
+// ============================================================================
+// Built-in PerfettoHashValue implementations for common standard library
+// types. These allow standard library types to work seamlessly with the
+// absl-style hash API without requiring users to define their own
+// implementations.
+// ============================================================================
-const option* LookupLongOpt(const std::vector<option>& opts,
- const char* name,
- size_t len) {
- for (const option& opt : opts) {
- if (strncmp(opt.name, name, len) == 0 && strlen(opt.name) == len)
- return &opt;
+// Hash function for std::optional - hashes the value if present, or a sentinel
+// if not.
+template <typename H, typename T>
+H PerfettoHashValue(H h, const std::optional<T>& value) {
+ if (value.has_value()) {
+ return H::Combine(H::Combine(std::move(h), true), *value);
}
- return nullptr;
+ return H::Combine(std::move(h), false, 0);
}
-const option* LookupShortOpt(const std::vector<option>& opts, char c) {
- for (const option& opt : opts) {
- if (!*opt.name && opt.val == c)
- return &opt;
- }
- return nullptr;
+// Hash function for std::pair - combines hashes of both elements.
+template <typename H, typename T1, typename T2>
+H PerfettoHashValue(H h, const std::pair<T1, T2>& value) {
+ return H::Combine(std::move(h), value.first, value.second);
}
-// Returns true if |token| is an option-bearing argv element whose argument
-// is supplied by the next argv element (rather than embedded or absent).
-// Used by the GNU-style permutation logic in getopt_long().
-bool TokenConsumesNextArg(const char* token, const std::vector<option>& opts) {
- if (token[0] != '-' || token[1] == '\0')
- return false;
- if (token[1] == '-') {
- // Long option: "--name" needs a separate arg if it's required_argument
- // and there is no embedded "=value".
- if (token[2] == '\0')
- return false; // "--" alone.
- if (strchr(token + 2, '=') != nullptr)
- return false;
- size_t len = strlen(token + 2);
- const option* opt = LookupLongOpt(opts, token + 2, len);
- return opt && opt->has_arg == required_argument;
- }
- // Short option chain: "-abc" / "-aXYZ". Walk until we find an option that
- // requires an argument; if it is the last character of the token, the next
- // argv element is the argument. Anything after it would be the embedded arg.
- for (size_t i = 1; token[i] != '\0'; ++i) {
- const option* opt = LookupShortOpt(opts, token[i]);
- if (!opt)
- return false;
- if (opt->has_arg == required_argument)
- return token[i + 1] == '\0';
- }
- return false;
+// Hash function for std::tuple - combines hashes of all elements.
+template <typename H, typename... Ts>
+H PerfettoHashValue(H h, const std::tuple<Ts...>& value) {
+ return std::apply(
+ [&h](const auto&... elements) {
+ return H::Combine(std::move(h), elements...);
+ },
+ value);
}
-bool ParseOpts(const char* shortopts,
- const option* longopts,
- std::vector<option>* res) {
- // Parse long options first.
- for (const option* lopt = longopts; lopt && lopt->name; lopt++) {
- PERFETTO_CHECK(lopt->flag == nullptr);
- PERFETTO_CHECK(lopt->has_arg == no_argument ||
- lopt->has_arg == required_argument);
- res->emplace_back(*lopt);
- }
-
- // Merge short options.
- for (const char* sopt = shortopts; sopt && *sopt;) {
- const size_t idx = static_cast<size_t>(sopt - shortopts);
- char c = *sopt++;
- bool valid = (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') ||
- (c >= '0' && c <= '9');
- if (!valid) {
- fprintf(stderr,
- "Error parsing shortopts. Unexpected char '%c' at offset %zu\n",
- c, idx);
- return false;
- }
- res->emplace_back();
- option& opt = res->back();
- opt.name = "";
- opt.val = c;
- opt.has_arg = no_argument;
- if (*sopt == ':') {
- opt.has_arg = required_argument;
- ++sopt;
- }
- }
- return true;
+// Hash function for pointers - hashes the pointer value as an integer.
+template <typename H, typename T>
+H PerfettoHashValue(H h, const std::unique_ptr<T>& ptr) {
+ return H::Combine(std::move(h), ptr.get());
}
-
-} // namespace
-
-int getopt_long(int argc,
- char** argv,
- const char* shortopts,
- const option* longopts,
- std::nullptr_t /*longind*/) {
- std::vector<option> opts;
- optarg = nullptr;
-
- if (optind == 0)
- optind = 1;
-
- if (optind >= argc)
- return -1;
-
- if (!ParseOpts(shortopts, longopts, &opts))
- return '?';
-
- // GNU-style permutation: if we're at a non-option, move the next option
- // (and its separate argument, if any) into position |optind|, shifting any
- // intervening non-options to the right. This matches the default behavior
- // of GNU getopt(3) so positional args can be freely interleaved with flags.
- // We only permute when |nextchar| is null (i.e. we're not in the middle of
- // a "-abc" short-option chain).
- if (!nextchar) {
- int scan = optind;
- while (scan < argc) {
- const char* s = argv[scan];
- // Stop at the next option-bearing token ("-x", "--long", or "--").
- if (s[0] == '-' && s[1] != '\0')
- break;
- ++scan;
- }
- // No permutation if there's nothing before the next option, or if the
- // next token is "--" (the explicit end-of-options marker).
- if (scan < argc && scan > optind && strcmp(argv[scan], "--") != 0) {
- bool takes_next = TokenConsumesNextArg(argv[scan], opts);
- int count = (takes_next && scan + 1 < argc) ? 2 : 1;
- char* opt_token = argv[scan];
- char* opt_arg = count == 2 ? argv[scan + 1] : nullptr;
- // Shift argv[optind..scan) right by |count| to make room.
- for (int k = scan - 1; k >= optind; --k)
- argv[k + count] = argv[k];
- argv[optind] = opt_token;
- if (count == 2)
- argv[optind + 1] = opt_arg;
- }
- }
-
- char* arg = argv[optind];
- optopt = 0;
-
- if (!nextchar) {
- // If |nextchar| is null we are NOT in the middle of a short option and we
- // should parse the next argv.
- if (strncmp(arg, "--", 2) == 0 && strlen(arg) > 2) {
- // A --long option.
- arg += 2;
- char* sep = strchr(arg, '=');
- optind++;
-
- size_t len = sep ? static_cast<size_t>(sep - arg) : strlen(arg);
- const option* opt = LookupLongOpt(opts, arg, len);
-
- if (!opt) {
- if (opterr)
- fprintf(stderr, "unrecognized option '--%s'\n", arg);
- return '?';
- }
-
- optopt = opt->val;
- if (opt->has_arg == no_argument) {
- if (sep) {
- fprintf(stderr, "option '--%s' doesn't allow an argument\n", arg);
- return '?';
- } else {
- return opt->val;
- }
- } else if (opt->has_arg == required_argument) {
- if (sep) {
- optarg = sep + 1;
- return opt->val;
- } else if (optind >= argc) {
- if (opterr)
- fprintf(stderr, "option '--%s' requires an argument\n", arg);
- return '?';
- } else {
- optarg = argv[optind++];
- return opt->val;
- }
- }
- // has_arg must be either |no_argument| or |required_argument|. We
- // shoulnd't get here unless the check in ParseOpts() has a bug.
- PERFETTO_CHECK(false);
- } // if (arg ~= "--*").
-
- if (strlen(arg) > 1 && arg[0] == '-' && arg[1] != '-') {
- // A sequence of short options. Parsing logic continues below.
- nextchar = &arg[1];
- }
- } // if(!nextchar)
-
- if (nextchar) {
- // At this point either:
- // 1. This is the first char of a sequence of short options, and we fell
- // through here from the lines above.
- // 2. This is the N (>1) char of a sequence of short options, and we got
- // here from a new getopt() call to getopt().
- const char cur_char = *nextchar;
- PERFETTO_CHECK(cur_char != '\0');
-
- // Advance the option char in any case, before we start reasoning on them.
- // if we got to the end of the "-abc" sequence, increment optind so the next
- // getopt() call resumes from the next argv argument.
- if (*(++nextchar) == '\0') {
- nextchar = nullptr;
- ++optind;
- }
-
- const option* opt = LookupShortOpt(opts, cur_char);
- optopt = cur_char;
- if (!opt) {
- if (opterr)
- fprintf(stderr, "invalid option -- '%c'\n", cur_char);
- return '?';
- }
- if (opt->has_arg == no_argument) {
- return cur_char;
- } else if (opt->has_arg == required_argument) {
- // This is a subtle getopt behavior. Say you call `tar -fx`, there are
- // two cases:
- // 1. If 'f' is no_argument then 'x' (and anything else after) is
- // interpreted as an independent argument (like `tar -f -x`).
- // 2. If 'f' is required_argument, than everything else after the 'f'
- // is interpreted as the option argument (like `tar -f x`)
- if (!nextchar) {
- // Case 1.
- if (optind >= argc) {
- if (opterr)
- fprintf(stderr, "option requires an argument -- '%c'\n", cur_char);
- return '?';
- } else {
- optarg = argv[optind++];
- return cur_char;
- }
- } else {
- // Case 2.
- optarg = nextchar;
- nextchar = nullptr;
- optind++;
- return cur_char;
- }
- }
- PERFETTO_CHECK(false);
- } // if (nextchar)
-
- // If we get here, we found the first non-option argument. Stop here.
-
- if (strcmp(arg, "--") == 0)
- optind++;
-
- return -1;
+template <typename H, typename T>
+H PerfettoHashValue(H h, const std::shared_ptr<T>& ptr) {
+ return H::Combine(std::move(h), ptr.get());
}
-int getopt(int argc, char** argv, const char* shortopts) {
- return getopt_long(argc, argv, shortopts, nullptr, nullptr);
-}
+// This is for using already-hashed key into std::unordered_map and avoid the
+// cost of re-hashing. Example:
+// unordered_map<uint64_t, Value, AlreadyHashed> my_map.
+template <typename T>
+struct AlreadyHashed {
+ size_t operator()(const T& x) const { return static_cast<size_t>(x); }
+};
-} // namespace getopt_compat
-} // namespace base
-} // namespace perfetto
-// gen_amalgamated begin source: src/base/intrusive_list.cc
-// gen_amalgamated begin header: include/perfetto/ext/base/intrusive_list.h
+} // namespace perfetto::base
+
+#endif // INCLUDE_PERFETTO_EXT_BASE_HASH_H_
/*
- * Copyright (C) 2025 The Android Open Source Project
+ * 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.
@@ -4955,209 +5198,340 @@ int getopt(int argc, char** argv, const char* shortopts) {
* limitations under the License.
*/
-#ifndef INCLUDE_PERFETTO_EXT_BASE_INTRUSIVE_LIST_H_
-#define INCLUDE_PERFETTO_EXT_BASE_INTRUSIVE_LIST_H_
+#ifndef INCLUDE_PERFETTO_EXT_BASE_MURMUR_HASH_H_
+#define INCLUDE_PERFETTO_EXT_BASE_MURMUR_HASH_H_
#include <cstddef>
#include <cstdint>
+#include <cstring>
+#include <limits>
+#include <string>
+#include <string_view>
+#include <type_traits>
+#include <utility>
-// gen_amalgamated expanded: #include "perfetto/base/logging.h"
+// gen_amalgamated expanded: #include "perfetto/ext/base/hash.h"
+// gen_amalgamated expanded: #include "perfetto/ext/base/string_view.h"
+// gen_amalgamated expanded: #include "perfetto/ext/base/utils.h"
+// gen_amalgamated expanded: #include "perfetto/public/compiler.h"
-// An intrusive (doubly linked) list implementation.
-// Unlike std::list<>, the entries being inserted into the list need to
-// explicitly declare an IntrusiveListNode structure (one for each list they are
-// part of). The user must specify a Traits struct for each list the entry is
-// part of. The traits struct defines how to get to the IntrusiveListNode from
-// the outer object.
-//
-// Usage example:
-// class Person {
-// public:
-// struct ListTraits {
-// static constexpr size_t node_offset() { return offsetof(Person, node); }
-// };
-// std::string name;
-// IntrusiveListNode node{};
-// }
+// This file provides an implementation of the 64-bit MurmurHash2 algorithm,
+// also known as MurmurHash64A. This algorithm, created by Austin Appleby, is a
+// fast, non-cryptographic hash function with excellent distribution properties,
+// making it ideal for use in hash tables.
//
-// IntrusiveList<Person, Person::ListTraits> list;
-// Person person;
-// list.PushBack(person);
-// ...
+// The file also includes related hashing utilities:
+// - A standalone `fmix64` finalizer from MurmurHash3, used for hashing
+// individual numeric types.
+// - A hash combiner for creating a single hash from a sequence of values.
+//
+// NOTE: This implementation is NOT cryptographically secure. It must not be
+// used for security-sensitive applications like password storage or digital
+// signatures, as it is not designed to be resistant to malicious attacks.
namespace perfetto::base {
-namespace internal {
-
-struct ListNode {
- ListNode* prev;
- ListNode* next;
-};
-
-// IntrusiveList's Base class to factor out type-independent code (avoid binary
-// bloat)
-class ListOps {
- public:
- void PushFront(ListNode* node);
- void PopFront();
- void Erase(ListNode* node);
-
- ListNode* front_{nullptr};
- size_t size_{0};
-};
-
-} // namespace internal
-
-using IntrusiveListNode = internal::ListNode;
-
-// T is the class that has one or more IntrusiveListNode as fields.
-// Traits defines getter and offset between node and T.
-// Traits is separate to allow the same T to be part of different lists (which
-// necessitate a different Traits, at very least for the offset).
-template <typename T, typename ListTraits>
-class IntrusiveList : private internal::ListOps {
- public:
- class Iterator {
- public:
- Iterator() = default;
- explicit Iterator(IntrusiveListNode* node) : node_(node) {}
- ~Iterator() = default;
- Iterator(const Iterator&) = default;
- Iterator& operator=(const Iterator&) = default;
- Iterator(Iterator&&) noexcept = default;
- Iterator& operator=(Iterator&&) noexcept = default;
+namespace murmur_internal {
- bool operator==(const Iterator& other) const {
- return node_ == other.node_;
- }
- bool operator!=(const Iterator& other) const { return !(*this == other); }
- T* operator->() { return const_cast<T*>(entryof(node_)); }
- T& operator*() {
- PERFETTO_DCHECK(node_);
- return *operator->();
- }
- explicit operator bool() const { return node_ != nullptr; }
+// Finalizes an intermediate hash value using the `fmix64` routine from
+// MurmurHash3.
+//
+// This function's purpose is to thoroughly mix the bits of the hash state to
+// ensure the final result is well-distributed, which is critical for avoiding
+// collisions in hash tables.
+//
+// Args:
+// h: The intermediate hash value to be finalized.
+//
+// Returns:
+// The final, well-mixed 64-bit hash value.
+inline uint64_t MurmurHashMix(uint64_t h) {
+ h ^= h >> 33;
+ h *= 0xff51afd7ed558ccdULL;
+ h ^= h >> 33;
+ h *= 0xc4ceb9fe1a85ec53ULL;
+ h ^= h >> 33;
+ return h;
+}
- Iterator& operator++() {
- PERFETTO_DCHECK(node_);
- node_ = node_->next;
- return *this;
- }
+// Computes a 64-bit hash for a block of memory using the MurmurHash64A
+// algorithm.
+//
+// The process involves four main steps:
+// 1. Initialization: The hash state is seeded with a value derived from the
+// input length.
+// 2. Main Loop: Data is processed in 8-byte chunks, with each chunk being
+// mixed into the hash state.
+// 3. Tail Processing: The final 1-7 bytes of data are handled.
+// 4. Finalization: The hash state is passed through a final mixing sequence to
+// ensure good bit distribution.
+//
+// Args:
+// input: A pointer to the data to be hashed.
+// len: The length of the data in bytes.
+//
+// Returns:
+// The 64-bit MurmurHash64A hash of the input data.
+inline uint64_t MurmurHashBytes(const void* input, size_t len) {
+ // This implementation follows the canonical MurmurHash64A algorithm.
+ // The constants `kMulConstant` (m) and the shift value `47` (r) are from
+ // the original specification.
+ // The seed is inspired by the one used in DuckDB.
+ static constexpr uint64_t kSeed = 0xe17a1465U;
+ static constexpr uint64_t kMulConstant = 0xc6a4a7935bd1e995;
+ static constexpr int kShift = 47;
- private:
- IntrusiveListNode* node_{nullptr};
- };
+ uint64_t h = kSeed ^ (len * kMulConstant);
+ const auto* data = static_cast<const uint8_t*>(input);
+ const size_t num_blocks = len / 8;
- using value_type = T;
- using const_pointer = const T*;
+ // Process 8-byte (64-bit) chunks
+ for (size_t i = 0; i < num_blocks; ++i) {
+ uint64_t k;
+ memcpy(&k, data, sizeof(k));
+ data += sizeof(k); // Advance the pointer by 8 bytes
- void PushFront(T& entry) { internal::ListOps::PushFront(nodeof(&entry)); }
+ k *= kMulConstant;
+ k ^= k >> kShift;
+ k *= kMulConstant;
- void PopFront() { internal::ListOps::PopFront(); }
+ h ^= k;
+ h *= kMulConstant;
+ }
- T& front() {
- PERFETTO_DCHECK(front_);
- return const_cast<T&>(*entryof(front_));
+ // Process the remaining 1 to 7 bytes
+ // The 'byte_ptr' now points to the beginning of the tail.
+ switch (len & 7) {
+ case 7:
+ h ^= static_cast<uint64_t>(data[6]) << 48;
+ [[fallthrough]];
+ case 6:
+ h ^= static_cast<uint64_t>(data[5]) << 40;
+ [[fallthrough]];
+ case 5:
+ h ^= static_cast<uint64_t>(data[4]) << 32;
+ [[fallthrough]];
+ case 4:
+ h ^= static_cast<uint64_t>(data[3]) << 24;
+ [[fallthrough]];
+ case 3:
+ h ^= static_cast<uint64_t>(data[2]) << 16;
+ [[fallthrough]];
+ case 2:
+ h ^= static_cast<uint64_t>(data[1]) << 8;
+ [[fallthrough]];
+ case 1:
+ h ^= static_cast<uint64_t>(data[0]);
+ h *= kMulConstant;
}
- void Erase(T& entry) { internal::ListOps::Erase(nodeof(&entry)); }
+ // Final mixing stage
+ h ^= h >> kShift;
+ h *= kMulConstant;
+ h ^= h >> kShift;
- bool empty() const { return size_ == 0; }
+ return h;
+}
- size_t size() const { return size_; }
+// Computes a 64-bit hash for a single built-in value without any combination.
+// This is the core primitive used by both MurmurHashValue and
+// MurmurHashCombiner::CombineOne for built-in types.
+//
+// NOTE: This function intentionally has no else branch for non-builtin types,
+// which will cause a compile error if called with an unsupported type. Callers
+// should check if the type is supported before calling this function.
+template <typename T>
+auto MurmurHashBuiltinValue(const T& value) {
+ if constexpr (std::is_enum_v<T>) {
+ return murmur_internal::MurmurHashMix(
+ static_cast<uint64_t>(static_cast<std::underlying_type_t<T>>(value)));
+ } else if constexpr (std::is_integral_v<T>) {
+ return murmur_internal::MurmurHashMix(static_cast<uint64_t>(value));
+ } else if constexpr (std::is_same_v<T, double>) {
+ return murmur_internal::MurmurHashMix(base::CanonicalFloatBits(value));
+ } else if constexpr (std::is_same_v<T, float>) {
+ return murmur_internal::MurmurHashMix(base::CanonicalFloatBits(value));
+ } else if constexpr (std::is_same_v<T, std::string> ||
+ std::is_same_v<T, std::string_view> ||
+ std::is_same_v<T, base::StringView>) {
+ return murmur_internal::MurmurHashBytes(value.data(), value.size());
+ } else if constexpr (std::is_same_v<T, const char*>) {
+ std::string_view view(value);
+ return murmur_internal::MurmurHashBytes(view.data(), view.size());
+ } else if constexpr (std::is_pointer_v<T>) {
+ return murmur_internal::MurmurHashMix(
+ static_cast<uint64_t>(reinterpret_cast<uintptr_t>(value)));
+ } else {
+ struct InvalidBuiltin {};
+ return InvalidBuiltin{};
+ }
+}
- Iterator begin() { return Iterator{front_}; }
+// Helper to check if a type has a built-in MurmurHash implementation.
+template <typename T>
+constexpr bool HasMurmurHashBuiltinValue() {
+ return std::is_same_v<decltype(MurmurHashBuiltinValue(std::declval<T>())),
+ uint64_t>;
+}
- Iterator end() { return Iterator{nullptr}; }
+// Helper to check if a type is string-like (i.e. string, c-string or string
+// views).
+template <typename T>
+constexpr bool IsStringLike() {
+ return std::is_same_v<T, std::string> ||
+ std::is_same_v<T, std::string_view> ||
+ std::is_same_v<T, base::StringView> || std::is_same_v<T, const char*>;
+}
- private:
- static constexpr size_t kNodeOffset = ListTraits::node_offset();
+// Helper to check if heterogeneous lookup is allowed between T and U: only
+// between string-like types. Other types (e.g. integers) are converted to T by
+// the caller instead, as converting them is cheap, and hashing them as is
+// could differ (e.g. a negative int hashed for a uint32_t key).
+template <typename T, typename U>
+constexpr bool AllowsHeterogeneousLookup() {
+ return IsStringLike<T>() && IsStringLike<U>();
+}
- static constexpr IntrusiveListNode* nodeof(T* entry) {
- return reinterpret_cast<IntrusiveListNode*>(
- reinterpret_cast<uintptr_t>(entry) + kNodeOffset);
- }
+// MurmurHash<T> is transparent (i.e. supports heterogeneous lookups) only for
+// string-like T.
+template <typename T, bool = IsStringLike<T>()>
+struct MurmurHashTransparency {};
- static constexpr const T* entryof(IntrusiveListNode* node) {
- return reinterpret_cast<T*>(reinterpret_cast<uintptr_t>(node) -
- kNodeOffset);
- }
+template <typename T>
+struct MurmurHashTransparency<T, true> {
+ using is_transparent = void;
};
-} // namespace perfetto::base
-
-#endif // INCLUDE_PERFETTO_EXT_BASE_INTRUSIVE_LIST_H_
-/*
- * Copyright (C) 2025 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.
- */
-
-// gen_amalgamated expanded: #include "perfetto/ext/base/intrusive_list.h"
+// Helper to detect pointers in Combine(...).
+// Hashing pointers directly is prohibited as it often indicates a misuse
+// (e.g., passing ptr and len instead of a single std::string_view).
+template <typename... Args>
+constexpr bool HasPointerV = (std::is_pointer_v<Args> || ...);
-// gen_amalgamated expanded: #include "perfetto/base/logging.h"
+} // namespace murmur_internal
-namespace perfetto::base::internal {
+// ============================================================================
+// MurmurHashCombiner - the core hasher state object
+// ============================================================================
+//
+// A helper class to create a 64-bit MurmurHash from a series of
+// structured fields.
+//
+// This class supports both the absl-style hasher API and a direct
+// member Combine() method.
+//
+// Absl-style API (for custom types with PerfettoHashValue):
+// template <typename H>
+// friend H PerfettoHashValue(H h, const MyType& value) {
+// return H::Combine(std::move(h), value.field1, value.field2);
+// }
+//
+// Direct API (for simple hash combining):
+// MurmurHashCombiner combiner;
+// combiner.Combine(field1, field2, ...);
+// return combiner.digest();
+//
+// IMPORTANT: This is NOT a true streaming hash. It is an order-dependent
+// combiner. It does not guarantee that hashing two concatenated chunks of data
+// will produce the same result as hashing them separately in sequence.
+class MurmurHashCombiner {
+ public:
+ MurmurHashCombiner() = default;
-void ListOps::PushFront(IntrusiveListNode* node) {
- node->prev = nullptr;
- node->next = front_;
+ // Static Combine - returns a new hasher with the combined state.
+ // This is used by the absl-style PerfettoHashValue API.
+ template <typename... Args>
+ static MurmurHashCombiner Combine(MurmurHashCombiner h, const Args&... args) {
+ h.Combine(args...);
+ return h;
+ }
- if (front_) {
- front_->prev = node;
+ // Member Combine - combines values into this hasher's state.
+ // This is a convenient API for directly combining multiple values.
+ // The combination is order-dependent.
+ template <typename... Args>
+ void Combine(const Args&... args) {
+ static_assert(!murmur_internal::HasPointerV<Args...>,
+ "MurmurHashCombiner::Combine() does not support pointers. "
+ "If you want to hash the contents of a memory range, use a "
+ "single hashable object (e.g., std::string_view). If you "
+ "want to hash a pointer address, cast it to uintptr_t.");
+ // Uses a C++17 fold expression with CombineOne for each argument.
+ (CombineOne(args), ...);
}
- front_ = node;
- ++size_;
-}
+ // Returns the digest (i.e. current state of the combiner).
+ uint64_t digest() const { return hash_; }
-void ListOps::PopFront() {
- PERFETTO_DCHECK(front_);
- front_ = front_->next;
+ private:
+ // Combines a single value into the hasher state.
+ template <typename T>
+ void CombineOne(const T& value) {
+ if constexpr (murmur_internal::HasMurmurHashBuiltinValue<T>()) {
+ Update(murmur_internal::MurmurHashBuiltinValue(value));
+ } else {
+ // For custom types, use ADL to find the PerfettoHashValue function.
+ // This will cause a compile error with a clear message if the function
+ // is not defined.
+ hash_ = PerfettoHashValue(std::move(*this), value).digest();
+ }
+ }
- if (front_) {
- front_->prev = nullptr;
+ // Low-level update with a pre-computed hash value. This uses a fast,
+ // order-dependent combination step inspired by the `hash_combine` function
+ // in the Boost C++ libraries.
+ void Update(uint64_t piece_hash) {
+ hash_ ^= piece_hash + 0x9e3779b9 + (hash_ << 6) + (hash_ >> 2);
}
- PERFETTO_DCHECK(size_ > 0);
- --size_;
-}
+ static constexpr uint64_t kSeed = 0xe17a1465U;
+ uint64_t hash_ = kSeed;
+};
-void ListOps::Erase(IntrusiveListNode* node) {
- auto* prev = node->prev;
- auto* next = node->next;
+// Simple wrapper function around MurmurHashCombiner to improve clarity in
+// callsites to not have to instantiate the class, call Combine() then digest().
+template <typename... Args>
+uint64_t MurmurHashCombine(const Args&... value) {
+ return MurmurHashCombiner::Combine(MurmurHashCombiner{}, value...).digest();
+}
- if (node == front_) {
- front_ = next;
+// Simple wrapper function to compute a hash value for a single value.
+// This is the primitive hash operation that MurmurHash<T> delegates to.
+//
+// For built-in types (integers, floats, strings), this uses a fast path that
+// avoids the overhead of the MurmurHashCombiner. For custom types, it delegates
+// to MurmurHashCombiner which will use ADL to find the PerfettoHashValue.
+template <typename T>
+uint64_t MurmurHashValue(const T& value) {
+ if constexpr (murmur_internal::HasMurmurHashBuiltinValue<T>()) {
+ return murmur_internal::MurmurHashBuiltinValue(value);
+ } else {
+ return MurmurHashCombine(value);
}
+}
- if (prev) {
- prev->next = next;
- }
+// std::hash<T> drop-in class which uses MurmurHashValue as the primitive.
+// All specializations consistently delegate to MurmurHashValue.
+template <typename T>
+struct MurmurHash : murmur_internal::MurmurHashTransparency<T> {
+ uint64_t operator()(const T& value) const { return MurmurHashValue(value); }
- if (next) {
- next->prev = prev;
+ // Heterogeneous lookup support, between string-like types only.
+ template <typename U>
+ auto operator()(const U& value) const -> std::enable_if_t<
+ murmur_internal::AllowsHeterogeneousLookup<T, std::decay_t<const U>>(),
+ uint64_t> {
+ // Forwarding callers retain string literals as arrays. Hash them as
+ // C strings instead of converting them to an owning std::string.
+ return MurmurHashValue<std::decay_t<const U>>(value);
}
+};
- PERFETTO_DCHECK(size_ > 0);
- --size_;
-}
+} // namespace perfetto::base
-} // namespace perfetto::base::internal
-// gen_amalgamated begin source: src/base/intrusive_tree.cc
-// gen_amalgamated begin header: include/perfetto/ext/base/intrusive_tree.h
+#endif // INCLUDE_PERFETTO_EXT_BASE_MURMUR_HASH_H_
/*
- * Copyright (C) 2025 The Android Open Source Project
+ * Copyright (C) 2021 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.
@@ -5172,239 +5546,456 @@ void ListOps::Erase(IntrusiveListNode* node) {
* limitations under the License.
*/
-#ifndef INCLUDE_PERFETTO_EXT_BASE_INTRUSIVE_TREE_H_
-#define INCLUDE_PERFETTO_EXT_BASE_INTRUSIVE_TREE_H_
-
-#include <cstddef>
-#include <cstdint>
-#include <functional>
+#ifndef INCLUDE_PERFETTO_EXT_BASE_FLAT_HASH_MAP_V1_H_
+#define INCLUDE_PERFETTO_EXT_BASE_FLAT_HASH_MAP_V1_H_
// gen_amalgamated expanded: #include "perfetto/base/logging.h"
+// gen_amalgamated expanded: #include "perfetto/ext/base/murmur_hash.h"
+// gen_amalgamated expanded: #include "perfetto/ext/base/utils.h"
+// gen_amalgamated expanded: #include "perfetto/public/compiler.h"
-// An intrusive tree implementation, inspired from BSD kernel's tree.h
-// Unlike std::set<>, the nodes being inserted into the tree need to explicitly
-// declare a RBNode structure (one for each tree they are part of).
-// The user must specify a TreeTraits for each tree the struct is part of.
-// The traits struct defines the type of the key and how to get to the node
-// entry from the outer object.
-// Usage example:
-// class Person {
-// public:
-// struct Traits {
-// using KeyType = std::string;
-// static const KeyType& GetKey(const Person& p) { return p->unique_id; }
-// static constexpr size_t NodeOffset() { return offsetof(Person, node); }
-// };
-// std::string unique_id;
-// std::string name;
-// std::string surname;
-// IntrusiveTreeNode node{};
-// }
-// IntrusiveTree<Person, Person::Traits> tree;
-// tree.insert(&person1);
-// ...
+#include <algorithm>
+#include <cstddef>
+#include <cstdint>
+#include <cstring>
+#include <limits>
+#include <memory>
+#include <type_traits>
+#include <utility>
namespace perfetto::base {
-namespace internal {
+// An open-addressing hashmap implementation.
+// Pointers are not stable, neither for keys nor values.
+// Has similar performances of a RobinHood hash (without the complications)
+// and 2x an unordered map.
+// Doc: http://go/perfetto-hashtables .
+//
+// When used to implement a string pool in TraceProcessor, the performance
+// characteristics obtained by replaying the set of strings seeen in a 4GB trace
+// (226M strings, 1M unique) are the following (see flat_hash_map_benchmark.cc):
+// This(Linear+AppendOnly) 879,383,676 ns 258.013M insertions/s
+// This(LinearProbe): 909,206,047 ns 249.546M insertions/s
+// This(QuadraticProbe): 1,083,844,388 ns 209.363M insertions/s
+// std::unordered_map: 6,203,351,870 ns 36.5811M insertions/s
+// tsl::robin_map: 931,403,397 ns 243.622M insertions/s
+// absl::flat_hash_map: 998,013,459 ns 227.379M insertions/s
+// FollyF14FastMap: 1,181,480,602 ns 192.074M insertions/s
+//
+// The structs below define the probing algorithm used to probe slots upon a
+// collision. They are guaranteed to visit all slots as our table size is always
+// a power of two (see https://en.wikipedia.org/wiki/Quadratic_probing).
-enum RBColor : uint8_t {
- BLACK = 0,
- RED = 1,
+// Linear probing can be faster if the hashing is well distributed and the load
+// is not high. For TraceProcessor's StringPool this is the fastest. It can
+// degenerate badly if the hashing doesn't spread (e.g., if using directly pids
+// as keys, with a no-op hashing function).
+struct LinearProbe {
+ static inline size_t Calc(size_t key_hash, size_t step, size_t capacity) {
+ return (key_hash + step) & (capacity - 1); // Linear probe
+ }
};
-struct RBNode {
- RBNode* left = nullptr;
- RBNode* right = nullptr;
- RBNode* parent = nullptr;
- RBColor color = RBColor::BLACK;
+// Generates the sequence: 0, 3, 10, 21, 36, 55, ...
+// Can be a bit (~5%) slower than LinearProbe because it's less cache hot, but
+// avoids degenerating badly if the hash function is bad and causes clusters.
+// A good default choice unless benchmarks prove otherwise.
+struct QuadraticProbe {
+ static inline size_t Calc(size_t key_hash, size_t step, size_t capacity) {
+ return (key_hash + 2 * step * step + step) & (capacity - 1);
+ }
};
-void RBInsertColor(RBNode** root, RBNode* elm);
-void RBRemove(RBNode** root, RBNode* elm);
+// Tends to perform in the middle between linear and quadratic.
+// It's a bit more cache-effective than the QuadraticProbe but can create more
+// clustering if the hash function doesn't spread well.
+// Generates the sequence: 0, 1, 3, 6, 10, 15, 21, ...
+struct QuadraticHalfProbe {
+ static inline size_t Calc(size_t key_hash, size_t step, size_t capacity) {
+ return (key_hash + (step * step + step) / 2) & (capacity - 1);
+ }
+};
-// Returns nullptr after reaching the last leaf (the max element).
-const RBNode* RBNext(const RBNode* node);
+// Non-templated base class to hold helpers for FlatHashMap.
+struct FlatHashMapV1Base {
+ public:
+ // Helper to detect if a hasher has is_transparent defined.
+ template <typename, typename = void>
+ struct HasIsTransparent : std::false_type {};
-// KeyCompare tries first to use the CompareKey function in Traits, if present.
-// The signature of that function is int(const KeyType&, const KeyType&).
-// If the comparator function doesn't exist, falls backk on std::less<KeyType>.
-template <
- class Traits,
- class = std::enable_if_t<std::is_function_v<typename Traits::CompareKey>,
- void> >
-int KeyCompare(const typename Traits::KeyType& k1,
- const typename Traits::KeyType& k2) {
- return Traits::CompareKey(k1, k2);
-}
-
-// SFINAE fallback on std::less<KeyType>
-template <class Traits>
-int KeyCompare(const typename Traits::KeyType& k1,
- const typename Traits::KeyType& k2) {
- std::less<typename Traits::KeyType> less_cmp;
- return less_cmp(k1, k2) ? -1 : (less_cmp(k2, k1) ? 1 : 0);
-}
-
-} // namespace internal
+ template <typename H>
+ struct HasIsTransparent<H, std::void_t<typename H::is_transparent>>
+ : std::true_type {};
-using IntrusiveTreeNode = internal::RBNode;
+ // Helper to check if a lookup key type K is allowed.
+ // Returns true if:
+ // 1. K can be implicitly converted to Key, OR
+ // 2. Hasher has is_transparent AND Hasher is invocable with K AND Key and K
+ // are equality comparable
+ template <typename K, typename Key, typename Hasher>
+ static constexpr bool IsLookupKeyAllowed() {
+ if constexpr (HasIsTransparent<Hasher>::value) {
+ return std::is_invocable_v<Hasher, const K&> &&
+ std::is_same_v<decltype(std::declval<const Key&>() ==
+ std::declval<const K&>()),
+ bool>;
+ } else if constexpr (std::is_convertible_v<K, Key>) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+};
-// T is the class that has one or more IntrusiveTreeNode as fiels.
-// Traits defines the key type, getter and offset between node and T.
-// Traits is separate to allow the same T to be part of different trees (which
-// necessitate a different Traits, at very least for the offset).
-template <typename T, typename Traits>
-class IntrusiveTree {
+template <typename Key,
+ typename Value,
+ typename Hasher = base::MurmurHash<Key>,
+ typename Probe = QuadraticProbe,
+ bool AppendOnly = false>
+class FlatHashMapV1 : protected FlatHashMapV1Base {
public:
- using Key = typename Traits::KeyType;
-
class Iterator {
public:
- Iterator() = default;
- explicit Iterator(const internal::RBNode* node) : node_(node) {}
+ explicit Iterator(const FlatHashMapV1* map) : map_(map) {
+ FindNextNonFree();
+ }
~Iterator() = default;
Iterator(const Iterator&) = default;
Iterator& operator=(const Iterator&) = default;
Iterator(Iterator&&) noexcept = default;
Iterator& operator=(Iterator&&) noexcept = default;
- bool operator==(const Iterator& o) const { return node_ == o.node_; }
- bool operator!=(const Iterator& o) const { return !(*this == o); }
- const T* operator->() const { return entryof(node_); }
- const T& operator*() const {
- PERFETTO_DCHECK(node_ != nullptr);
- return *operator->();
- }
- T* operator->() { return const_cast<T*>(entryof(node_)); }
- T& operator*() {
- PERFETTO_DCHECK(node_ != nullptr);
- return *operator->();
- }
- explicit operator bool() const { return node_ != nullptr; }
+ Key& key() { return map_->keys_[idx_]; }
+ Value& value() { return map_->values_[idx_]; }
+ const Key& key() const { return map_->keys_[idx_]; }
+ const Value& value() const { return map_->values_[idx_]; }
+ explicit operator bool() const { return idx_ != kEnd; }
Iterator& operator++() {
- node_ = internal::RBNext(node_);
+ PERFETTO_DCHECK(idx_ < map_->capacity_);
+ ++idx_;
+ FindNextNonFree();
return *this;
}
private:
- const internal::RBNode* node_ = nullptr;
+ static constexpr size_t kEnd = std::numeric_limits<size_t>::max();
+
+ void FindNextNonFree() {
+ const auto& tags = map_->tags_;
+ for (; idx_ < map_->capacity_; idx_++) {
+ if (tags[idx_] != kFreeSlot && (AppendOnly || tags[idx_] != kTombstone))
+ return;
+ }
+ idx_ = kEnd;
+ }
+
+ const FlatHashMapV1* map_ = nullptr;
+ size_t idx_ = 0;
}; // Iterator
+ static constexpr int kDefaultLoadLimitPct = 75;
+ explicit FlatHashMapV1(size_t initial_capacity = 0,
+ int load_limit_pct = kDefaultLoadLimitPct)
+ : load_limit_percent_(load_limit_pct) {
+ if (initial_capacity > 0)
+ Reset(initial_capacity, true);
+ }
- using value_type = T;
- using const_pointer = const T*;
- using const_iterator = Iterator;
+ // We are calling Clear() so that the destructors for the inserted entries are
+ // called (unless they are trivial, in which case it will be a no-op).
+ ~FlatHashMapV1() { Clear(); }
- std::pair<Iterator, bool> Insert(T& entry) {
- // The insertion preamble is inlined because it's few instructions and
- // out-lining it would require std::function indirections for getting the
- // key and the comparator.
- int comp = 0;
- internal::RBNode* tmp = root_;
- internal::RBNode* parent = nullptr;
- internal::RBNode* const entry_node = nodeof(&entry);
- while (tmp) {
- parent = tmp;
- comp = key_compare(entry_node, parent);
- if (comp < 0) {
- tmp = tmp->left;
- } else if (comp > 0) {
- tmp = tmp->right;
- } else {
- return {Iterator(tmp), false}; // The key exists already.
+ FlatHashMapV1(FlatHashMapV1&& other) noexcept {
+ tags_ = std::move(other.tags_);
+ keys_ = std::move(other.keys_);
+ values_ = std::move(other.values_);
+ capacity_ = other.capacity_;
+ size_ = other.size_;
+ tombstones_ = other.tombstones_;
+ max_probe_length_ = other.max_probe_length_;
+ load_limit_ = other.load_limit_;
+ load_limit_percent_ = other.load_limit_percent_;
+
+ new (&other) FlatHashMapV1();
+ }
+
+ FlatHashMapV1& operator=(FlatHashMapV1&& other) noexcept {
+ this->~FlatHashMapV1();
+ new (this) FlatHashMapV1(std::move(other));
+ return *this;
+ }
+
+ FlatHashMapV1(const FlatHashMapV1&) = delete;
+ FlatHashMapV1& operator=(const FlatHashMapV1&) = delete;
+
+ std::pair<Value*, bool> Insert(Key key, Value value) {
+ const size_t key_hash = Hasher{}(key);
+ const uint8_t tag = HashToTag(key_hash);
+ static constexpr size_t kSlotNotFound = std::numeric_limits<size_t>::max();
+
+ // This for loop does in reality at most two attempts:
+ // The first iteration either:
+ // - Early-returns, because the key exists already,
+ // - Finds an insertion slot and proceeds because the load is < limit.
+ // The second iteration is only hit in the unlikely case of this insertion
+ // bringing the table beyond the target |load_limit_| (or the edge case
+ // of the HT being full, if |load_limit_pct_| = 100).
+ // We cannot simply pre-grow the table before insertion, because we must
+ // guarantee that calling Insert() with a key that already exists doesn't
+ // invalidate iterators.
+ size_t insertion_slot;
+ size_t probe_len;
+ for (;;) {
+ PERFETTO_DCHECK((capacity_ & (capacity_ - 1)) == 0); // Must be a pow2.
+ insertion_slot = kSlotNotFound;
+ // Start the iteration at the desired slot (key_hash % capacity_)
+ // searching either for a free slot or a tombstone. In the worst case we
+ // might end up scanning the whole array of slots. The Probe functions are
+ // guaranteed to visit all the slots within |capacity_| steps. If we find
+ // a free slot, we can stop the search immediately (a free slot acts as an
+ // "end of chain for entries having the same hash". If we find a
+ // tombstones (a deleted slot) we remember its position, but have to keep
+ // searching until a free slot to make sure we don't insert a duplicate
+ // key.
+ for (probe_len = 0; probe_len < capacity_;) {
+ const size_t idx = Probe::Calc(key_hash, probe_len, capacity_);
+ PERFETTO_DCHECK(idx < capacity_);
+ const uint8_t tag_idx = tags_[idx];
+ ++probe_len;
+ if (tag_idx == kFreeSlot) {
+ // Rationale for "insertion_slot == kSlotNotFound": if we encountered
+ // a tombstone while iterating we should reuse that rather than
+ // taking another slot.
+ if (AppendOnly || insertion_slot == kSlotNotFound)
+ insertion_slot = idx;
+ break;
+ }
+ // We should never encounter tombstones in AppendOnly mode.
+ PERFETTO_DCHECK(!(tag_idx == kTombstone && AppendOnly));
+ if (!AppendOnly && tag_idx == kTombstone) {
+ insertion_slot = idx;
+ continue;
+ }
+ if (tag_idx == tag && keys_[idx] == key) {
+ // The key is already in the map.
+ return std::make_pair(&values_[idx], false);
+ }
+ } // for (idx)
+
+ // If we got to this point the key does not exist (otherwise we would have
+ // hit the return above) and we are going to insert a new entry.
+ // Before doing so, ensure we stay under the target load limit.
+ if (PERFETTO_UNLIKELY(size_ >= load_limit_)) {
+ MaybeGrowAndRehash(/*grow=*/true);
+ continue;
}
- } // while(tmp)
- entry_node->left = entry_node->right = nullptr;
- entry_node->parent = parent;
- entry_node->color = internal::RBColor::RED;
- if (parent) {
- if (comp < 0) {
- PERFETTO_DCHECK(parent->left == nullptr);
- parent->left = entry_node;
- } else {
- PERFETTO_DCHECK(parent->right == nullptr);
- parent->right = entry_node;
+ // If there are too many tombstones, it's worth doing a rehash to
+ // clean them up. This is to avoid the case where we have a table full
+ // of tombstones which would cause lookups to be very slow.
+ bool is_many_tombstones = tombstones_ > size_ && size_ > 128;
+ bool is_tombstones_plus_size_too_high = tombstones_ + size_ > load_limit_;
+ if (PERFETTO_UNLIKELY(is_many_tombstones ||
+ is_tombstones_plus_size_too_high)) {
+ MaybeGrowAndRehash(/*grow=*/false);
+ continue;
}
- } else {
- root_ = entry_node;
+ PERFETTO_DCHECK(insertion_slot != kSlotNotFound);
+ break;
+ } // for (attempt)
+
+ PERFETTO_CHECK(insertion_slot < capacity_);
+
+ // We found a free slot (or a tombstone). Proceed with the insertion.
+ if (tags_[insertion_slot] == kTombstone) {
+ PERFETTO_DCHECK(tombstones_ > 0);
+ tombstones_--;
}
- internal::RBInsertColor(&root_, entry_node);
- ++size_;
- return {Iterator(entry_node), true};
+ Value* value_idx = &values_[insertion_slot];
+ new (&keys_[insertion_slot]) Key(std::move(key));
+ new (value_idx) Value(std::move(value));
+ tags_[insertion_slot] = tag;
+ PERFETTO_DCHECK(probe_len > 0 && probe_len <= capacity_);
+ max_probe_length_ = std::max(max_probe_length_, probe_len);
+ size_++;
+
+ return std::make_pair(value_idx, true);
}
- Iterator Find(const Key& key) const {
- internal::RBNode* tmp = root_;
- while (tmp) {
- int comp =
- internal::KeyCompare<Traits>(key, Traits::GetKey(*entryof(tmp)));
- if (comp < 0) {
- tmp = tmp->left;
- } else if (comp > 0) {
- tmp = tmp->right;
- } else {
- return Iterator(tmp);
- }
- }
- return Iterator(nullptr);
+ template <typename K = Key>
+ Value* Find(const K& key) const {
+ const size_t idx = FindInternal(key);
+ if (idx == kNotFound)
+ return nullptr;
+ return &values_[idx];
}
- bool Remove(const Key& key) {
- Iterator it = Find(key);
- if (!it)
+ template <typename K = Key>
+ bool Erase(const K& key) {
+ if (AppendOnly)
+ PERFETTO_FATAL("Erase() not supported because AppendOnly=true");
+ size_t idx = FindInternal(key);
+ if (idx == kNotFound)
return false;
- internal::RBRemove(&root_, nodeof(std::addressof(*it)));
- --size_;
+ EraseInternal(idx);
return true;
}
- Iterator Remove(T& entry) { return Remove(Iterator(nodeof(&entry))); }
+ void Clear() {
+ // Avoid trivial heap operations on zero-capacity std::move()-d objects.
+ if (PERFETTO_UNLIKELY(capacity_ == 0))
+ return;
- Iterator Remove(Iterator it) {
- Iterator next = it;
- ++next;
- internal::RBRemove(&root_, nodeof(std::addressof(*it)));
- --size_;
- return next;
+ for (size_t i = 0; i < capacity_; ++i) {
+ const uint8_t tag = tags_[i];
+ if (tag != kFreeSlot && (AppendOnly || tag != kTombstone)) {
+ keys_[i].~Key();
+ values_[i].~Value();
+ }
+ }
+ Reset(capacity_, false);
}
- size_t Size() const { return size_; }
+ Value& operator[](Key key) {
+ auto it_and_inserted = Insert(std::move(key), Value{});
+ return *it_and_inserted.first;
+ }
- Iterator begin() const {
- const internal::RBNode* node = root_;
- while (node && node->left)
- node = node->left;
- return Iterator(node);
+ Iterator GetIterator() { return Iterator(this); }
+ const Iterator GetIterator() const { return Iterator(this); }
+
+ size_t size() const { return size_; }
+ size_t capacity() const { return capacity_; }
+
+ // "protected" here is only for the flat_hash_map_benchmark.cc. Everything
+ // below is by all means private.
+ protected:
+ enum ReservedTags : uint8_t { kFreeSlot = 0, kTombstone = 1 };
+ static constexpr size_t kNotFound = std::numeric_limits<size_t>::max();
+
+ template <typename K = Key>
+ size_t FindInternal(const K& key) const {
+ static_assert(
+ IsLookupKeyAllowed<K, Key, Hasher>(),
+ "Heterogeneous lookup requires Hasher to define is_transparent and "
+ "support hashing the lookup key type. For same-type lookup, Key and K "
+ "must match exactly.");
+ const size_t key_hash = Hasher{}(key);
+ const uint8_t tag = HashToTag(key_hash);
+ PERFETTO_DCHECK((capacity_ & (capacity_ - 1)) == 0); // Must be a pow2.
+ PERFETTO_DCHECK(max_probe_length_ <= capacity_);
+ for (size_t i = 0; i < max_probe_length_; ++i) {
+ const size_t idx = Probe::Calc(key_hash, i, capacity_);
+ const uint8_t tag_idx = tags_[idx];
+
+ if (tag_idx == kFreeSlot)
+ return kNotFound;
+ // HashToTag() never returns kTombstone, so the tag-check below cannot
+ // possibly match. Also we just want to skip tombstones.
+ if (tag_idx == tag && keys_[idx] == key) {
+ PERFETTO_DCHECK(tag_idx > kTombstone);
+ return idx;
+ }
+ } // for (idx)
+ return kNotFound;
}
- Iterator end() const { return Iterator(nullptr); }
+ void EraseInternal(size_t idx) {
+ PERFETTO_DCHECK(tags_[idx] > kTombstone);
+ PERFETTO_DCHECK(size_ > 0);
+ tags_[idx] = kTombstone;
+ keys_[idx].~Key();
+ values_[idx].~Value();
+ size_--;
+ tombstones_++;
+ PERFETTO_DCHECK(size_ + tombstones_ <= capacity_);
+ }
- private:
- static constexpr size_t off_ = Traits::NodeOffset();
- static internal::RBNode* nodeof(T* t) {
- PERFETTO_DCHECK(t != nullptr);
- return reinterpret_cast<internal::RBNode*>(reinterpret_cast<uintptr_t>(t) +
- off_);
+ PERFETTO_NO_INLINE void MaybeGrowAndRehash(bool grow) {
+ PERFETTO_DCHECK(size_ <= capacity_);
+ const size_t old_capacity = capacity_;
+
+ // Grow quickly up to 1MB, then chill.
+ const size_t old_size_bytes = old_capacity * (sizeof(Key) + sizeof(Value));
+ const size_t grow_factor = old_size_bytes < (1024u * 1024u) ? 8 : 2;
+ const size_t new_capacity =
+ grow ? std::max(old_capacity * grow_factor, size_t(1024))
+ : old_capacity;
+
+ auto old_tags(std::move(tags_));
+ auto old_keys(std::move(keys_));
+ auto old_values(std::move(values_));
+ size_t old_size = size_;
+
+ // This must be a CHECK (i.e. not just a DCHECK) to prevent UAF attacks on
+ // 32-bit archs that try to double the size of the table until wrapping.
+ PERFETTO_CHECK(new_capacity >= old_capacity);
+ Reset(new_capacity, true);
+
+ size_t new_size = 0; // Recompute the size.
+ for (size_t i = 0; i < old_capacity; ++i) {
+ const uint8_t old_tag = old_tags[i];
+ if (old_tag != kFreeSlot && old_tag != kTombstone) {
+ Insert(std::move(old_keys[i]), std::move(old_values[i]));
+ old_keys[i].~Key(); // Destroy the old objects.
+ old_values[i].~Value();
+ new_size++;
+ }
+ }
+ PERFETTO_DCHECK(new_size == old_size);
+ PERFETTO_DCHECK(tombstones_ == 0);
+ size_ = new_size;
}
- static const T* entryof(const internal::RBNode* n) {
- PERFETTO_DCHECK(n != nullptr);
- return reinterpret_cast<T*>(reinterpret_cast<uintptr_t>(n) - off_);
+
+ // Doesn't call destructors. Use Clear() for that.
+ PERFETTO_NO_INLINE void Reset(size_t n, bool reallocate) {
+ PERFETTO_DCHECK((n & (n - 1)) == 0); // Must be a pow2.
+
+ capacity_ = n;
+ max_probe_length_ = 0;
+ size_ = 0;
+ tombstones_ = 0;
+ load_limit_ = n * static_cast<size_t>(load_limit_percent_) / 100;
+ load_limit_ = std::min(load_limit_, n);
+
+ if (reallocate) {
+ tags_.reset(new uint8_t[n]);
+ keys_ = AlignedAllocTyped<Key[]>(n); // Deliberately not 0-initialized.
+ values_ =
+ AlignedAllocTyped<Value[]>(n); // Deliberately not 0-initialized.
+ }
+
+ // Only clear the tags if not nullptr.
+ if (tags_) {
+ memset(&tags_[0], 0, n); // Clear all tags.
+ }
}
- static int key_compare(const internal::RBNode* node_a,
- const internal::RBNode* node_b) {
- auto* a = entryof(node_a);
- auto* b = entryof(node_b);
- return internal::KeyCompare<Traits>(Traits::GetKey(*a), Traits::GetKey(*b));
+
+ static inline uint8_t HashToTag(size_t full_hash) {
+ uint8_t tag = full_hash >> (sizeof(full_hash) * 8 - 8);
+ // Ensure the hash is always >= 2. We use 0, 1 for kFreeSlot and kTombstone.
+ tag += (tag <= kTombstone) << 1;
+ PERFETTO_DCHECK(tag > kTombstone);
+ return tag;
}
- internal::RBNode* root_ = nullptr;
+ size_t capacity_ = 0;
size_t size_ = 0;
+ size_t tombstones_ = 0;
+ size_t max_probe_length_ = 0;
+ size_t load_limit_ = 0; // Updated every time |capacity_| changes.
+ int load_limit_percent_ =
+ kDefaultLoadLimitPct; // Load factor limit in % of |capacity_|.
+
+ // These arrays have always the |capacity_| elements.
+ // Note: AlignedUniquePtr just allocates memory, doesn't invoke any ctor/dtor.
+ std::unique_ptr<uint8_t[]> tags_;
+ AlignedUniquePtr<Key[]> keys_;
+ AlignedUniquePtr<Value[]> values_;
};
} // namespace perfetto::base
-#endif // INCLUDE_PERFETTO_EXT_BASE_INTRUSIVE_TREE_H_
+#endif // INCLUDE_PERFETTO_EXT_BASE_FLAT_HASH_MAP_V1_H_
/*
* Copyright (C) 2025 The Android Open Source Project
*
@@ -5420,1183 +6011,941 @@ class IntrusiveTree {
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-/* Part of this work is inspired by the original OpenBSD's tree.h */
-/* $OpenBSD: tree.h,v 1.31 2023/03/08 04:43:09 guenther Exp $ */
-/*
- * Copyright 2002 Niels Provos <provos@citi.umich.edu>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-// gen_amalgamated expanded: #include "perfetto/ext/base/intrusive_tree.h"
+#ifndef INCLUDE_PERFETTO_EXT_BASE_FLAT_HASH_MAP_H_
+#define INCLUDE_PERFETTO_EXT_BASE_FLAT_HASH_MAP_H_
-namespace perfetto::base::internal {
+// gen_amalgamated expanded: #include "perfetto/base/build_config.h"
+// gen_amalgamated expanded: #include "perfetto/base/logging.h"
+// gen_amalgamated expanded: #include "perfetto/ext/base/bits.h"
+// gen_amalgamated expanded: #include "perfetto/ext/base/flat_hash_map_v1.h"
+// gen_amalgamated expanded: #include "perfetto/ext/base/murmur_hash.h"
+// gen_amalgamated expanded: #include "perfetto/ext/base/string_utils.h"
+// gen_amalgamated expanded: #include "perfetto/ext/base/string_view.h"
+// gen_amalgamated expanded: #include "perfetto/ext/base/utils.h"
+// gen_amalgamated expanded: #include "perfetto/public/compiler.h"
-namespace {
+#include <algorithm>
+#include <cstddef>
+#include <cstdint>
+#include <cstring>
+#include <functional>
+#include <limits>
+#include <memory>
+#include <string>
+#include <string_view>
+#include <type_traits>
+#include <utility>
-void RBSetBlackRed(RBNode* black, RBNode* red) {
- black->color = RBColor::BLACK;
- red->color = RBColor::RED;
-}
+#if PERFETTO_BUILDFLAG(PERFETTO_X64_CPU_OPT)
+#include <immintrin.h>
+#endif
-void RBRotateLeft(RBNode** root, RBNode* elm, RBNode* tmp) {
- tmp = elm->right;
- if ((elm->right = tmp->left)) {
- tmp->left->parent = elm;
- }
- // RB_AUGMENT(elm);
- if ((tmp->parent = elm->parent)) {
- if (elm == elm->parent->left)
- elm->parent->left = tmp;
- else
- elm->parent->right = tmp;
- } else
- *root = tmp;
- tmp->left = elm;
- elm->parent = tmp;
- // RB_AUGMENT(tmp);
- // if ((tmp->parent))
- // RB_AUGMENT(tmp->parent);
-}
+namespace perfetto::base {
-void RBRotateRight(RBNode** root, RBNode* elm, RBNode* tmp) {
- tmp = elm->left;
- if ((elm->left = tmp->right)) {
- tmp->right->parent = elm;
- }
- // RB_AUGMENT(elm);
- if ((tmp->parent = elm->parent)) {
- if (elm == elm->parent->left)
- elm->parent->left = tmp;
- else
- elm->parent->right = tmp;
- } else
- *root = tmp;
- tmp->right = elm;
- elm->parent = tmp;
- // RB_AUGMENT(tmp);
- // if ((tmp->parent))
- // RB_AUGMENT(tmp->parent);
-}
+// A Swiss Table-style open-addressing hashmap implementation.
+// Inspired by absl::flat_hash_map, this uses a metadata array of control bytes
+// to enable fast SIMD-accelerated probing.
+//
+// Key design choices:
+// - Control bytes: Each slot has a 1-byte tag (7-bit H2 hash or special marker)
+// stored in a separate array, enabling fast group-based matching.
+// - SIMD acceleration: On x64, uses SSE instructions to match 16 control bytes
+// in parallel. Falls back to SWAR (SIMD Within A Register) on other platforms
+// matching 8 bytes at a time.
+// - Triangular probing: Uses the sequence 0, 16, 48, 96, ... (like Absl) to
+// probe groups of slots, ensuring good cache behavior.
+// - Pointers are NOT stable: Neither keys nor values have stable addresses
+// across insertions that trigger rehashing.
+//
+// See also: FlatHashMapV1 in flat_hash_map_v1.h for the older implementation
+// using traditional open-addressing with configurable probing strategies.
-void RBRemoveColor(RBNode** root, RBNode* parent, RBNode* elm) {
- RBNode* tmp;
- while ((elm == nullptr || elm->color == RBColor::BLACK) && elm != *root) {
- if (parent->left == elm) {
- tmp = parent->right;
- if (tmp->color == RBColor::RED) {
- RBSetBlackRed(tmp, parent);
- RBRotateLeft(root, parent, tmp);
- tmp = parent->right;
- }
- if ((tmp->left == nullptr || tmp->left->color == RBColor::BLACK) &&
- (tmp->right == nullptr || tmp->right->color == RBColor::BLACK)) {
- tmp->color = RBColor::RED;
- elm = parent;
- parent = elm->parent;
- } else {
- if (tmp->right == nullptr || tmp->right->color == RBColor::BLACK) {
- RBNode* oleft;
- if ((oleft = tmp->left))
- oleft->color = RBColor::BLACK;
- tmp->color = RBColor::RED;
- RBRotateRight(root, tmp, oleft);
- tmp = parent->right;
- }
- tmp->color = parent->color;
- parent->color = RBColor::BLACK;
- if (tmp->right)
- tmp->right->color = RBColor::BLACK;
- RBRotateLeft(root, parent, tmp);
- elm = *root;
- break;
- }
- } else {
- tmp = parent->left;
- if (tmp->color == RBColor::RED) {
- RBSetBlackRed(tmp, parent);
- RBRotateRight(root, parent, tmp);
- tmp = parent->left;
- }
- if ((tmp->left == nullptr || tmp->left->color == RBColor::BLACK) &&
- (tmp->right == nullptr || tmp->right->color == RBColor::BLACK)) {
- tmp->color = RBColor::RED;
- elm = parent;
- parent = elm->parent;
- } else {
- if (tmp->left == nullptr || tmp->left->color == RBColor::BLACK) {
- RBNode* oright;
- if ((oright = tmp->right))
- oright->color = RBColor::BLACK;
- tmp->color = RBColor::RED;
- RBRotateLeft(root, tmp, oright);
- tmp = parent->left;
- }
- tmp->color = parent->color;
- parent->color = RBColor::BLACK;
- if (tmp->left)
- tmp->left->color = RBColor::BLACK;
- RBRotateRight(root, parent, tmp);
- elm = *root;
- break;
- }
- }
- }
- if (elm)
- elm->color = RBColor::BLACK;
-}
+// Non-templated base class to hold helpers for FlatHashMapV2.
+namespace flat_hash_map_v2_internal {
-} // namespace
+// Helper to detect if a hasher has is_transparent defined.
+template <typename, typename = void>
+struct HasIsTransparent : std::false_type {};
-void RBInsertColor(RBNode** root, RBNode* elm) {
- RBNode *parent, *gparent, *tmp;
- while ((parent = elm->parent) && parent->color == RBColor::RED) {
- gparent = parent->parent;
- if (parent == gparent->left) {
- tmp = gparent->right;
- if (tmp && tmp->color == RBColor::RED) {
- tmp->color = RBColor::BLACK;
- RBSetBlackRed(parent, gparent);
- elm = gparent;
- continue;
- }
- if (parent->right == elm) {
- RBRotateLeft(root, parent, tmp);
- tmp = parent;
- parent = elm;
- elm = tmp;
- }
- RBSetBlackRed(parent, gparent);
- RBRotateRight(root, gparent, tmp);
- } else {
- tmp = gparent->left;
- if (tmp && tmp->color == RBColor::RED) {
- tmp->color = RBColor::BLACK;
- RBSetBlackRed(parent, gparent);
- elm = gparent;
- continue;
- }
- if (parent->left == elm) {
- RBRotateRight(root, parent, tmp);
- tmp = parent;
- parent = elm;
- elm = tmp;
- }
- RBSetBlackRed(parent, gparent);
- RBRotateLeft(root, gparent, tmp);
- }
- }
- (*root)->color = RBColor::BLACK;
-}
+template <typename H>
+struct HasIsTransparent<H, std::void_t<typename H::is_transparent>>
+ : std::true_type {};
-void RBRemove(RBNode** root, RBNode* elm) {
- RBNode* child = elm;
- RBNode* parent = elm;
- RBNode* old = elm;
- RBColor color;
+// Equality comparator trait.
+template <typename T>
+struct HashEq : public std::equal_to<T> {};
- if (elm->left == nullptr)
- child = elm->right;
- else if (elm->right == nullptr)
- child = elm->left;
- else {
- RBNode* left;
- elm = elm->right;
- while ((left = elm->left))
- elm = left;
- child = elm->right;
- parent = elm->parent;
- color = elm->color;
- if (child)
- child->parent = parent;
- if (parent) {
- if (parent->left == elm) {
- parent->left = child;
- } else {
- parent->right = child;
- }
- // RB_AUGMENT(parent);
- } else {
- *root = child;
- }
- if (elm->parent == old)
- parent = elm;
- *elm = *old;
- if (old->parent) {
- if (old->parent->left == old) {
- old->parent->left = elm;
- } else {
- old->parent->right = elm;
- }
- // RB_AUGMENT(old->parent);
- } else {
- *root = elm;
- }
- old->left->parent = elm;
- if (old->right)
- old->right->parent = elm;
- if (parent) {
- left = parent;
- // do {
- // RB_AUGMENT(left);
- // } while ((left = left->parent));
- }
- goto color;
+// Specialization for std::string to compare via std::string_view.
+//
+// This exists because after benchmarking, it turns out libc++ has an
+// "optimization" for std::string equality that does something byte by
+// byte comparision for short strings but this is slower than just memcmp.
+//
+// This helps close the gap to absl::flat_hash_map for string keys.
+template <>
+struct HashEq<std::string> {
+ bool operator()(const std::string& a, const std::string& b) const {
+ return std::string_view(a) == std::string_view(b);
}
- parent = elm->parent;
- color = elm->color;
- if (child)
- child->parent = parent;
- if (parent) {
- if (parent->left == elm)
- parent->left = child;
- else
- parent->right = child;
- // RB_AUGMENT(parent);
- } else {
- *root = child;
+ bool operator()(const std::string& a, const std::string_view& b) const {
+ return std::string_view(a) == b;
}
-color:
- if (color == RBColor::BLACK)
- RBRemoveColor(root, parent, child);
-}
+ bool operator()(const std::string& a, base::StringView b) const {
+ return base::StringView(a) == b;
+ }
+ bool operator()(const std::string& a, const char* b) const {
+ return std::string_view(a) == std::string_view(b);
+ }
+};
-// Returns nullptr after reaching the last leaf (the max element).
-const RBNode* RBNext(const RBNode* node) {
- if (node->right) {
- node = node->right;
- while (node->left)
- node = node->left;
+// Specialization for double to prevent spurious -Wfloat-equal warnings.
+//
+// Trace processor legitimately has a need to compare with exact equality
+template <>
+struct HashEq<double> {
+ bool operator()(double a, double b) const { return std::equal_to<>()(a, b); }
+};
+
+// Helper to check if a lookup key type K is allowed.
+// Returns true if:
+// 1. Hasher is transparent, can hash K, and Eq can compare Key and K, OR
+// 2. Hasher is not transparent and K can be implicitly converted to Key.
+template <typename K, typename Key, typename Hasher, typename Eq>
+constexpr bool IsLookupKeyAllowed() {
+ if constexpr (HasIsTransparent<Hasher>::value) {
+ return std::is_invocable_v<Hasher, const K&> &&
+ std::is_invocable_v<Eq, const Key&, const K&>;
+ } else if constexpr (std::is_convertible_v<K, Key>) {
+ return true;
} else {
- if (node->parent && node == node->parent->left) {
- node = node->parent;
- } else {
- while (node->parent && node == node->parent->right) {
- node = node->parent;
- }
- node = node->parent;
- }
+ return false;
}
- return node;
}
-} // namespace perfetto::base::internal
-// gen_amalgamated begin source: src/base/logging.cc
-// gen_amalgamated begin header: src/base/log_ring_buffer.h
-// gen_amalgamated begin header: include/perfetto/ext/base/thread_annotations.h
-/*
- * 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.
- */
+// Swiss Table control byte encoding:
+// - Empty: 0x80 (10000000) - MSB set, easy to detect with sign bit
+// - Deleted: 0xFE (11111110) - MSB set
+// - Full: 0x00-0x7F - MSB clear, stores 7-bit H2 hash
+static constexpr uint8_t kFreeSlot = 0x80; // Empty slot
+static constexpr uint8_t kTombstone = 0xFE; // Deleted slot
-#ifndef INCLUDE_PERFETTO_EXT_BASE_THREAD_ANNOTATIONS_H_
-#define INCLUDE_PERFETTO_EXT_BASE_THREAD_ANNOTATIONS_H_
+// The default load limit percent before growing the table.
+static constexpr int kDefaultLoadLimitPct = 75;
-// gen_amalgamated expanded: #include "perfetto/base/build_config.h"
+// Abstraction over a group of control bytes that enables batch operations.
+// On x64, uses SSE to match 16 control bytes in parallel.
+// On other platforms, uses SWAR (SIMD Within A Register) for 8 bytes.
+//
+// Match() returns an iterator over slots whose control byte matches h2.
+// MatchEmpty() returns an iterator over empty slots (kFreeSlot).
+// MatchEmptyOrDeleted() returns an iterator over empty or deleted slots.
+#if PERFETTO_BUILDFLAG(PERFETTO_X64_CPU_OPT)
+struct Group {
+ public:
+ // Group size 16 for x64 SSE
+ static constexpr size_t kSize = 16;
-// Windows TSAN doesn't currently support these annotations.
-#if defined(THREAD_SANITIZER) && !PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
-extern "C" {
-void AnnotateBenignRaceSized(const char* file,
- int line,
- const volatile void* address,
- size_t size,
- const char* description);
-}
+ // Iterates over set bits in a match mask. Each set bit indicates a slot
+ // in the group that matched the search criteria. Call Next() to get the
+ // index of each matching slot.
+ struct Iterator {
+ public:
+ PERFETTO_ALWAYS_INLINE explicit Iterator(uint16_t mask) : mask_(mask) {}
+ PERFETTO_ALWAYS_INLINE explicit operator bool() const { return mask_; }
-#define PERFETTO_ANNOTATE_BENIGN_RACE_SIZED(pointer, size, description) \
- AnnotateBenignRaceSized(__FILE__, __LINE__, pointer, size, description);
-#else // defined(ADDRESS_SANITIZER)
-#define PERFETTO_ANNOTATE_BENIGN_RACE_SIZED(pointer, size, description)
-#endif // defined(ADDRESS_SANITIZER)
+ PERFETTO_ALWAYS_INLINE size_t Next() {
+ auto idx = static_cast<size_t>(CountTrailZeros(mask_));
+ mask_ &= static_cast<uint16_t>(mask_ - 1);
+ return idx;
+ }
-#endif // INCLUDE_PERFETTO_EXT_BASE_THREAD_ANNOTATIONS_H_
-/*
- * Copyright (C) 2021 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.
- */
+ private:
+ uint16_t mask_;
+ };
-#ifndef SRC_BASE_LOG_RING_BUFFER_H_
-#define SRC_BASE_LOG_RING_BUFFER_H_
+ PERFETTO_ALWAYS_INLINE explicit Group(const uint8_t* pos) {
+ ctrl_ = _mm_loadu_si128(reinterpret_cast<const __m128i*>(pos));
+ }
-#include <stddef.h>
-#include <stdio.h>
+ PERFETTO_ALWAYS_INLINE Iterator Match(uint8_t h2) const {
+ auto match = _mm_cmpeq_epi8(ctrl_, _mm_set1_epi8(static_cast<char>(h2)));
+ return Iterator(static_cast<uint16_t>(_mm_movemask_epi8(match)));
+ }
-#include <array>
-#include <atomic>
+ PERFETTO_ALWAYS_INLINE Iterator MatchEmpty() const {
+ return Iterator(
+ static_cast<uint16_t>(_mm_movemask_epi8(_mm_sign_epi8(ctrl_, ctrl_))));
+ }
-// gen_amalgamated expanded: #include "perfetto/ext/base/string_view.h"
-// gen_amalgamated expanded: #include "perfetto/ext/base/thread_annotations.h"
+ PERFETTO_ALWAYS_INLINE Iterator MatchEmptyOrDeleted() const {
+ return Iterator(static_cast<uint16_t>(_mm_movemask_epi8(ctrl_)));
+ }
-namespace perfetto {
-namespace base {
+ private:
+ __m128i ctrl_;
+};
+#else
+// SWAR fallback: processes 8 control bytes at a time using 64-bit arithmetic.
+struct Group {
+ public:
+ // Group size 8 for ARM and other platforms
+ static constexpr size_t kSize = 8;
-// Defined out of line because a static constexpr requires static storage if
-// ODR-used, not worth adding a .cc file just for tests.
-constexpr size_t kLogRingBufEntries = 8;
-constexpr size_t kLogRingBufMsgLen = 256;
+ // Iterates over set bits in a sparse 64-bit mask. Each set MSB indicates
+ // a matching byte in the group. Call Next() to get the index of each
+ // matching slot.
+ struct Iterator {
+ public:
+ PERFETTO_ALWAYS_INLINE explicit Iterator(uint64_t mask) : mask_(mask) {}
+ PERFETTO_ALWAYS_INLINE explicit operator bool() const { return mask_; }
+ PERFETTO_ALWAYS_INLINE size_t Next() {
+ // Count zeros and divide by 8 (shift 3)
+ // 0x80 (Byte 0) -> CTZ 7 -> 7>>3 = 0
+ // 0x8000 (Byte 1) -> CTZ 15 -> 15>>3 = 1
+ size_t idx = static_cast<size_t>(CountTrailZeros(mask_) >> 3);
+ mask_ &= mask_ - 1; // Clear lowest set bit
+ return idx;
+ }
-// A static non-allocating ring-buffer to hold the most recent log events.
-// This class is really an implementation detail of logging.cc. The only reason
-// why is fully defined in a dedicated header is for allowing unittesting,
-// without leaking extra headers into logging.h (which is a high-fanout header).
-// This is used to report the last logs in a crash report when a CHECK/FATAL
-// is encountered.
-// This class has just an Append() method to insert events into the buffer and
-// a Read() to read the events in FIFO order. Read() is non-destructive.
-//
-// Thread safety considerations:
-// - The Append() method can be called concurrently by several threads, unless
-// there are > kLogRingBufEntries concurrent threads. Even if that happens,
-// case some events will contain a mix of strings but the behavior of
-// further Append() and Read() is still defined.
-// - The Read() method is not thread safe but it's fine in practice. Even if
-// it's called concurrently with other Append(), it only causes some partial
-// events to be emitted in output.
-// In both cases, we never rely purely on \0, all operations are size-bound.
-//
-// See logging_unittest.cc for tests.
-class LogRingBuffer {
- public:
- LogRingBuffer() = default;
- LogRingBuffer(const LogRingBuffer&) = delete;
- LogRingBuffer& operator=(const LogRingBuffer&) = delete;
- LogRingBuffer(LogRingBuffer&&) = delete;
- LogRingBuffer& operator=(LogRingBuffer&&) = delete;
+ private:
+ uint64_t mask_;
+ };
- // This takes three arguments because it fits its only caller (logging.cc).
- // The args are just concatenated together (plus one space before the msg).
- void Append(StringView tstamp, StringView source, StringView log_msg) {
- // Reserve atomically a slot in the ring buffer, so any concurrent Append()
- // won't overlap (unless too many concurrent Append() happen together).
- // There is no strict synchronization here, |event_slot_| is atomic only for
- // the sake of avoiding colliding on the same slot but does NOT guarantee
- // full consistency and integrity of the log messages written in each slot.
- // A release-store (or acq+rel) won't be enough for full consistency. Two
- // threads that race on Append() and take the N+1 and N+2 slots could finish
- // the write in reverse order. So Read() would need to synchronize with
- // something else (either a per-slot atomic flag or with a second atomic
- // counter which is incremented after the snprintf). Both options increase
- // the cost of Append() with no huge benefits (90% of the perfetto services
- // where we use it is single thread, and the log ring buffer is disabled
- // on non-standalone builds like the SDK).
- uint32_t slot = event_slot_.fetch_add(1, std::memory_order_relaxed);
- slot = slot % kLogRingBufEntries;
+ PERFETTO_ALWAYS_INLINE explicit Group(const uint8_t* pos) {
+ memcpy(&ctrl_, pos, sizeof(ctrl_));
+ }
- char* const msg = events_[slot];
- PERFETTO_ANNOTATE_BENIGN_RACE_SIZED(msg, kLogRingBufMsgLen,
- "see comments in log_ring_buffer.h")
- snprintf(msg, kLogRingBufMsgLen, "%.*s%.*s %.*s",
- static_cast<int>(tstamp.size()), tstamp.data(),
- static_cast<int>(source.size()), source.data(),
- static_cast<int>(log_msg.size()), log_msg.data());
+ PERFETTO_ALWAYS_INLINE Iterator Match(uint8_t h2) const {
+ uint64_t x = ctrl_ ^ (kLsbs * h2);
+ return Iterator((x - kLsbs) & ~x & kMsbs);
}
- // Reads back the buffer in FIFO order, up to |len - 1| characters at most
- // (the -1 is because a NUL terminator is always appended, unless |len| == 0).
- // The string written in |dst| is guaranteed to be NUL-terminated, even if
- // |len| < buffer contents length.
- // Returns the number of bytes written in output, excluding the \0 terminator.
- size_t Read(char* dst, size_t len) {
- if (len == 0)
- return 0;
- // This is a relaxed-load because we don't need to fully synchronize on the
- // writing path for the reasons described in the fetch_add() above.
- const uint32_t event_slot = event_slot_.load(std::memory_order_relaxed);
- size_t dst_written = 0;
- for (uint32_t pos = 0; pos < kLogRingBufEntries; ++pos) {
- const uint32_t slot = (event_slot + pos) % kLogRingBufEntries;
- const char* src = events_[slot];
- if (*src == '\0')
- continue; // Empty slot. Skip.
- char* const wptr = dst + dst_written;
- // |src| might not be null terminated. This can happen if some
- // thread-race happened. Limit the copy length.
- const size_t limit = std::min(len - dst_written, kLogRingBufMsgLen);
- for (size_t i = 0; i < limit; ++i) {
- const char c = src[i];
- ++dst_written;
- if (c == '\0' || i == limit - 1) {
- wptr[i] = '\n';
- break;
- }
- // Skip non-printable ASCII characters to avoid confusing crash reports.
- // Note that this deliberately mangles \n. Log messages should not have
- // a \n in the middle and are NOT \n terminated. The trailing \n between
- // each line is appended by the if () branch above.
- const bool is_printable = c >= ' ' && c <= '~';
- wptr[i] = is_printable ? c : '?';
- }
- }
- // Ensure that the output string is null-terminated.
- PERFETTO_DCHECK(dst_written <= len);
- if (dst_written == len) {
- // In case of truncation we replace the last char with \0. But the return
- // value is the number of chars without \0, hence the --.
- dst[--dst_written] = '\0';
- } else {
- dst[dst_written] = '\0';
- }
- return dst_written;
+ PERFETTO_ALWAYS_INLINE Iterator MatchEmpty() const {
+ // 0x80 check (Empty)
+ return Iterator((ctrl_ & ~(ctrl_ << 6)) & kMsbs);
}
- private:
- using EventBuf = char[kLogRingBufMsgLen];
- EventBuf events_[kLogRingBufEntries]{};
+ PERFETTO_ALWAYS_INLINE Iterator MatchEmptyOrDeleted() const {
+ // 0x80 or 0xFE check (Empty or Deleted)
+ return Iterator((ctrl_ & ~(ctrl_ << 7)) & kMsbs);
+ }
- static_assert((kLogRingBufEntries & (kLogRingBufEntries - 1)) == 0,
- "kLogRingBufEntries must be a power of two");
+ private:
+ static constexpr uint64_t kLsbs = 0x0101010101010101ULL;
+ static constexpr uint64_t kMsbs = 0x8080808080808080ULL;
- // A monotonically increasing counter incremented on each event written.
- // It determines which of the kLogRingBufEntries indexes in |events_| should
- // be used next.
- // It grows >> kLogRingBufEntries, it's supposed to be always used
- // mod(kLogRingBufEntries). A static_assert in the .cc file ensures that
- // kLogRingBufEntries is a power of two so wraps are aligned.
- std::atomic<uint32_t> event_slot_{};
+ uint64_t ctrl_;
};
+#endif
-} // namespace base
-} // namespace perfetto
+// The state and the operations of FlatHashMapV2 which don't depend on the key
+// and value types. Not templated, and the heavier operations are defined in
+// flat_hash_map.cc, so that all maps share one copy of the code.
+class FlatHashMapV2Base {
+ protected:
+ // Tracks growth capacity and whether any deletions have occurred.
+ // Using bitfields like absl's GrowthInfo to avoid manual bit manipulation.
+ struct GrowthInfo {
+ uint64_t growth_left : 63;
+ uint64_t has_tombstones : 1;
+ };
-#endif // SRC_BASE_LOG_RING_BUFFER_H_
-/*
- * 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.
- */
-
-// gen_amalgamated expanded: #include "perfetto/base/logging.h"
+ // The table being moved out of while growing.
+ struct OldTable {
+ std::unique_ptr<uint8_t[]> storage;
+ const uint8_t* ctrl;
+ uint8_t* slots;
+ size_t capacity;
+ size_t size;
+ };
-#include <stdarg.h>
-#include <stdio.h>
+ // The number of cloned control bytes after the main control byte array.
+ static constexpr size_t kNumClones = Group::kSize - 1;
-#if !PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
-#include <unistd.h> // For isatty()
-#endif
+ explicit FlatHashMapV2Base(int load_limit_pct)
+ : load_limit_percent_(load_limit_pct) {}
-#include <atomic>
-#include <memory>
+ FlatHashMapV2Base(FlatHashMapV2Base&& other) noexcept
+ : storage_(std::move(other.storage_)),
+ capacity_(other.capacity_),
+ size_(other.size_),
+ growth_info_(other.growth_info_),
+ load_limit_percent_(other.load_limit_percent_),
+ ctrl_(other.ctrl_),
+ slots_(other.slots_) {
+ other.capacity_ = 0;
+ other.size_ = 0;
+ other.growth_info_ = {0, 0};
+ other.load_limit_percent_ = kDefaultLoadLimitPct;
+ other.ctrl_ = nullptr;
+ other.slots_ = nullptr;
+ }
-// gen_amalgamated expanded: #include "perfetto/base/build_config.h"
-// gen_amalgamated expanded: #include "perfetto/base/time.h"
-// gen_amalgamated expanded: #include "perfetto/ext/base/crash_keys.h"
-// gen_amalgamated expanded: #include "perfetto/ext/base/string_utils.h"
-// gen_amalgamated expanded: #include "perfetto/ext/base/string_view.h"
-// gen_amalgamated expanded: #include "src/base/log_ring_buffer.h"
+ // Swiss Table hash splitting (matching absl):
+ // H1 = upper bits for bucket index
+ // H2 = lower 7 bits for tag
+ // This ensures H1 and H2 are independent, avoiding tag collisions within
+ // buckets. The seed XOR prevents clustering when hash values have patterns
+ // (e.g., sequential keys)
+ static constexpr size_t H1(size_t hash) { return (hash >> 7); }
+ static constexpr uint8_t H2(size_t hash) { return hash & 0x7F; }
-#if PERFETTO_ENABLE_LOG_RING_BUFFER() && PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID)
-#include <android/set_abort_message.h>
-#endif
+ // Doesn't call destructors.
+ void Reset(size_t n, bool reallocate, size_t slot_size, size_t slot_align);
-namespace perfetto {
-namespace base {
+ // Find first empty OR tombstone slot for insertion.
+ // Called when has_tombstones is set to find an earlier tombstone that can
+ // be reused instead of taking a new empty slot.
+ size_t FindFirstEmptyOrTombstone(size_t key_hash) const;
-namespace {
-const char kReset[] = "\x1b[0m";
-const char kDefault[] = "\x1b[39m";
-const char kDim[] = "\x1b[2m";
-const char kRed[] = "\x1b[31m";
-const char kBoldGreen[] = "\x1b[1m\x1b[32m";
-const char kLightGray[] = "\x1b[90m";
+ PERFETTO_ALWAYS_INLINE size_t
+ FindFirstEmptyOrTombstoneImpl(size_t key_hash) const {
+ const size_t cap_mask = capacity_ - 1;
+ size_t offset = H1(key_hash) & cap_mask;
+ size_t probe_size = 0;
+ while (true) {
+ Group group(ctrl_ + offset);
+ if (auto it = group.MatchEmptyOrDeleted(); PERFETTO_LIKELY(it)) {
+ return (offset + it.Next()) & cap_mask;
+ }
+ probe_size += Group::kSize;
+ offset = (offset + probe_size) & cap_mask;
+ }
+ }
-std::atomic<LogMessageCallback> g_log_callback{};
+ // Swaps in an empty table twice as large and returns the old one, from
+ // which the caller must move the entries before calling FinishGrow().
+ OldTable Grow(size_t slot_size, size_t slot_align);
-#if PERFETTO_BUILDFLAG(PERFETTO_STDERR_CRASH_DUMP)
-// __attribute__((constructor)) causes a static initializer that automagically
-// early runs this function before the main().
-void PERFETTO_EXPORT_COMPONENT __attribute__((constructor))
-InitDebugCrashReporter() {
- // This function is defined in debug_crash_stack_trace.cc.
- // The dynamic initializer is in logging.cc because logging.cc is included
- // in virtually any target that depends on base. Having it in
- // debug_crash_stack_trace.cc would require figuring out -Wl,whole-archive
- // which is not worth it.
- EnableStacktraceOnCrashForDebug();
-}
-#endif
+ void FinishGrow(size_t new_size) {
+ PERFETTO_CHECK(growth_info_.growth_left >= new_size);
+ size_ = new_size;
+ growth_info_.growth_left -= new_size;
+ }
-#if PERFETTO_ENABLE_LOG_RING_BUFFER()
-LogRingBuffer g_log_ring_buffer{};
+ // Set control byte and update clone if needed
+ PERFETTO_ALWAYS_INLINE void SetCtrl(size_t i, uint8_t h) {
+ ctrl_[i] = h;
+ // Update clone if this is one of the first kNumClones entries
+ if (PERFETTO_UNLIKELY(i < kNumClones)) {
+ ctrl_[capacity_ + i] = h;
+ }
+ }
-// This is global to avoid allocating memory or growing too much the stack
-// in MaybeSerializeLastLogsForCrashReporting(), which is called from
-// arbitrary code paths hitting PERFETTO_CHECK()/FATAL().
-char g_crash_buf[kLogRingBufEntries * kLogRingBufMsgLen];
-#endif
+ // Owns the actual memory with the following layout:
+ //
+ // [Control bytes]
+ // |capacity_| bytes for control bytes.
+ // kNumClones (15 or 7) bytes for control byte clones (*).
+ // No alignment required (accessed at arbitrary byte offsets).
+ //
+ // [Padding for Slot alignment]
+ //
+ // [Slots]
+ // capacity_ * sizeof(Slot): contains key-value pairs.
+ // Must be aligned to alignof(Slot).
+ //
+ // (*) Control byte clones: The first kNumClones control bytes are duplicated
+ // at the end of the control array. This allows SIMD operations to read a full
+ // group (16 or 8 bytes) starting from any position without bounds checking,
+ // even near the end of the array.
+ std::unique_ptr<uint8_t[]> storage_;
-} // namespace
+ size_t capacity_ = 0;
+ size_t size_ = 0;
-void SetLogMessageCallback(LogMessageCallback callback) {
- g_log_callback.store(callback, std::memory_order_relaxed);
-}
+ // Slots remaining + has_deleted flag
+ GrowthInfo growth_info_{0, 0};
-void LogMessage(LogLev level,
- const char* fname,
- int line,
- const char* fmt,
- ...) {
- char stack_buf[512];
- std::unique_ptr<char[]> large_buf;
- char* log_msg = &stack_buf[0];
- size_t log_msg_len = 0;
+ // Load factor limit in % of |capacity_|.
+ int load_limit_percent_ = kDefaultLoadLimitPct;
- // By default use a stack allocated buffer because most log messages are quite
- // short. In rare cases they can be larger (e.g. --help). In those cases we
- // pay the cost of allocating the buffer on the heap.
- for (size_t max_len = sizeof(stack_buf);;) {
- va_list args;
- va_start(args, fmt);
- int res = vsnprintf(log_msg, max_len, fmt, args);
- va_end(args);
+ // Cached pointers for fast access (like absl::flat_hash_map)
+ // These are updated whenever storage is allocated/reallocated.
+ uint8_t* ctrl_ = nullptr; // Points to control bytes
+ uint8_t* slots_ = nullptr; // Points to slot array
+};
- // If for any reason the print fails, overwrite the message but still print
- // it. The code below will attach the filename and line, which is still
- // useful.
- if (res < 0) {
- snprintf(log_msg, max_len, "%s", "[printf format error]");
- break;
- }
+} // namespace flat_hash_map_v2_internal
- // if res == max_len, vsnprintf saturated the input buffer. Retry with a
- // larger buffer in that case (within reasonable limits).
- if (res < static_cast<int>(max_len) || max_len >= 128 * 1024) {
- // In case of truncation vsnprintf returns the len that "would have been
- // written if the string was longer", not the actual chars written.
- log_msg_len = std::min(static_cast<size_t>(res), max_len - 1);
- break;
+// Hash and equality functors which treat ASCII strings case-insensitively.
+// Pass as the Hasher/Eq parameters of FlatHashMapV2 for maps keyed by
+// case-insensitive identifiers (e.g. SQL object names). Transparent, so
+// lookups accept std::string_view or const char* without constructing a
+// std::string key.
+struct CaseInsensitiveHash {
+ using is_transparent = void;
+ uint64_t operator()(std::string_view value) const {
+ MurmurHashCombiner combiner;
+ for (char c : value) {
+ combiner.Combine(Lowercase(c));
}
- max_len *= 4;
- large_buf.reset(new char[max_len]);
- log_msg = &large_buf[0];
- }
-
- LogMessageCallback cb = g_log_callback.load(std::memory_order_relaxed);
- if (cb) {
- cb({level, line, fname, log_msg});
- return;
+ return combiner.digest();
}
+};
- const char* color = kDefault;
- switch (level) {
- case kLogDebug:
- color = kDim;
- break;
- case kLogInfo:
- color = kDefault;
- break;
- case kLogImportant:
- color = kBoldGreen;
- break;
- case kLogError:
- color = kRed;
- break;
+struct CaseInsensitiveEq {
+ using is_transparent = void;
+ bool operator()(std::string_view lhs, std::string_view rhs) const {
+ return CaseInsensitiveEqual(lhs, rhs);
}
+};
-#if !PERFETTO_BUILDFLAG(PERFETTO_OS_WIN) && \
- !PERFETTO_BUILDFLAG(PERFETTO_OS_WASM) && \
- !PERFETTO_BUILDFLAG(PERFETTO_CHROMIUM_BUILD)
- static const bool use_colors = isatty(STDERR_FILENO);
-#else
- static const bool use_colors = false;
-#endif
-
- // Formats file.cc:line as a space-padded fixed width string. If the file name
- // |fname| is too long, truncate it on the left-hand side.
- StackString<10> line_str("%d", line);
-
- // 24 will be the width of the file.cc:line column in the log event.
- static constexpr size_t kMaxNameAndLine = 24;
- size_t fname_len = strlen(fname);
- size_t fname_max = kMaxNameAndLine - line_str.len() - 2; // 2 = ':' + '\0'.
- size_t fname_offset = fname_len <= fname_max ? 0 : fname_len - fname_max;
- StackString<kMaxNameAndLine> file_and_line(
- "%*s:%s", static_cast<int>(fname_max), &fname[fname_offset],
- line_str.c_str());
-
-#if PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID)
- // Logcat has already timestamping, don't re-emit it.
- __android_log_print(int{ANDROID_LOG_DEBUG} + level, "perfetto", "%s %s",
- file_and_line.c_str(), log_msg);
-#endif
+template <typename Key,
+ typename Value,
+ typename Hasher = base::MurmurHash<Key>,
+ typename Eq = flat_hash_map_v2_internal::HashEq<Key>>
+class FlatHashMapV2 : private flat_hash_map_v2_internal::FlatHashMapV2Base {
+ private:
+ // Import constants from internal namespace.
+ static constexpr uint8_t kFreeSlot = flat_hash_map_v2_internal::kFreeSlot;
+ static constexpr uint8_t kTombstone = flat_hash_map_v2_internal::kTombstone;
+ static constexpr int kDefaultLoadLimitPct =
+ flat_hash_map_v2_internal::kDefaultLoadLimitPct;
- // When printing on stderr, print also the timestamp. We don't really care
- // about the actual time. We just need some reference clock that can be used
- // to correlated events across different processes (e.g. traced and
- // traced_probes). The wall time % 1000 is good enough.
- uint32_t t_ms = static_cast<uint32_t>(GetWallTimeMs().count());
- uint32_t t_sec = t_ms / 1000;
- t_ms -= t_sec * 1000;
- t_sec = t_sec % 1000;
- StackString<32> timestamp("[%03u.%03u] ", t_sec, t_ms);
+ // Slot structure holds both key and value
+ struct Slot {
+ Key key;
+ Value value;
+ };
- if (use_colors) {
- fprintf(stderr, "%s%s%s%s %s%s%s\n", kLightGray, timestamp.c_str(),
- file_and_line.c_str(), kReset, color, log_msg, kReset);
- } else {
- fprintf(stderr, "%s%s %s\n", timestamp.c_str(), file_and_line.c_str(),
- log_msg);
+ // Whether |K| is a type other than Key which, with a transparent Hasher,
+ // is hashed and compared to Key as is (e.g. a std::string_view looked up in
+ // a map keyed by std::string), sparing the construction of a Key.
+ template <typename K>
+ static constexpr bool IsHeterogeneousKey() {
+ using RawK = std::remove_cv_t<std::remove_reference_t<K>>;
+ if constexpr (std::is_same_v<RawK, Key>) {
+ return false;
+ } else {
+ return flat_hash_map_v2_internal::HasIsTransparent<Hasher>::value &&
+ flat_hash_map_v2_internal::IsLookupKeyAllowed<RawK, Key, Hasher,
+ Eq>();
+ }
}
-#if PERFETTO_ENABLE_LOG_RING_BUFFER()
- // Append the message to the ring buffer for crash reporting postmortems.
- StringView timestamp_sv = timestamp.string_view();
- StringView file_and_line_sv = file_and_line.string_view();
- StringView log_msg_sv(log_msg, static_cast<size_t>(log_msg_len));
- g_log_ring_buffer.Append(timestamp_sv, file_and_line_sv, log_msg_sv);
-#else
- ignore_result(log_msg_len);
-#endif
-}
+ public:
+ class Iterator {
+ public:
+ explicit Iterator(const uint8_t* ctrl, const uint8_t* ctrl_end, Slot* slot)
+ : ctrl_(ctrl), ctrl_end_(ctrl_end), slot_(slot) {
+ FindNextNonFree();
+ }
+ ~Iterator() = default;
+ Iterator(const Iterator&) = default;
+ Iterator& operator=(const Iterator&) = default;
+ Iterator(Iterator&&) noexcept = default;
+ Iterator& operator=(Iterator&&) noexcept = default;
-#if PERFETTO_ENABLE_LOG_RING_BUFFER()
-void MaybeSerializeLastLogsForCrashReporting() {
- // Keep this function minimal. This is called from the watchdog thread, often
- // when the system is thrashing.
+ const Key& key() { return slot_->key; }
+ Value& value() { return slot_->value; }
+ const Key& key() const { return slot_->key; }
+ const Value& value() const { return slot_->value; }
- // This is racy because two threads could hit a CHECK/FATAL at the same time.
- // But if that happens we have bigger problems, not worth designing around it.
- // The behaviour is still defined in the race case (the string attached to
- // the crash report will contain a mixture of log strings).
- size_t wr = 0;
- wr += SerializeCrashKeys(&g_crash_buf[wr], sizeof(g_crash_buf) - wr);
- wr += g_log_ring_buffer.Read(&g_crash_buf[wr], sizeof(g_crash_buf) - wr);
+ explicit operator bool() const { return ctrl_ != ctrl_end_; }
+ Iterator& operator++() {
+ PERFETTO_DCHECK(ctrl_ != ctrl_end_);
+ ++ctrl_;
+ ++slot_;
+ FindNextNonFree();
+ return *this;
+ }
- // Read() null-terminates the string properly. This is just to avoid UB when
- // two threads race on each other (T1 writes a shorter string, T2
- // overwrites the \0 writing a longer string. T1 continues here before T2
- // finishes writing the longer string with the \0 -> boom.
- g_crash_buf[sizeof(g_crash_buf) - 1] = '\0';
+ private:
+ void FindNextNonFree() {
+ for (; ctrl_ != ctrl_end_; ++ctrl_, ++slot_) {
+ const uint8_t cur_ctrl = *ctrl_;
+ if (cur_ctrl != kFreeSlot && cur_ctrl != kTombstone)
+ return;
+ }
+ }
+ const uint8_t* ctrl_ = nullptr;
+ const uint8_t* ctrl_end_ = nullptr;
+ Slot* slot_ = nullptr;
+ }; // Iterator
-#if PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID)
- // android_set_abort_message() will cause debuggerd to report the message
- // in the tombstone and in the crash log in logcat.
- // NOTE: android_set_abort_message() can be called only once. This should
- // be called only when we are sure we are about to crash.
- android_set_abort_message(g_crash_buf);
-#else
- // Print out the message on stderr on Linux/Mac/Win.
- fputs("\n-----BEGIN PERFETTO PRE-CRASH LOG-----\n", stderr);
- fputs(g_crash_buf, stderr);
- fputs("\n-----END PERFETTO PRE-CRASH LOG-----\n", stderr);
-#endif
-}
-#endif // PERFETTO_ENABLE_LOG_RING_BUFFER
+ explicit FlatHashMapV2(size_t initial_capacity = 0,
+ int load_limit_pct = kDefaultLoadLimitPct)
+ : FlatHashMapV2Base(load_limit_pct) {
+ if (initial_capacity > 0) {
+ Reset(initial_capacity, true);
+ }
+ }
-} // namespace base
-} // namespace perfetto
-// gen_amalgamated begin source: src/base/metatrace.cc
-// gen_amalgamated begin header: include/perfetto/ext/base/metatrace.h
-// gen_amalgamated begin header: include/perfetto/ext/base/metatrace_events.h
-/*
- * 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.
- */
+ // We are calling Clear() so that the destructors for the inserted entries are
+ // called (unless they are trivial, in which case it will be a no-op).
+ ~FlatHashMapV2() { Clear(); }
-#ifndef INCLUDE_PERFETTO_EXT_BASE_METATRACE_EVENTS_H_
-#define INCLUDE_PERFETTO_EXT_BASE_METATRACE_EVENTS_H_
+ FlatHashMapV2(FlatHashMapV2&& other) noexcept
+ : FlatHashMapV2Base(std::move(other)) {}
-#include <stdint.h>
+ FlatHashMapV2& operator=(FlatHashMapV2&& other) noexcept {
+ this->~FlatHashMapV2();
+ new (this) FlatHashMapV2(std::move(other));
+ return *this;
+ }
-namespace perfetto {
-namespace metatrace {
+ FlatHashMapV2(const FlatHashMapV2&) = delete;
+ FlatHashMapV2& operator=(const FlatHashMapV2&) = delete;
-enum Tags : uint32_t {
- TAG_NONE = 0,
- TAG_ANY = uint32_t(-1),
- TAG_FTRACE = 1 << 0,
- TAG_PROC_POLLERS = 1 << 1,
- TAG_TRACE_WRITER = 1 << 2,
- TAG_TRACE_SERVICE = 1 << 3,
- TAG_PRODUCER = 1 << 4,
-};
+ // Find(), Erase(), Insert() and operator[] take a Key, which the caller
+ // converts to as needed. With a transparent Hasher, they also take any type
+ // it can hash and compare to Key as is (see IsHeterogeneousKey()).
-// The macros below generate matching enums and arrays of string literals.
-// This is to avoid maintaining string maps manually.
+ PERFETTO_ALWAYS_INLINE Value* Find(const Key& key) const {
+ return FindImpl(key);
+ }
+ template <typename K, typename = std::enable_if_t<IsHeterogeneousKey<K>()>>
+ PERFETTO_ALWAYS_INLINE Value* Find(const K& key) const {
+ return FindImpl(key);
+ }
-// clang-format off
+ bool Erase(const Key& key) { return EraseImpl(key); }
+ template <typename K, typename = std::enable_if_t<IsHeterogeneousKey<K>()>>
+ bool Erase(const K& key) {
+ return EraseImpl(key);
+ }
-// DO NOT remove or reshuffle items in this list, only append. The ID of these
-// events are an ABI, the trace processor relies on these to open old traces.
-#define PERFETTO_METATRACE_EVENTS(F) \
- F(EVENT_ZERO_UNUSED), \
- F(FTRACE_CPU_READER_READ), /*unused*/ \
- F(FTRACE_DRAIN_CPUS), /*unused*/ \
- F(FTRACE_UNBLOCK_READERS), /*unused*/ \
- F(FTRACE_CPU_READ_NONBLOCK), /*unused*/ \
- F(FTRACE_CPU_READ_BLOCK), /*unused*/ \
- F(FTRACE_CPU_SPLICE_NONBLOCK), /*unused*/ \
- F(FTRACE_CPU_SPLICE_BLOCK), /*unused*/ \
- F(FTRACE_CPU_WAIT_CMD), /*unused*/ \
- F(FTRACE_CPU_RUN_CYCLE), /*unused*/ \
- F(FTRACE_CPU_FLUSH), \
- F(FTRACE_CPU_BUFFER_WATERMARK), \
- F(READ_SYS_STATS), \
- F(PS_WRITE_ALL_PROCESSES), \
- F(PS_ON_PIDS), \
- F(PS_ON_RENAME_PIDS), \
- F(PS_WRITE_ALL_PROCESS_STATS), \
- F(TRACE_WRITER_COMMIT_STARTUP_WRITER_BATCH), \
- F(FTRACE_READ_TICK), \
- F(FTRACE_CPU_READ_CYCLE), \
- F(FTRACE_CPU_READ_BATCH), \
- F(KALLSYMS_PARSE), \
- F(PROFILER_READ_TICK), \
- F(PROFILER_READ_CPU), \
- F(PROFILER_UNWIND_TICK), \
- F(PROFILER_UNWIND_SAMPLE), \
- F(PROFILER_UNWIND_INITIAL_ATTEMPT), \
- F(PROFILER_UNWIND_ATTEMPT), \
- F(PROFILER_MAPS_PARSE), \
- F(PROFILER_MAPS_REPARSE), \
- F(PROFILER_UNWIND_CACHE_CLEAR), \
- F(ANDROID_CPU_PER_UID_TICK), \
- F(ANDROID_KERNEL_WAKELOCKS_TICK), \
- F(ANDROID_POWER_TICK), \
- F(ANDROID_POWER_WRITE_BATTERY_COUNTERS), \
- F(ANDROID_POWER_WRITE_ENERGY_ESTIMATION_BREAKDOWN), \
- F(ANDROID_POWER_WRITE_ENTITY_STATE_RESIDENCY), \
- F(ANDROID_POWER_WRITE_POWER_RAILS_DATA), \
- F(LINUX_POWER_SYSFS_TICK)
+ PERFETTO_ALWAYS_INLINE std::pair<Value*, bool> Insert(const Key& key,
+ Value value) {
+ return InsertImpl(key, std::move(value));
+ }
+ PERFETTO_ALWAYS_INLINE std::pair<Value*, bool> Insert(Key&& key,
+ Value value) {
+ return InsertImpl(std::move(key), std::move(value));
+ }
+ // Constructs the Key only if |key| is absent.
+ template <typename K, typename = std::enable_if_t<IsHeterogeneousKey<K>()>>
+ PERFETTO_ALWAYS_INLINE std::pair<Value*, bool> Insert(K&& key, Value value) {
+ return InsertImpl(std::forward<K>(key), std::move(value));
+ }
-// Append only, see above.
-//
-// Values that aren't used as counters:
-// * FTRACE_SERVICE_COMMIT_DATA is a bit-packed representation of an event, see
-// tracing_service_impl.cc for the format.
-// * PROFILER_UNWIND_CURRENT_PID represents the PID that is being unwound.
-// * WATCHDOG_CRASH_REASON represents the base::WatchdogCrashReason enum.
-// * WATCHDOG_CRASH_TIME_BOOT_MS The time in ms since boot when the watchdog
-// timeout alarm triggered (i.e. when it would have caused a crash, without
-// counting for the optional handler time).
-// * WATCHDOG_CRASH_ACTUAL_{MONO,BOOT,CPU} are the elapsed seconds (since the
-// offending fatal timer was created) sampled from CLOCK_MONOTONIC,
-// CLOCK_BOOTTIME and CLOCK_PROCESS_CPUTIME_ID respectively.
-//
-#define PERFETTO_METATRACE_COUNTERS(F) \
- F(COUNTER_ZERO_UNUSED),\
- F(FTRACE_PAGES_DRAINED), \
- F(PS_PIDS_SCANNED), \
- F(TRACE_SERVICE_COMMIT_DATA), \
- F(PROFILER_UNWIND_QUEUE_SZ), \
- F(PROFILER_UNWIND_CURRENT_PID), \
- F(WATCHDOG_CRASH_REASON), \
- F(WATCHDOG_CRASH_TIME_BOOT_MS), \
- F(WATCHDOG_CRASH_ACTUAL_MONO), \
- F(WATCHDOG_CRASH_ACTUAL_BOOT), \
- F(WATCHDOG_CRASH_ACTUAL_CPU), \
- F(FTRACE_SESSIONS)
+ Value& operator[](const Key& key) { return *Insert(key, Value{}).first; }
+ Value& operator[](Key&& key) {
+ return *Insert(std::move(key), Value{}).first;
+ }
+ template <typename K, typename = std::enable_if_t<IsHeterogeneousKey<K>()>>
+ Value& operator[](K&& key) {
+ return *Insert(std::forward<K>(key), Value{}).first;
+ }
-// clang-format on
+ void Clear() {
+ // Avoid trivial heap operations on zero-capacity std::move()-d objects.
+ if (PERFETTO_UNLIKELY(capacity_ == 0)) {
+ return;
+ }
+ for (size_t i = 0; i < capacity_; ++i) {
+ const uint8_t tag = ctrl_[i];
+ if (tag == kFreeSlot || tag == kTombstone) {
+ continue;
+ }
+ slots()[i].key.~Key();
+ slots()[i].value.~Value();
+ }
+ Reset(capacity_, false);
+ }
-#define PERFETTO_METATRACE_IDENTITY(name) name
-#define PERFETTO_METATRACE_TOSTRING(name) #name
+ Iterator GetIterator() { return Iterator(ctrl_, ctrl_ + capacity_, slots()); }
+ Iterator GetIterator() const {
+ return Iterator(ctrl_, ctrl_ + capacity_, slots());
+ }
-enum Events : uint16_t {
- PERFETTO_METATRACE_EVENTS(PERFETTO_METATRACE_IDENTITY),
- EVENTS_MAX
-};
-constexpr char const* kEventNames[] = {
- PERFETTO_METATRACE_EVENTS(PERFETTO_METATRACE_TOSTRING)};
+ size_t size() const { return size_; }
+ size_t capacity() const { return capacity_; }
-enum Counters : uint16_t {
- PERFETTO_METATRACE_COUNTERS(PERFETTO_METATRACE_IDENTITY),
- COUNTERS_MAX
-};
-constexpr char const* kCounterNames[] = {
- PERFETTO_METATRACE_COUNTERS(PERFETTO_METATRACE_TOSTRING)};
+ private:
+ // Result struct for FindOrPrepareInsert - avoids bit manipulation overhead
+ struct FindResult {
+ uint64_t idx : 63;
+ uint64_t needs_insert : 1;
+ };
-inline void SuppressUnusedVarsInAmalgamatedBuild() {
- (void)kCounterNames;
- (void)kEventNames;
-}
+ // Not found sentinel (must fit in 63-bit FindResult.idx)
+ static constexpr size_t kNotFound = std::numeric_limits<size_t>::max() >> 1;
-} // namespace metatrace
-} // namespace perfetto
+ using Group = flat_hash_map_v2_internal::Group;
-#endif // INCLUDE_PERFETTO_EXT_BASE_METATRACE_EVENTS_H_
-/*
- * 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.
- */
-
-#ifndef INCLUDE_PERFETTO_EXT_BASE_METATRACE_H_
-#define INCLUDE_PERFETTO_EXT_BASE_METATRACE_H_
-
-#include <array>
-#include <atomic>
-#include <functional>
-#include <string>
-
-// gen_amalgamated expanded: #include "perfetto/base/logging.h"
-// gen_amalgamated expanded: #include "perfetto/base/thread_utils.h"
-// gen_amalgamated expanded: #include "perfetto/base/time.h"
-// gen_amalgamated expanded: #include "perfetto/ext/base/metatrace_events.h"
-// gen_amalgamated expanded: #include "perfetto/ext/base/utils.h"
-
-// A facility to trace execution of the perfetto codebase itself.
-// The meta-tracing framework is organized into three layers:
-//
-// 1. A static ring-buffer in base/ (this file) that supports concurrent writes
-// and a single reader.
-// The responsibility of this layer is to store events and counters as
-// efficiently as possible without re-entering any tracing code.
-// This is really a static-storage-based ring-buffer based on a POD array.
-// This layer does NOT deal with serializing the meta-trace buffer.
-// It posts a task when it's half full and expects something outside of
-// base/ to drain the ring-buffer and serialize it, eventually writing it
-// into the trace itself, before it gets 100% full.
-//
-// 2. A class in tracing/core which takes care of serializing the meta-trace
-// buffer into the trace using a TraceWriter. See metatrace_writer.h .
-//
-// 3. A data source in traced_probes that, when be enabled via the trace config,
-// injects metatrace events into the trace. See metatrace_data_source.h .
-//
-// The available events and tags are defined in metatrace_events.h .
-
-namespace perfetto {
+ // Searches for a key in the table. This function IGNORES tombstones during
+ // the search - it only stops at empty slots (kFreeSlot) or matching keys.
+ //
+ // Why ignore tombstones? In Swiss Tables, tombstones mark deleted entries but
+ // must be skipped during lookup because the key we're searching for may have
+ // been inserted AFTER the tombstone was created (i.e., the key's probe
+ // sequence may have skipped over that tombstone). Only an empty slot
+ // definitively proves the key doesn't exist.
+ //
+ // Returns FindResult with idx and whether the key needs to be inserted:
+ // - If key is found: {idx, false} where idx is the slot containing the key.
+ // - If key not found and ForInsert=true: {empty_idx, true} where empty_idx
+ // is the index of the first EMPTY slot encountered.
+ // - If key not found and ForInsert=false: {kNotFound, true}.
+ //
+ // IMPORTANT for insertion (ForInsert=true): The returned empty_idx is NOT
+ // necessarily the best slot to insert into! There may be an earlier tombstone
+ // in the probe sequence that should be reused to avoid wasting slots. When
+ // has_tombstones is set, the caller must make a SECOND pass by calling
+ // FindFirstEmptyOrTombstone() to find the actual insertion slot.
+ template <bool ForInsert, typename K = Key>
+ PERFETTO_ALWAYS_INLINE FindResult
+ FindSlotIgnoringTombstones(const K& key, size_t key_hash, uint8_t h2) const {
+ static_assert(
+ flat_hash_map_v2_internal::IsLookupKeyAllowed<K, Key, Hasher, Eq>(),
+ "Heterogeneous lookup requires Hasher to define is_transparent and "
+ "support hashing the lookup key type, and Eq to compare Key and K. "
+ "Without a transparent Hasher, K must be convertible to Key.");
-namespace base {
-class TaskRunner;
-} // namespace base
+ if (PERFETTO_UNLIKELY(ctrl_ == nullptr)) {
+ return {kNotFound, true};
+ }
-namespace metatrace {
+ const size_t cap_mask = capacity_ - 1;
+ size_t offset = H1(key_hash) & cap_mask;
+ size_t probe_size = 0;
+ const uint8_t* ctrl = ctrl_;
-// Meta-tracing is organized in "tags" that can be selectively enabled. This is
-// to enable meta-tracing only of one sub-system. This word has one "enabled"
-// bit for each tag. 0 -> meta-tracing off.
-extern std::atomic<uint32_t> g_enabled_tags;
+ // Prefetch control bytes (like Absl's prefetch_heap_block).
+ // Use locality hint 3 (high temporal locality) for better L1 cache usage.
+ __builtin_prefetch(ctrl_ + offset, 0, 3);
-// Time of the Enable() call. Used as a reference for keeping delta timestmaps
-// in Record.
-extern std::atomic<uint64_t> g_enabled_timestamp;
+ while (true) {
+ // Prefetch slots at current probe offset (like Absl).
+ __builtin_prefetch(slots() + offset, 0, 3);
-// Enables meta-tracing for one or more tags. Once enabled it will discard any
-// further Enable() calls and return false until disabled,
-// |read_task| is a closure that will be called enqueued |task_runner| when the
-// meta-tracing ring buffer is half full. The task is expected to read the ring
-// buffer using RingBuffer::GetReadIterator() and serialize the contents onto a
-// file or into the trace itself.
-// Must be called on the |task_runner| passed.
-// |task_runner| must have static lifetime.
-bool Enable(std::function<void()> read_task, base::TaskRunner*, uint32_t tags);
+ Group group(ctrl + offset);
-// Disables meta-tracing.
-// Must be called on the same |task_runner| as Enable().
-void Disable();
+ // Match H2 tags in this group.
+ for (auto it = group.Match(h2); PERFETTO_LIKELY(it);) {
+ // Must mask because offset + it.Next() can exceed capacity when
+ // group straddles the table boundary (using cloned control bytes).
+ size_t idx = (offset + it.Next()) & cap_mask;
+ if (PERFETTO_LIKELY(Eq{}(slots()[idx].key, key))) {
+ return {idx, false}; // Found
+ }
+ }
-inline uint64_t TraceTimeNowNs() {
- return static_cast<uint64_t>(base::GetBootTimeNs().count());
-}
+ // Check for empty slot (NOT tombstones). If we find an empty slot, the
+ // key cannot exist in the table (empty slots terminate probe chains).
+ if (auto it = group.MatchEmpty(); PERFETTO_LIKELY(it)) {
+ if constexpr (ForInsert) {
+ size_t empty_idx = (offset + it.Next()) & cap_mask;
+ return {empty_idx, true}; // Not found - empty slot for insertion
+ } else {
+ return {kNotFound, true}; // Not found - no need to compute slot
+ }
+ }
-// Returns a relaxed view of whether metatracing is enabled for the given tag.
-// Useful for skipping unnecessary argument computation if metatracing is off.
-inline bool IsEnabled(uint32_t tag) {
- auto enabled_tags = g_enabled_tags.load(std::memory_order_relaxed);
- return PERFETTO_UNLIKELY((enabled_tags & tag) != 0);
-}
+ // Triangular probing (like Absl): 0, 16, 48, 96, ...
+ probe_size += Group::kSize;
+ offset = (offset + probe_size) & cap_mask;
-// Holds the data for a metatrace event or counter.
-struct Record {
- static constexpr uint16_t kTypeMask = 0x8000;
- static constexpr uint16_t kTypeCounter = 0x8000;
- static constexpr uint16_t kTypeEvent = 0;
+ // Should never happen with load limit.
+ PERFETTO_DCHECK(probe_size <= capacity_);
+ }
+ }
- uint64_t timestamp_ns() const {
- auto base_ns = g_enabled_timestamp.load(std::memory_order_relaxed);
- PERFETTO_DCHECK(base_ns);
- return base_ns + ((static_cast<uint64_t>(timestamp_ns_high) << 32) |
- timestamp_ns_low);
+ // Only constructing the key and value is inlined: finding the slot is out of
+ // line in FindOrPrepareInsert(), compiled once per lookup key type rather
+ // than per call site or per value category of |key|.
+ template <typename K>
+ PERFETTO_ALWAYS_INLINE std::pair<Value*, bool> InsertImpl(K&& key,
+ Value&& value) {
+ const std::remove_reference_t<K>& lookup_key = key;
+ FindResult res = FindOrPrepareInsert(lookup_key);
+ Slot* slot = &slots()[res.idx];
+ const bool inserted = res.needs_insert;
+ if (inserted) {
+ new (&slot->key) Key(std::forward<K>(key));
+ new (&slot->value) Value(std::move(value));
+ }
+ return {&slot->value, inserted};
}
- void set_timestamp(uint64_t ts) {
- auto t_start = g_enabled_timestamp.load(std::memory_order_relaxed);
- uint64_t diff = ts - t_start;
- PERFETTO_DCHECK(diff < (1ull << 48));
- timestamp_ns_low = static_cast<uint32_t>(diff);
- timestamp_ns_high = static_cast<uint16_t>(diff >> 32);
+ // Out of line, compiled once per lookup key type.
+ template <typename K>
+ PERFETTO_NO_INLINE Value* FindImpl(const K& key) const {
+ size_t key_hash = Hasher{}(key);
+ uint8_t h2 = H2(key_hash);
+ FindResult res = FindSlotIgnoringTombstones<false>(key, key_hash, h2);
+ if (PERFETTO_UNLIKELY(res.needs_insert)) {
+ return nullptr;
+ }
+ return &slots()[res.idx].value;
}
- // We can't just memset() this class because on MSVC std::atomic<> is not
- // trivially constructible anymore. Also std::atomic<> has a deleted copy
- // constructor so we cant just do "*this = Record()" either.
- // See http://bit.ly/339Jlzd .
- void clear() {
- this->~Record();
- new (this) Record();
+ template <typename K>
+ PERFETTO_NO_INLINE bool EraseImpl(const K& key) {
+ size_t key_hash = Hasher{}(key);
+ uint8_t h2 = H2(key_hash);
+ FindResult res = FindSlotIgnoringTombstones<false>(key, key_hash, h2);
+ if (PERFETTO_UNLIKELY(res.needs_insert)) {
+ return false;
+ }
+ PERFETTO_DCHECK(size_ > 0);
+ SetCtrl(res.idx, kTombstone);
+ slots()[res.idx].key.~Key();
+ slots()[res.idx].value.~Value();
+ size_--;
+ growth_info_.has_tombstones = 1;
+ return true;
}
- // This field holds the type (counter vs event) in the MSB and event ID (as
- // defined in metatrace_events.h) in the lowest 15 bits. It is also used also
- // as a linearization point: this is always written after all the other
- // fields with a release-store. This is so the reader can determine whether it
- // can safely process the other event fields after a load-acquire.
- std::atomic<uint16_t> type_and_id{};
+ // Returns the slot holding |key| if present. Otherwise claims a slot for it,
+ // growing the table if needed, and the caller must construct into it.
+ template <typename K>
+ PERFETTO_NO_INLINE FindResult FindOrPrepareInsert(const K& key) {
+ size_t key_hash = Hasher{}(key);
+ uint8_t h2 = H2(key_hash);
+ FindResult res = FindSlotIgnoringTombstones<true>(key, key_hash, h2);
+ if (PERFETTO_UNLIKELY(!res.needs_insert)) {
+ return res;
+ }
+ if (PERFETTO_UNLIKELY(growth_info_.growth_left == 0)) {
+ GrowAndRehash();
+ // After rehash, table has no tombstones. Find an empty slot directly
+ // instead of recursing (which would prevent inlining).
+ res.idx = FindFirstEmptyOrTombstone(key_hash);
+ }
+ PERFETTO_DCHECK(res.idx != kNotFound);
+ size_t insert_idx = res.idx;
+ bool is_freeslot = true;
+ if (PERFETTO_UNLIKELY(growth_info_.has_tombstones)) {
+ insert_idx = FindFirstEmptyOrTombstone(key_hash);
+ is_freeslot = ctrl_[insert_idx] != kTombstone;
+ }
+ SetCtrl(insert_idx, h2);
+ size_++;
+ if (is_freeslot) {
+ growth_info_.growth_left--;
+ }
+ return {insert_idx, true};
+ }
- // Timestamp is stored as a 48-bits value diffed against g_enabled_timestamp.
- // This gives us 78 hours from Enabled().
- uint16_t timestamp_ns_high = 0;
- uint32_t timestamp_ns_low = 0;
+ // Allocating the new table is shared by all maps in Grow(): only moving the
+ // entries over, which needs their types, is compiled per map.
+ PERFETTO_NO_INLINE void GrowAndRehash() {
+ OldTable old = Grow(sizeof(Slot), alignof(Slot));
+ Slot* old_slots = reinterpret_cast<Slot*>(old.slots);
+ // Keys are unique and the new table has no tombstones, so each entry goes
+ // straight into the first empty slot of its probe sequence.
+ size_t new_size = 0;
+ for (size_t i = 0; i < old.capacity; ++i) {
+ if (uint8_t t = old.ctrl[i]; t == kFreeSlot || t == kTombstone) {
+ continue;
+ }
+ Slot& old_slot = old_slots[i];
+ size_t key_hash = Hasher{}(old_slot.key);
+ size_t idx = FindFirstEmptyOrTombstoneImpl(key_hash);
+ new (&slots()[idx].key) Key(std::move(old_slot.key));
+ new (&slots()[idx].value) Value(std::move(old_slot.value));
+ SetCtrl(idx, H2(key_hash));
+ old_slot.key.~Key(); // Destroy the old objects.
+ old_slot.value.~Value();
+ new_size++;
+ }
+ PERFETTO_DCHECK(new_size == old.size);
+ FinishGrow(new_size);
+ }
- uint32_t thread_id = 0;
+ // Doesn't call destructors. Use Clear() for that.
+ void Reset(size_t n, bool reallocate) {
+ FlatHashMapV2Base::Reset(n, reallocate, sizeof(Slot), alignof(Slot));
+ }
- union {
- // Only one of the two elements can be zero initialized, clang complains
- // about "initializing multiple members of union" otherwise.
- uint32_t duration_ns = 0; // If type == event.
- int32_t counter_value; // If type == counter.
- };
+ PERFETTO_ALWAYS_INLINE Slot* slots() const {
+ return reinterpret_cast<Slot*>(slots_);
+ }
};
-// Hold the meta-tracing data into a statically allocated array.
-// This class uses static storage (as opposite to being a singleton) to:
-// - Have the guarantee of always valid storage, so that meta-tracing can be
-// safely used in any part of the codebase, including base/ itself.
-// - Avoid barriers that thread-safe static locals would require.
-class RingBuffer {
- public:
- static constexpr size_t kCapacity = 4096; // 4096 * 16 bytes = 64K.
-
- // This iterator is not idempotent and will bump the read index in the buffer
- // at the end of the reads. There can be only one reader at any time.
- // Usage: for (auto it = RingBuffer::GetReadIterator(); it; ++it) { it->... }
- class ReadIterator {
- public:
- ReadIterator(ReadIterator&& other) {
- PERFETTO_DCHECK(other.valid_);
- cur_ = other.cur_;
- end_ = other.end_;
- valid_ = other.valid_;
- other.valid_ = false;
- }
+// Alias FlatHashMap to FlatHashMapV1 for backward compatibility.
+//
+// TODO(lalitm): Once FlatHashMapV2 is fully tested and verified, switch this
+// to FlatHashMapV2.
+template <typename Key,
+ typename Value,
+ typename Hasher = MurmurHash<Key>,
+ typename Probe = QuadraticProbe,
+ bool AppendOnly = false>
+using FlatHashMap = FlatHashMapV1<Key, Value, Hasher, Probe, AppendOnly>;
- ~ReadIterator() {
- if (!valid_)
- return;
- PERFETTO_DCHECK(cur_ >= RingBuffer::rd_index_);
- PERFETTO_DCHECK(cur_ <= RingBuffer::wr_index_);
- RingBuffer::rd_index_.store(cur_, std::memory_order_release);
- }
+} // namespace perfetto::base
- explicit operator bool() const { return cur_ < end_; }
- const Record* operator->() const { return RingBuffer::At(cur_); }
- const Record& operator*() const { return *operator->(); }
+#endif // INCLUDE_PERFETTO_EXT_BASE_FLAT_HASH_MAP_H_
+/*
+ * Copyright (C) 2026 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.
+ */
- // This is for ++it. it++ is deliberately not supported.
- ReadIterator& operator++() {
- PERFETTO_DCHECK(cur_ < end_);
- // Once a record has been read, mark it as free clearing its type_and_id,
- // so if we encounter it in another read iteration while being written
- // we know it's not fully written yet.
- // The memory_order_relaxed below is enough because:
- // - The reader is single-threaded and doesn't re-read the same records.
- // - Before starting a read batch, the reader has an acquire barrier on
- // |rd_index_|.
- // - After terminating a read batch, the ~ReadIterator dtor updates the
- // |rd_index_| with a release-store.
- // - Reader and writer are typically kCapacity/2 apart. So unless an
- // overrun happens a writer won't reuse a newly released record any time
- // soon. If an overrun happens, everything is busted regardless.
- At(cur_)->type_and_id.store(0, std::memory_order_relaxed);
- ++cur_;
- return *this;
- }
+// gen_amalgamated expanded: #include "perfetto/ext/base/flat_hash_map.h"
- private:
- friend class RingBuffer;
- ReadIterator(uint64_t begin, uint64_t end)
- : cur_(begin), end_(end), valid_(true) {}
- ReadIterator& operator=(const ReadIterator&) = delete;
- ReadIterator(const ReadIterator&) = delete;
+#include <algorithm>
+#include <cstddef>
+#include <cstdint>
+#include <cstring>
+#include <memory>
+#include <utility>
- uint64_t cur_;
- uint64_t end_;
- bool valid_;
- };
+// gen_amalgamated expanded: #include "perfetto/base/logging.h"
+// gen_amalgamated expanded: #include "perfetto/ext/base/utils.h"
- static Record* At(uint64_t index) {
- // Doesn't really have to be pow2, but if not the compiler will emit
- // arithmetic operations to compute the modulo instead of a bitwise AND.
- static_assert(!(kCapacity & (kCapacity - 1)), "kCapacity must be pow2");
- PERFETTO_DCHECK(index >= rd_index_);
- PERFETTO_DCHECK(index <= wr_index_);
- return &records_[index % kCapacity];
- }
+namespace perfetto::base::flat_hash_map_v2_internal {
- // Must be called on the same task runner passed to Enable()
- static ReadIterator GetReadIterator() {
- PERFETTO_DCHECK(RingBuffer::IsOnValidTaskRunner());
- return ReadIterator(rd_index_.load(std::memory_order_acquire),
- wr_index_.load(std::memory_order_acquire));
- }
+void FlatHashMapV2Base::Reset(size_t n,
+ bool reallocate,
+ size_t slot_size,
+ size_t slot_align) {
+ // Must be a pow2.
+ PERFETTO_CHECK((n & (n - 1)) == 0);
- static Record* AppendNewRecord();
- static void Reset();
+ // Always ensure at least 128 capacity to avoid too frequent growths.
+ capacity_ = std::max<size_t>(n, 128u);
+ size_ = 0;
+ growth_info_.growth_left =
+ (capacity_ * static_cast<size_t>(load_limit_percent_)) / 100;
+ growth_info_.has_tombstones = 0;
- static bool has_overruns() {
- return has_overruns_.load(std::memory_order_acquire);
+ if (reallocate) {
+ // See memory layout comment above |storage_| in flat_hash_map.h.
+ size_t slots_offset = base::AlignUp(capacity_ + kNumClones, slot_align);
+ storage_.reset(new uint8_t[slots_offset + (capacity_ * slot_size)]);
+ ctrl_ = storage_.get();
+ slots_ = storage_.get() + slots_offset;
}
-
- // Can temporarily return a value >= kCapacity but is eventually consistent.
- // This would happen in case of overruns until threads hit the --wr_index_
- // in AppendNewRecord().
- static uint64_t GetSizeForTesting() {
- auto wr_index = wr_index_.load(std::memory_order_relaxed);
- auto rd_index = rd_index_.load(std::memory_order_relaxed);
- PERFETTO_DCHECK(wr_index >= rd_index);
- return wr_index - rd_index;
+ if (ctrl_) {
+ // Initialize all control bytes (including clones) to empty (kFreeSlot)
+ memset(ctrl_, kFreeSlot, capacity_ + kNumClones);
}
+}
- private:
- friend class ReadIterator;
+size_t FlatHashMapV2Base::FindFirstEmptyOrTombstone(size_t key_hash) const {
+ return FindFirstEmptyOrTombstoneImpl(key_hash);
+}
- // Returns true if the caller is on the task runner passed to Enable().
- // Used only for DCHECKs.
- static bool IsOnValidTaskRunner();
+FlatHashMapV2Base::OldTable FlatHashMapV2Base::Grow(size_t slot_size,
+ size_t slot_align) {
+ PERFETTO_DCHECK(size_ <= capacity_);
+ OldTable old{std::move(storage_), ctrl_, slots_, capacity_, size_};
+ // This must be a CHECK (i.e. not just a DCHECK) to prevent UAF attacks on
+ // 32-bit archs that try to double the size of the table until wrapping.
+ size_t new_capacity = capacity_ * 2;
+ PERFETTO_CHECK(new_capacity >= capacity_);
+ Reset(new_capacity, true, slot_size, slot_align);
+ return old;
+}
- static std::array<Record, kCapacity> records_;
- static std::atomic<bool> read_task_queued_;
- static std::atomic<uint64_t> wr_index_;
- static std::atomic<uint64_t> rd_index_;
- static std::atomic<bool> has_overruns_;
- static Record bankruptcy_record_; // Used in case of overruns.
-};
+} // namespace perfetto::base::flat_hash_map_v2_internal
+// gen_amalgamated begin source: src/base/futex.cc
+// gen_amalgamated begin header: include/perfetto/ext/base/futex.h
+/*
+ * Copyright (C) 2026 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.
+ */
-inline void TraceCounter(uint32_t tag, uint16_t id, int32_t value) {
- // memory_order_relaxed is okay because the storage has static lifetime.
- // It is safe to accidentally log an event soon after disabling.
- auto enabled_tags = g_enabled_tags.load(std::memory_order_relaxed);
- if (PERFETTO_LIKELY((enabled_tags & tag) == 0))
- return;
- Record* record = RingBuffer::AppendNewRecord();
- record->thread_id = static_cast<uint32_t>(base::GetThreadId());
- record->set_timestamp(TraceTimeNowNs());
- record->counter_value = value;
- record->type_and_id.store(Record::kTypeCounter | id,
- std::memory_order_release);
-}
+#ifndef INCLUDE_PERFETTO_EXT_BASE_FUTEX_H_
+#define INCLUDE_PERFETTO_EXT_BASE_FUTEX_H_
-class ScopedEvent {
- public:
- ScopedEvent(uint32_t tag, uint16_t event_id) {
- auto enabled_tags = g_enabled_tags.load(std::memory_order_relaxed);
- if (PERFETTO_LIKELY((enabled_tags & tag) == 0))
- return;
- event_id_ = event_id;
- record_ = RingBuffer::AppendNewRecord();
- record_->thread_id = static_cast<uint32_t>(base::GetThreadId());
- record_->set_timestamp(TraceTimeNowNs());
- }
+#include <stdint.h>
- ~ScopedEvent() {
- if (PERFETTO_LIKELY(!record_))
- return;
- auto now = TraceTimeNowNs();
- record_->duration_ns = static_cast<uint32_t>(now - record_->timestamp_ns());
- record_->type_and_id.store(Record::kTypeEvent | event_id_,
- std::memory_order_release);
- }
+// gen_amalgamated expanded: #include "perfetto/base/build_config.h"
- private:
- Record* record_ = nullptr;
- uint16_t event_id_ = 0;
- ScopedEvent(const ScopedEvent&) = delete;
- ScopedEvent& operator=(const ScopedEvent&) = delete;
-};
+// Whether this build implements FutexWait() and FutexWake(). It does not check
+// runtime restrictions, such as a sandbox that blocks the system call.
+// TODO(rsavitski): Add support for other platforms.
+#define PERFETTO_HAS_FUTEX() \
+ (PERFETTO_BUILDFLAG(PERFETTO_OS_LINUX_BUT_NOT_QNX) || \
+ PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID))
-// Boilerplate to derive a unique variable name for the event.
-#define PERFETTO_METATRACE_UID2(a, b) a##b
-#define PERFETTO_METATRACE_UID(x) PERFETTO_METATRACE_UID2(metatrace_, x)
+namespace perfetto::base {
-#define PERFETTO_METATRACE_SCOPED(TAG, ID) \
- ::perfetto::metatrace::ScopedEvent PERFETTO_METATRACE_UID(__COUNTER__)( \
- ::perfetto::metatrace::TAG, ::perfetto::metatrace::ID)
+// Futex operations wait and wake threads on a 32-bit word in memory. A waiter
+// sleeps if the word matches an expected value. Another thread can update the
+// word and wake waiters to recheck their condition.
+//
+// These operations also work across processes when the word is in shared
+// memory. Each process uses its own address for the same backing storage.
+//
+// Neither operation modifies the word or provides C++ memory ordering. Callers
+// must use atomic accesses and the memory ordering required by their protocol.
+// To avoid lost wakeups, update the word before calling FutexWake().
+// Wakeups are not remembered for subsequent waits.
+//
+// Implemented on Linux and Android. Use PERFETTO_HAS_FUTEX() to select a
+// fallback on other platforms.
+
+enum class FutexWaitResult {
+ // The wait returned after a wake. The wake can be spurious, so the word can
+ // still hold the expected value.
+ kWoken,
+ // The word did not match the expected value when checked before sleeping.
+ kValueMismatch,
+ // The relative timeout expired.
+ kTimedOut,
+ // The wait was interrupted, for example by a signal. It was not retried.
+ kInterrupted,
+ // The operation failed, including on unsupported platforms. May indicate
+ // invalid arguments or runtime restrictions. Do not blindly retry.
+ kError,
+};
-#define PERFETTO_METATRACE_COUNTER(TAG, ID, VALUE) \
- ::perfetto::metatrace::TraceCounter(::perfetto::metatrace::TAG, \
- ::perfetto::metatrace::ID, \
- static_cast<int32_t>(VALUE))
+// Makes one attempt to sleep if |word| contains |expected_value|. The value
+// check and the start of the wait are atomic with respect to FutexWake().
+// Returns kValueMismatch without sleeping if the value does not match.
+//
+// |timeout_ms| is a relative timeout in milliseconds. Zero causes no wait.
+// Scheduling can delay the return beyond the timeout.
+//
+// Recheck the caller's condition after every result other than kError,
+// including kWoken. Interruptions and spurious wakes are not retried. A retry
+// loop with an overall deadline must compute the remaining timeout each time.
+//
+// |word| requirements:
+// - It is 4-byte aligned and stays mapped until the call returns.
+// - Only the kernel reads it. This call makes no C++ load of it.
+// - Every write to it is one atomic store that covers all 32 bits. For
+// example, a std::atomic<uint32_t> store, or a lock-free
+// std::atomic<uint64_t> store that contains the word.
+//
+// Returns kError without sleeping on unsupported platforms.
+FutexWaitResult FutexWait(const uint32_t* word,
+ uint32_t expected_value,
+ uint32_t timeout_ms);
+
+// Wakes up to |max_waiters| threads waiting on |word|, including waiters in
+// other processes that share the same storage.
+// |max_waiters| must be positive. Use INT_MAX to wake all waiters.
+//
+// |word| has the same storage requirements as FutexWait().
+// Returns the number of waiters woken, or -1 on failure or unsupported
+// platforms.
+int FutexWake(const uint32_t* word, int max_waiters);
-} // namespace metatrace
-} // namespace perfetto
+} // namespace perfetto::base
-#endif // INCLUDE_PERFETTO_EXT_BASE_METATRACE_H_
+#endif // INCLUDE_PERFETTO_EXT_BASE_FUTEX_H_
/*
- * Copyright (C) 2018 The Android Open Source Project
+ * Copyright (C) 2026 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.
@@ -6611,136 +6960,93 @@ class ScopedEvent {
* limitations under the License.
*/
-// gen_amalgamated expanded: #include "perfetto/ext/base/metatrace.h"
+// gen_amalgamated expanded: #include "perfetto/ext/base/futex.h"
-// gen_amalgamated expanded: #include "perfetto/base/compiler.h"
-// gen_amalgamated expanded: #include "perfetto/base/task_runner.h"
-// gen_amalgamated expanded: #include "perfetto/base/time.h"
-// gen_amalgamated expanded: #include "perfetto/ext/base/file_utils.h"
-// gen_amalgamated expanded: #include "perfetto/ext/base/thread_annotations.h"
+// gen_amalgamated expanded: #include "perfetto/base/build_config.h"
+// gen_amalgamated expanded: #include "perfetto/base/logging.h"
+// gen_amalgamated expanded: #include "perfetto/ext/base/utils.h"
-namespace perfetto {
-namespace metatrace {
+#if PERFETTO_HAS_FUTEX()
+#include <errno.h>
+#include <linux/futex.h>
+#include <linux/types.h>
+#include <sys/syscall.h>
+#include <unistd.h>
+#endif
-std::atomic<uint32_t> g_enabled_tags{0};
-std::atomic<uint64_t> g_enabled_timestamp{0};
+namespace perfetto::base {
-// static members
-std::array<Record, RingBuffer::kCapacity> RingBuffer::records_;
-std::atomic<bool> RingBuffer::read_task_queued_;
-std::atomic<uint64_t> RingBuffer::wr_index_;
-std::atomic<uint64_t> RingBuffer::rd_index_;
-std::atomic<bool> RingBuffer::has_overruns_;
-Record RingBuffer::bankruptcy_record_;
+#if PERFETTO_HAS_FUTEX()
-namespace {
+// Use the shared FUTEX_WAIT/FUTEX_WAKE operations so different mappings of the
+// same shared-memory word refer to the same wait queue across processes.
-// std::function<> is not trivially de/constructible. This struct wraps it in a
-// heap-allocated struct to avoid static initializers.
-struct Delegate {
- static Delegate* GetInstance() {
- static Delegate* instance = new Delegate();
- return instance;
+FutexWaitResult FutexWait(const uint32_t* word,
+ uint32_t expected_value,
+ uint32_t timeout_ms) {
+ // SYS_futex expects seconds and nanoseconds in two kernel-sized longs.
+ // Use that layout directly because libc's timespec can use a wider time_t.
+ // Even UINT32_MAX milliseconds fits in signed 32-bit seconds.
+ struct KernelTimespec {
+ __kernel_long_t tv_sec;
+ __kernel_long_t tv_nsec;
+ };
+ const KernelTimespec timeout{
+ static_cast<__kernel_long_t>(timeout_ms / 1000),
+ static_cast<__kernel_long_t>((timeout_ms % 1000) * 1000000)};
+ const int ret = static_cast<int>(syscall(
+ SYS_futex, word, FUTEX_WAIT, expected_value, &timeout, nullptr, 0));
+ if (ret == 0)
+ return FutexWaitResult::kWoken;
+
+ switch (errno) {
+ case EAGAIN:
+ return FutexWaitResult::kValueMismatch;
+ case ETIMEDOUT:
+ return FutexWaitResult::kTimedOut;
+ case EINTR:
+ return FutexWaitResult::kInterrupted;
+ default:
+ PERFETTO_DPLOG("futex FUTEX_WAIT failed");
+ return FutexWaitResult::kError;
}
+}
- base::TaskRunner* task_runner = nullptr;
- std::function<void()> read_task;
-};
+int FutexWake(const uint32_t* word, int max_waiters) {
+ PERFETTO_DCHECK(max_waiters > 0);
+ const int ret = static_cast<int>(
+ syscall(SYS_futex, word, FUTEX_WAKE, max_waiters, nullptr, nullptr, 0));
+ if (PERFETTO_UNLIKELY(ret < 0)) {
+ PERFETTO_DPLOG("futex FUTEX_WAKE failed");
+ return -1;
+ }
+ return ret;
+}
-} // namespace
+#else
-bool Enable(std::function<void()> read_task,
- base::TaskRunner* task_runner,
- uint32_t tags) {
- PERFETTO_DCHECK(read_task);
- PERFETTO_DCHECK(task_runner->RunsTasksOnCurrentThread());
- if (g_enabled_tags.load(std::memory_order_acquire))
- return false;
+FutexWaitResult FutexWait(const uint32_t* word,
+ uint32_t expected_value,
+ uint32_t timeout_ms) {
+ ignore_result(word);
+ ignore_result(expected_value);
+ ignore_result(timeout_ms);
+ return FutexWaitResult::kError;
+}
- Delegate* dg = Delegate::GetInstance();
- dg->task_runner = task_runner;
- dg->read_task = std::move(read_task);
- RingBuffer::Reset();
- g_enabled_timestamp.store(TraceTimeNowNs(), std::memory_order_relaxed);
- g_enabled_tags.store(tags, std::memory_order_release);
- return true;
+int FutexWake(const uint32_t* word, int max_waiters) {
+ ignore_result(word);
+ ignore_result(max_waiters);
+ return -1;
}
-void Disable() {
- g_enabled_tags.store(0, std::memory_order_release);
- Delegate* dg = Delegate::GetInstance();
- PERFETTO_DCHECK(!dg->task_runner ||
- dg->task_runner->RunsTasksOnCurrentThread());
- dg->task_runner = nullptr;
- dg->read_task = nullptr;
-}
-
-// static
-void RingBuffer::Reset() {
- bankruptcy_record_.clear();
- for (Record& record : records_)
- record.clear();
- wr_index_ = 0;
- rd_index_ = 0;
- has_overruns_ = false;
- read_task_queued_ = false;
-}
-
-// static
-Record* RingBuffer::AppendNewRecord() {
- auto wr_index = wr_index_.fetch_add(1, std::memory_order_acq_rel);
-
- // rd_index can only monotonically increase, we don't care if we read an
- // older value, we'll just hit the slow-path a bit earlier if it happens.
- auto rd_index = rd_index_.load(std::memory_order_relaxed);
-
- PERFETTO_DCHECK(wr_index >= rd_index);
- auto size = wr_index - rd_index;
- if (PERFETTO_LIKELY(size < kCapacity / 2))
- return At(wr_index);
-
- // Slow-path: Enqueue the read task and handle overruns.
- bool expected = false;
- if (RingBuffer::read_task_queued_.compare_exchange_strong(expected, true)) {
- Delegate* dg = Delegate::GetInstance();
- if (dg->task_runner) {
- dg->task_runner->PostTask([] {
- // Meta-tracing might have been disabled in the meantime.
- auto read_task = Delegate::GetInstance()->read_task;
- if (read_task)
- read_task();
- RingBuffer::read_task_queued_ = false;
- });
- }
- }
-
- if (PERFETTO_LIKELY(size < kCapacity))
- return At(wr_index);
-
- has_overruns_.store(true, std::memory_order_release);
- wr_index_.fetch_sub(1, std::memory_order_acq_rel);
-
- // In the case of overflows, threads will race writing on the same memory
- // location and TSan will rightly complain. This is fine though because nobody
- // will read the bankruptcy record and it's designed to contain garbage.
- PERFETTO_ANNOTATE_BENIGN_RACE_SIZED(&bankruptcy_record_, sizeof(Record),
- "nothing reads bankruptcy_record_")
- return &bankruptcy_record_;
-}
-
-// static
-bool RingBuffer::IsOnValidTaskRunner() {
- auto* task_runner = Delegate::GetInstance()->task_runner;
- return task_runner && task_runner->RunsTasksOnCurrentThread();
-}
+#endif // PERFETTO_HAS_FUTEX()
-} // namespace metatrace
-} // namespace perfetto
-// gen_amalgamated begin source: src/base/paged_memory.cc
-// gen_amalgamated begin header: include/perfetto/ext/base/paged_memory.h
-// gen_amalgamated begin header: include/perfetto/ext/base/container_annotations.h
+} // namespace perfetto::base
+// gen_amalgamated begin source: src/base/getopt_compat.cc
+// gen_amalgamated begin header: include/perfetto/ext/base/getopt_compat.h
/*
- * Copyright (C) 2018 The Android Open Source Project
+ * Copyright (C) 2021 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.
@@ -6755,51 +7061,63 @@ bool RingBuffer::IsOnValidTaskRunner() {
* limitations under the License.
*/
-#ifndef INCLUDE_PERFETTO_EXT_BASE_CONTAINER_ANNOTATIONS_H_
-#define INCLUDE_PERFETTO_EXT_BASE_CONTAINER_ANNOTATIONS_H_
+#ifndef INCLUDE_PERFETTO_EXT_BASE_GETOPT_COMPAT_H_
+#define INCLUDE_PERFETTO_EXT_BASE_GETOPT_COMPAT_H_
-// gen_amalgamated expanded: #include "perfetto/base/build_config.h"
+#include <cstddef> // For std::nullptr_t
-// Windows ASAN doesn't currently support these annotations.
-#if defined(ADDRESS_SANITIZER) && !PERFETTO_BUILDFLAG(PERFETTO_OS_WIN) && \
- !defined(ADDRESS_SANITIZER_WITHOUT_INSTRUMENTATION)
+// No translation units other than base/getopt.h and getopt_compat_unittest.cc
+// should directly include this file. Use base/getopt.h instead.
-#include <sanitizer/common_interface_defs.h>
+namespace perfetto {
+namespace base {
+namespace getopt_compat {
-#define ANNOTATE_NEW_BUFFER(buffer, capacity, new_size) \
- if (buffer) { \
- __sanitizer_annotate_contiguous_container(buffer, (buffer) + (capacity), \
- (buffer) + (capacity), \
- (buffer) + (new_size)); \
- }
-#define ANNOTATE_DELETE_BUFFER(buffer, capacity, old_size) \
- if (buffer) { \
- __sanitizer_annotate_contiguous_container(buffer, (buffer) + (capacity), \
- (buffer) + (old_size), \
- (buffer) + (capacity)); \
- }
-#define ANNOTATE_CHANGE_SIZE(buffer, capacity, old_size, new_size) \
- if (buffer) { \
- __sanitizer_annotate_contiguous_container(buffer, (buffer) + (capacity), \
- (buffer) + (old_size), \
- (buffer) + (new_size)); \
- }
-#define ANNOTATE_CHANGE_CAPACITY(buffer, old_capacity, buffer_size, \
- new_capacity) \
- ANNOTATE_DELETE_BUFFER(buffer, old_capacity, buffer_size); \
- ANNOTATE_NEW_BUFFER(buffer, new_capacity, buffer_size);
-// Annotations require buffers to begin on an 8-byte boundary.
-#else // defined(ADDRESS_SANITIZER)
-#define ANNOTATE_NEW_BUFFER(buffer, capacity, new_size)
-#define ANNOTATE_DELETE_BUFFER(buffer, capacity, old_size)
-#define ANNOTATE_CHANGE_SIZE(buffer, capacity, old_size, new_size)
-#define ANNOTATE_CHANGE_CAPACITY(buffer, old_capacity, buffer_size, \
- new_capacity)
-#endif // defined(ADDRESS_SANITIZER)
+// A tiny getopt() replacement for Windows, which doesn't have <getopt.h>.
+// This implementation is based on the subset of features that we use in the
+// Perfetto codebase. It doesn't even try to deal with the full surface of GNU's
+// getopt().
+// Limitations:
+// - getopt_long_only() is not supported.
+// - optional_argument is not supported. That is extremely subtle and caused us
+// problems in the past with GNU's getopt.
+// - It does not reorder non-option arguments. It behaves like MacOS getopt, or
+// GNU's when POSIXLY_CORRECT=1.
+// - Doesn't expose optopt or opterr.
+// - option.flag and longindex are not supported and must be nullptr.
-#endif // INCLUDE_PERFETTO_EXT_BASE_CONTAINER_ANNOTATIONS_H_
+enum {
+ no_argument = 0,
+ required_argument = 1,
+};
+
+struct option {
+ const char* name;
+ int has_arg;
+ std::nullptr_t flag; // Only nullptr is supported.
+ int val;
+};
+
+extern char* optarg;
+extern int optind;
+extern int optopt;
+extern int opterr;
+
+int getopt_long(int argc,
+ char** argv,
+ const char* shortopts,
+ const option* longopts,
+ std::nullptr_t /*longindex is not supported*/);
+
+int getopt(int argc, char** argv, const char* shortopts);
+
+} // namespace getopt_compat
+} // namespace base
+} // namespace perfetto
+
+#endif // INCLUDE_PERFETTO_EXT_BASE_GETOPT_COMPAT_H_
/*
- * Copyright (C) 2017 The Android Open Source Project
+ * Copyright (C) 2021 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.
@@ -6814,97 +7132,289 @@ bool RingBuffer::IsOnValidTaskRunner() {
* limitations under the License.
*/
-#ifndef INCLUDE_PERFETTO_EXT_BASE_PAGED_MEMORY_H_
-#define INCLUDE_PERFETTO_EXT_BASE_PAGED_MEMORY_H_
+// gen_amalgamated expanded: #include "perfetto/ext/base/getopt_compat.h"
-#include <cstddef>
-#include <memory>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
-// gen_amalgamated expanded: #include "perfetto/base/build_config.h"
-// gen_amalgamated expanded: #include "perfetto/ext/base/container_annotations.h"
+#include <vector>
-// We need to track the committed size on windows and when ASAN is enabled.
-#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN) || defined(ADDRESS_SANITIZER)
-#define TRACK_COMMITTED_SIZE() 1
-#else
-#define TRACK_COMMITTED_SIZE() 0
-#endif
+// gen_amalgamated expanded: #include "perfetto/base/logging.h"
namespace perfetto {
namespace base {
+namespace getopt_compat {
-class PagedMemory {
- public:
- // Initializes an invalid PagedMemory pointing to nullptr.
- PagedMemory();
+char* optarg = nullptr;
+int optind = 0;
+int optopt = 0;
+int opterr = 1;
- ~PagedMemory();
+namespace {
- PagedMemory(PagedMemory&& other) noexcept;
- PagedMemory& operator=(PagedMemory&& other);
+char* nextchar = nullptr;
- enum AllocationFlags {
- // By default, Allocate() crashes if the underlying mmap fails (e.g., if out
- // of virtual address space). When this flag is provided, an invalid
- // PagedMemory pointing to nullptr is returned in this case instead.
- kMayFail = 1 << 0,
+const option* LookupLongOpt(const std::vector<option>& opts,
+ const char* name,
+ size_t len) {
+ for (const option& opt : opts) {
+ if (strncmp(opt.name, name, len) == 0 && strlen(opt.name) == len)
+ return &opt;
+ }
+ return nullptr;
+}
- // By default, Allocate() commits the allocated memory immediately. When
- // this flag is provided, the memory virtual address space may only be
- // reserved and the user should call EnsureCommitted() before writing to
- // memory addresses.
- kDontCommit = 1 << 1,
- };
+const option* LookupShortOpt(const std::vector<option>& opts, char c) {
+ for (const option& opt : opts) {
+ if (!*opt.name && opt.val == c)
+ return &opt;
+ }
+ return nullptr;
+}
- // Allocates |size| bytes using mmap(MAP_ANONYMOUS). The returned memory is
- // guaranteed to be page-aligned and guaranteed to be zeroed.
- // For |flags|, see the AllocationFlags enum above.
- static PagedMemory Allocate(size_t size, int flags = 0);
+// Returns true if |token| is an option-bearing argv element whose argument
+// is supplied by the next argv element (rather than embedded or absent).
+// Used by the GNU-style permutation logic in getopt_long().
+bool TokenConsumesNextArg(const char* token, const std::vector<option>& opts) {
+ if (token[0] != '-' || token[1] == '\0')
+ return false;
+ if (token[1] == '-') {
+ // Long option: "--name" needs a separate arg if it's required_argument
+ // and there is no embedded "=value".
+ if (token[2] == '\0')
+ return false; // "--" alone.
+ if (strchr(token + 2, '=') != nullptr)
+ return false;
+ size_t len = strlen(token + 2);
+ const option* opt = LookupLongOpt(opts, token + 2, len);
+ return opt && opt->has_arg == required_argument;
+ }
+ // Short option chain: "-abc" / "-aXYZ". Walk until we find an option that
+ // requires an argument; if it is the last character of the token, the next
+ // argv element is the argument. Anything after it would be the embedded arg.
+ for (size_t i = 1; token[i] != '\0'; ++i) {
+ const option* opt = LookupShortOpt(opts, token[i]);
+ if (!opt)
+ return false;
+ if (opt->has_arg == required_argument)
+ return token[i + 1] == '\0';
+ }
+ return false;
+}
- // Hint to the OS that the memory range is not needed and can be discarded.
- // The memory remains accessible and its contents may be retained, or they
- // may be zeroed. This function may be a NOP on some platforms. Returns true
- // if implemented.
- bool AdviseDontNeed(void* p, size_t size);
+bool ParseOpts(const char* shortopts,
+ const option* longopts,
+ std::vector<option>* res) {
+ // Parse long options first.
+ for (const option* lopt = longopts; lopt && lopt->name; lopt++) {
+ PERFETTO_CHECK(lopt->flag == nullptr);
+ PERFETTO_CHECK(lopt->has_arg == no_argument ||
+ lopt->has_arg == required_argument);
+ res->emplace_back(*lopt);
+ }
- // Ensures that at least the first |committed_size| bytes of the allocated
- // memory region are committed. The implementation may commit memory in larger
- // chunks above |committed_size|. Crashes if the memory couldn't be committed.
-#if TRACK_COMMITTED_SIZE()
- void EnsureCommitted(size_t committed_size);
-#else // TRACK_COMMITTED_SIZE()
- void EnsureCommitted(size_t /*committed_size*/) {}
-#endif // TRACK_COMMITTED_SIZE()
+ // Merge short options.
+ for (const char* sopt = shortopts; sopt && *sopt;) {
+ const size_t idx = static_cast<size_t>(sopt - shortopts);
+ char c = *sopt++;
+ bool valid = (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') ||
+ (c >= '0' && c <= '9');
+ if (!valid) {
+ fprintf(stderr,
+ "Error parsing shortopts. Unexpected char '%c' at offset %zu\n",
+ c, idx);
+ return false;
+ }
+ res->emplace_back();
+ option& opt = res->back();
+ opt.name = "";
+ opt.val = c;
+ opt.has_arg = no_argument;
+ if (*sopt == ':') {
+ opt.has_arg = required_argument;
+ ++sopt;
+ }
+ }
+ return true;
+}
- inline void* Get() const noexcept { return p_; }
- inline bool IsValid() const noexcept { return !!p_; }
- inline size_t size() const noexcept { return size_; }
+} // namespace
- private:
- PagedMemory(char* p, size_t size);
+int getopt_long(int argc,
+ char** argv,
+ const char* shortopts,
+ const option* longopts,
+ std::nullptr_t /*longind*/) {
+ std::vector<option> opts;
+ optarg = nullptr;
- PagedMemory(const PagedMemory&) = delete;
- // Defaulted for implementation of move constructor + assignment.
- PagedMemory& operator=(const PagedMemory&) = default;
+ if (optind == 0)
+ optind = 1;
- char* p_ = nullptr;
+ if (optind >= argc)
+ return -1;
- // The size originally passed to Allocate(). The actual virtual memory
- // reservation will be larger due to: (i) guard pages; (ii) rounding up to
- // the system page size.
- size_t size_ = 0;
+ if (!ParseOpts(shortopts, longopts, &opts))
+ return '?';
-#if TRACK_COMMITTED_SIZE()
- size_t committed_size_ = 0u;
-#endif // TRACK_COMMITTED_SIZE()
-};
+ // GNU-style permutation: if we're at a non-option, move the next option
+ // (and its separate argument, if any) into position |optind|, shifting any
+ // intervening non-options to the right. This matches the default behavior
+ // of GNU getopt(3) so positional args can be freely interleaved with flags.
+ // We only permute when |nextchar| is null (i.e. we're not in the middle of
+ // a "-abc" short-option chain).
+ if (!nextchar) {
+ int scan = optind;
+ while (scan < argc) {
+ const char* s = argv[scan];
+ // Stop at the next option-bearing token ("-x", "--long", or "--").
+ if (s[0] == '-' && s[1] != '\0')
+ break;
+ ++scan;
+ }
+ // No permutation if there's nothing before the next option, or if the
+ // next token is "--" (the explicit end-of-options marker).
+ if (scan < argc && scan > optind && strcmp(argv[scan], "--") != 0) {
+ bool takes_next = TokenConsumesNextArg(argv[scan], opts);
+ int count = (takes_next && scan + 1 < argc) ? 2 : 1;
+ char* opt_token = argv[scan];
+ char* opt_arg = count == 2 ? argv[scan + 1] : nullptr;
+ // Shift argv[optind..scan) right by |count| to make room.
+ for (int k = scan - 1; k >= optind; --k)
+ argv[k + count] = argv[k];
+ argv[optind] = opt_token;
+ if (count == 2)
+ argv[optind + 1] = opt_arg;
+ }
+ }
+
+ char* arg = argv[optind];
+ optopt = 0;
+
+ if (!nextchar) {
+ // If |nextchar| is null we are NOT in the middle of a short option and we
+ // should parse the next argv.
+ if (strncmp(arg, "--", 2) == 0 && strlen(arg) > 2) {
+ // A --long option.
+ arg += 2;
+ char* sep = strchr(arg, '=');
+ optind++;
+
+ size_t len = sep ? static_cast<size_t>(sep - arg) : strlen(arg);
+ const option* opt = LookupLongOpt(opts, arg, len);
+
+ if (!opt) {
+ if (opterr)
+ fprintf(stderr, "unrecognized option '--%s'\n", arg);
+ return '?';
+ }
+
+ optopt = opt->val;
+ if (opt->has_arg == no_argument) {
+ if (sep) {
+ fprintf(stderr, "option '--%s' doesn't allow an argument\n", arg);
+ return '?';
+ } else {
+ return opt->val;
+ }
+ } else if (opt->has_arg == required_argument) {
+ if (sep) {
+ optarg = sep + 1;
+ return opt->val;
+ } else if (optind >= argc) {
+ if (opterr)
+ fprintf(stderr, "option '--%s' requires an argument\n", arg);
+ return '?';
+ } else {
+ optarg = argv[optind++];
+ return opt->val;
+ }
+ }
+ // has_arg must be either |no_argument| or |required_argument|. We
+ // shoulnd't get here unless the check in ParseOpts() has a bug.
+ PERFETTO_CHECK(false);
+ } // if (arg ~= "--*").
+
+ if (strlen(arg) > 1 && arg[0] == '-' && arg[1] != '-') {
+ // A sequence of short options. Parsing logic continues below.
+ nextchar = &arg[1];
+ }
+ } // if(!nextchar)
+
+ if (nextchar) {
+ // At this point either:
+ // 1. This is the first char of a sequence of short options, and we fell
+ // through here from the lines above.
+ // 2. This is the N (>1) char of a sequence of short options, and we got
+ // here from a new getopt() call to getopt().
+ const char cur_char = *nextchar;
+ PERFETTO_CHECK(cur_char != '\0');
+
+ // Advance the option char in any case, before we start reasoning on them.
+ // if we got to the end of the "-abc" sequence, increment optind so the next
+ // getopt() call resumes from the next argv argument.
+ if (*(++nextchar) == '\0') {
+ nextchar = nullptr;
+ ++optind;
+ }
+
+ const option* opt = LookupShortOpt(opts, cur_char);
+ optopt = cur_char;
+ if (!opt) {
+ if (opterr)
+ fprintf(stderr, "invalid option -- '%c'\n", cur_char);
+ return '?';
+ }
+ if (opt->has_arg == no_argument) {
+ return cur_char;
+ } else if (opt->has_arg == required_argument) {
+ // This is a subtle getopt behavior. Say you call `tar -fx`, there are
+ // two cases:
+ // 1. If 'f' is no_argument then 'x' (and anything else after) is
+ // interpreted as an independent argument (like `tar -f -x`).
+ // 2. If 'f' is required_argument, than everything else after the 'f'
+ // is interpreted as the option argument (like `tar -f x`)
+ if (!nextchar) {
+ // Case 1.
+ if (optind >= argc) {
+ if (opterr)
+ fprintf(stderr, "option requires an argument -- '%c'\n", cur_char);
+ return '?';
+ } else {
+ optarg = argv[optind++];
+ return cur_char;
+ }
+ } else {
+ // Case 2.
+ optarg = nextchar;
+ nextchar = nullptr;
+ optind++;
+ return cur_char;
+ }
+ }
+ PERFETTO_CHECK(false);
+ } // if (nextchar)
+
+ // If we get here, we found the first non-option argument. Stop here.
+
+ if (strcmp(arg, "--") == 0)
+ optind++;
+
+ return -1;
+}
+
+int getopt(int argc, char** argv, const char* shortopts) {
+ return getopt_long(argc, argv, shortopts, nullptr, nullptr);
+}
+} // namespace getopt_compat
} // namespace base
} // namespace perfetto
-
-#endif // INCLUDE_PERFETTO_EXT_BASE_PAGED_MEMORY_H_
+// gen_amalgamated begin source: src/base/intrusive_list.cc
+// gen_amalgamated begin header: include/perfetto/ext/base/intrusive_list.h
/*
- * Copyright (C) 2017 The Android Open Source Project
+ * Copyright (C) 2025 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.
@@ -6919,257 +7429,140 @@ class PagedMemory {
* limitations under the License.
*/
-// gen_amalgamated expanded: #include "perfetto/ext/base/paged_memory.h"
+#ifndef INCLUDE_PERFETTO_EXT_BASE_INTRUSIVE_LIST_H_
+#define INCLUDE_PERFETTO_EXT_BASE_INTRUSIVE_LIST_H_
-#include <algorithm>
-#include <cmath>
#include <cstddef>
-
-#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
-#include <windows.h>
-#else // PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
-#include <sys/mman.h>
-#endif // PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
+#include <cstdint>
// gen_amalgamated expanded: #include "perfetto/base/logging.h"
-// gen_amalgamated expanded: #include "perfetto/ext/base/container_annotations.h"
-// gen_amalgamated expanded: #include "perfetto/ext/base/utils.h"
-
-namespace perfetto {
-namespace base {
-
-namespace {
-
-#if TRACK_COMMITTED_SIZE()
-constexpr size_t kCommitChunkSize = 4 * 1024 * 1024; // 4MB
-#endif
-size_t RoundUpToSysPageSize(size_t req_size) {
- const size_t page_size = GetSysPageSize();
- return (req_size + page_size - 1) & ~(page_size - 1);
-}
-
-size_t GuardSize() {
- return GetSysPageSize();
-}
-
-} // namespace
-
-// static
-PagedMemory PagedMemory::Allocate(size_t req_size, int flags) {
- size_t rounded_up_size = RoundUpToSysPageSize(req_size);
- PERFETTO_CHECK(rounded_up_size >= req_size);
- size_t outer_size = rounded_up_size + GuardSize() * 2;
-#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
- void* ptr = VirtualAlloc(nullptr, outer_size, MEM_RESERVE, PAGE_NOACCESS);
- if (!ptr && (flags & kMayFail))
- return PagedMemory();
- PERFETTO_CHECK(ptr);
- char* usable_region = reinterpret_cast<char*>(ptr) + GuardSize();
-#else // PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
- void* ptr = mmap(nullptr, outer_size, PROT_READ | PROT_WRITE,
- MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
- if (ptr == MAP_FAILED && (flags & kMayFail))
- return PagedMemory();
- PERFETTO_CHECK(ptr && ptr != MAP_FAILED);
- char* usable_region = reinterpret_cast<char*>(ptr) + GuardSize();
- int res = mprotect(ptr, GuardSize(), PROT_NONE);
- res |= mprotect(usable_region + rounded_up_size, GuardSize(), PROT_NONE);
- PERFETTO_CHECK(res == 0);
-#endif // PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
+// An intrusive (doubly linked) list implementation.
+// Unlike std::list<>, the entries being inserted into the list need to
+// explicitly declare an IntrusiveListNode structure (one for each list they are
+// part of). The user must specify a Traits struct for each list the entry is
+// part of. The traits struct defines how to get to the IntrusiveListNode from
+// the outer object.
+//
+// Usage example:
+// class Person {
+// public:
+// struct ListTraits {
+// static constexpr size_t node_offset() { return offsetof(Person, node); }
+// };
+// std::string name;
+// IntrusiveListNode node{};
+// }
+//
+// IntrusiveList<Person, Person::ListTraits> list;
+// Person person;
+// list.PushBack(person);
+// ...
- auto memory = PagedMemory(usable_region, req_size);
-#if TRACK_COMMITTED_SIZE()
- size_t initial_commit = req_size;
- if (flags & kDontCommit)
- initial_commit = std::min(initial_commit, kCommitChunkSize);
- memory.EnsureCommitted(initial_commit);
-#endif // TRACK_COMMITTED_SIZE()
- return memory;
-}
+namespace perfetto::base {
-PagedMemory::PagedMemory() {}
+namespace internal {
-// clang-format off
-PagedMemory::PagedMemory(char* p, size_t size) : p_(p), size_(size) {
- ANNOTATE_NEW_BUFFER(p_, size_, committed_size_)
-}
+struct ListNode {
+ ListNode* prev;
+ ListNode* next;
+};
-PagedMemory::PagedMemory(PagedMemory&& other) noexcept {
- *this = other;
- other.p_ = nullptr;
-}
-// clang-format on
+// IntrusiveList's Base class to factor out type-independent code (avoid binary
+// bloat)
+class ListOps {
+ public:
+ void PushFront(ListNode* node);
+ void PopFront();
+ void Erase(ListNode* node);
-PagedMemory& PagedMemory::operator=(PagedMemory&& other) {
- this->~PagedMemory();
- new (this) PagedMemory(std::move(other));
- return *this;
-}
+ ListNode* front_{nullptr};
+ size_t size_{0};
+};
-PagedMemory::~PagedMemory() {
- if (!p_)
- return;
- PERFETTO_CHECK(size_);
- char* start = p_ - GuardSize();
-#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
- BOOL res = VirtualFree(start, 0, MEM_RELEASE);
- PERFETTO_CHECK(res != 0);
-#else // PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
- const size_t outer_size = RoundUpToSysPageSize(size_) + GuardSize() * 2;
- int res = munmap(start, outer_size);
- PERFETTO_CHECK(res == 0);
-#endif // PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
- ANNOTATE_DELETE_BUFFER(p_, size_, committed_size_)
-}
+} // namespace internal
-bool PagedMemory::AdviseDontNeed(void* p, size_t size) {
- PERFETTO_DCHECK(p_);
- PERFETTO_DCHECK(p >= p_);
- PERFETTO_DCHECK(static_cast<char*>(p) + size <= p_ + size_);
-#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN) || PERFETTO_BUILDFLAG(PERFETTO_OS_NACL)
- // Discarding pages on Windows has more CPU cost than is justified for the
- // possible memory savings.
- return false;
-#elif PERFETTO_BUILDFLAG(PERFETTO_OS_QNX)
- int res = posix_madvise(p, size, POSIX_MADV_DISCARD_NP);
- PERFETTO_DCHECK(res == 0);
- return true;
-#else // PERFETTO_BUILDFLAG(PERFETTO_OS_WIN) ||
- // PERFETTO_BUILDFLAG(PERFETTO_OS_NACL)
- // http://man7.org/linux/man-pages/man2/madvise.2.html
- int res = madvise(p, size, MADV_DONTNEED);
- PERFETTO_DCHECK(res == 0);
- return true;
-#endif // PERFETTO_BUILDFLAG(PERFETTO_OS_WIN) ||
- // PERFETTO_BUILDFLAG(PERFETTO_OS_NACL)
-}
+using IntrusiveListNode = internal::ListNode;
-#if TRACK_COMMITTED_SIZE()
-void PagedMemory::EnsureCommitted(size_t committed_size) {
- PERFETTO_DCHECK(committed_size <= size_);
-#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
- if (committed_size_ >= committed_size)
- return;
- // Rounding up.
- size_t delta = committed_size - committed_size_;
- size_t num_additional_chunks =
- (delta + kCommitChunkSize - 1) / kCommitChunkSize;
- PERFETTO_DCHECK(num_additional_chunks * kCommitChunkSize >= delta);
- // Don't commit more than the total size.
- size_t commit_size = std::min(num_additional_chunks * kCommitChunkSize,
- size_ - committed_size_);
- void* res = VirtualAlloc(p_ + committed_size_, commit_size, MEM_COMMIT,
- PAGE_READWRITE);
- PERFETTO_CHECK(res);
- ANNOTATE_CHANGE_SIZE(p_, size_, committed_size_,
- committed_size_ + commit_size)
- committed_size_ += commit_size;
-#else // PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
- // mmap commits automatically as needed, so we only track here for ASAN.
- committed_size = std::max(committed_size_, committed_size);
- ANNOTATE_CHANGE_SIZE(p_, size_, committed_size_, committed_size)
- committed_size_ = committed_size;
-#endif // PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
-}
-#endif // TRACK_COMMITTED_SIZE()
+// T is the class that has one or more IntrusiveListNode as fields.
+// Traits defines getter and offset between node and T.
+// Traits is separate to allow the same T to be part of different lists (which
+// necessitate a different Traits, at very least for the offset).
+template <typename T, typename ListTraits>
+class IntrusiveList : private internal::ListOps {
+ public:
+ class Iterator {
+ public:
+ Iterator() = default;
+ explicit Iterator(IntrusiveListNode* node) : node_(node) {}
+ ~Iterator() = default;
+ Iterator(const Iterator&) = default;
+ Iterator& operator=(const Iterator&) = default;
+ Iterator(Iterator&&) noexcept = default;
+ Iterator& operator=(Iterator&&) noexcept = default;
-} // namespace base
-} // namespace perfetto
-// gen_amalgamated begin source: src/base/periodic_task.cc
-// gen_amalgamated begin header: include/perfetto/ext/base/periodic_task.h
-/*
- * Copyright (C) 2021 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.
- */
+ bool operator==(const Iterator& other) const {
+ return node_ == other.node_;
+ }
+ bool operator!=(const Iterator& other) const { return !(*this == other); }
+ T* operator->() { return const_cast<T*>(entryof(node_)); }
+ T& operator*() {
+ PERFETTO_DCHECK(node_);
+ return *operator->();
+ }
+ explicit operator bool() const { return node_ != nullptr; }
-#ifndef INCLUDE_PERFETTO_EXT_BASE_PERIODIC_TASK_H_
-#define INCLUDE_PERFETTO_EXT_BASE_PERIODIC_TASK_H_
+ Iterator& operator++() {
+ PERFETTO_DCHECK(node_);
+ node_ = node_->next;
+ return *this;
+ }
-#include <functional>
+ private:
+ IntrusiveListNode* node_{nullptr};
+ };
-// gen_amalgamated expanded: #include "perfetto/ext/base/scoped_file.h"
-// gen_amalgamated expanded: #include "perfetto/ext/base/thread_checker.h"
-// gen_amalgamated expanded: #include "perfetto/ext/base/weak_ptr.h"
+ using value_type = T;
+ using const_pointer = const T*;
-namespace perfetto {
-namespace base {
+ void PushFront(T& entry) { internal::ListOps::PushFront(nodeof(&entry)); }
-class TaskRunner;
+ void PopFront() { internal::ListOps::PopFront(); }
-// A periodic task utility class. It wraps the logic necessary to do periodic
-// tasks using a TaskRunner, taking care of subtleties like ensuring that
-// outstanding tasks are cancelled after reset/dtor.
-// Tasks are aligned on wall time (unless they are |one_shot|). This is to
-// ensure that when using multiple periodic tasks, they happen at the same time,
-// minimizing context switches.
-// On Linux/Android it also supports suspend-aware mode (via timerfd). On other
-// operating systems it falls back to PostDelayedTask, which is not
-// suspend-aware.
-// TODO(primiano): this should probably become a periodic timer scheduler, so we
-// can use one FD for everything rather than one FD per task. For now we take
-// the hit of a FD-per-task to keep this low-risk.
-// TODO(primiano): consider renaming this class to TimerTask. When |one_shot|
-// is set, the "Periodic" part of the class name becomes a lie.
-class PeriodicTask {
- public:
- explicit PeriodicTask(base::TaskRunner*);
- ~PeriodicTask(); // Calls Reset().
+ T& front() {
+ PERFETTO_DCHECK(front_);
+ return const_cast<T&>(*entryof(front_));
+ }
- struct Args {
- uint32_t period_ms = 0;
- std::function<void()> task = nullptr;
- bool start_first_task_immediately = false;
- bool use_suspend_aware_timer = false;
- bool one_shot = false;
- };
+ void Erase(T& entry) { internal::ListOps::Erase(nodeof(&entry)); }
- void Start(Args);
+ bool empty() const { return size_ == 0; }
- // Safe to be called multiple times, even without calling Start():
- void Reset();
+ size_t size() const { return size_; }
- // No copy or move. WeakPtr-wrapped pointers to |this| are posted on the
- // task runner, this class is not easily movable.
- PeriodicTask(const PeriodicTask&) = delete;
- PeriodicTask& operator=(const PeriodicTask&) = delete;
- PeriodicTask(PeriodicTask&&) = delete;
- PeriodicTask& operator=(PeriodicTask&&) = delete;
+ Iterator begin() { return Iterator{front_}; }
- base::PlatformHandle timer_fd_for_testing() { return *timer_fd_; }
+ Iterator end() { return Iterator{nullptr}; }
private:
- static void RunTaskAndPostNext(base::WeakPtr<PeriodicTask>,
- uint32_t generation);
- void PostNextTask();
- void ResetTimerFd();
+ static constexpr size_t kNodeOffset = ListTraits::node_offset();
- base::TaskRunner* const task_runner_;
- Args args_;
- uint32_t generation_ = 0;
- base::ScopedPlatformHandle timer_fd_;
+ static constexpr IntrusiveListNode* nodeof(T* entry) {
+ return reinterpret_cast<IntrusiveListNode*>(
+ reinterpret_cast<uintptr_t>(entry) + kNodeOffset);
+ }
- PERFETTO_THREAD_CHECKER(thread_checker_)
- base::WeakPtrFactory<PeriodicTask> weak_ptr_factory_; // Keep last.
+ static constexpr const T* entryof(IntrusiveListNode* node) {
+ return reinterpret_cast<T*>(reinterpret_cast<uintptr_t>(node) -
+ kNodeOffset);
+ }
};
-} // namespace base
-} // namespace perfetto
+} // namespace perfetto::base
-#endif // INCLUDE_PERFETTO_EXT_BASE_PERIODIC_TASK_H_
+#endif // INCLUDE_PERFETTO_EXT_BASE_INTRUSIVE_LIST_H_
/*
- * Copyright (C) 2021 The Android Open Source Project
+ * Copyright (C) 2025 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.
@@ -7184,180 +7577,61 @@ class PeriodicTask {
* limitations under the License.
*/
-// gen_amalgamated expanded: #include "perfetto/ext/base/periodic_task.h"
-
-#include <limits>
+// gen_amalgamated expanded: #include "perfetto/ext/base/intrusive_list.h"
-// gen_amalgamated expanded: #include "perfetto/base/build_config.h"
// gen_amalgamated expanded: #include "perfetto/base/logging.h"
-// gen_amalgamated expanded: #include "perfetto/base/task_runner.h"
-// gen_amalgamated expanded: #include "perfetto/base/time.h"
-// gen_amalgamated expanded: #include "perfetto/ext/base/file_utils.h"
-
-#if PERFETTO_BUILDFLAG(PERFETTO_OS_LINUX_BUT_NOT_QNX) || \
- PERFETTO_BUILDFLAG(PERFETTO_OS_FREEBSD) || \
- (PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID) && __ANDROID_API__ >= 19)
-#include <sys/timerfd.h>
-#endif
-
-namespace perfetto {
-namespace base {
-
-namespace {
-
-uint32_t GetNextDelayMs(const TimeMillis& now_ms,
- const PeriodicTask::Args& args) {
- if (args.one_shot)
- return args.period_ms;
- return args.period_ms -
- static_cast<uint32_t>(now_ms.count() % args.period_ms);
-}
+namespace perfetto::base::internal {
-ScopedPlatformHandle CreateTimerFd(const PeriodicTask::Args& args) {
-#if PERFETTO_BUILDFLAG(PERFETTO_OS_LINUX_BUT_NOT_QNX) || \
- PERFETTO_BUILDFLAG(PERFETTO_OS_FREEBSD) || \
- (PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID) && __ANDROID_API__ >= 19)
- ScopedPlatformHandle tfd(
- timerfd_create(CLOCK_BOOTTIME, TFD_CLOEXEC | TFD_NONBLOCK));
- uint32_t phase_ms = GetNextDelayMs(GetBootTimeMs(), args);
+void ListOps::PushFront(IntrusiveListNode* node) {
+ node->prev = nullptr;
+ node->next = front_;
- struct itimerspec its{};
- // The "1 +" is to make sure that we never pass a zero it_value in the
- // unlikely case of phase_ms being 0. That would cause the timer to be
- // considered disarmed by timerfd_settime.
- its.it_value.tv_sec = static_cast<time_t>(phase_ms / 1000u);
- its.it_value.tv_nsec = 1 + static_cast<long>((phase_ms % 1000u) * 1000000u);
- if (args.one_shot) {
- its.it_interval.tv_sec = 0;
- its.it_interval.tv_nsec = 0;
- } else {
- const uint32_t period_ms = args.period_ms;
- its.it_interval.tv_sec = static_cast<time_t>(period_ms / 1000u);
- its.it_interval.tv_nsec = static_cast<long>((period_ms % 1000u) * 1000000u);
+ if (front_) {
+ front_->prev = node;
}
- if (timerfd_settime(*tfd, 0, &its, nullptr) < 0)
- return ScopedPlatformHandle();
- return tfd;
-#else
- ignore_result(args);
- return ScopedPlatformHandle();
-#endif
-}
-
-} // namespace
-
-PeriodicTask::PeriodicTask(TaskRunner* task_runner)
- : task_runner_(task_runner), weak_ptr_factory_(this) {}
-PeriodicTask::~PeriodicTask() {
- Reset();
+ front_ = node;
+ ++size_;
}
-void PeriodicTask::Start(Args args) {
- PERFETTO_DCHECK_THREAD(thread_checker_);
- Reset();
- if (args.period_ms == 0 || !args.task) {
- PERFETTO_DCHECK(args.period_ms > 0);
- PERFETTO_DCHECK(args.task);
- return;
- }
- args_ = std::move(args);
- if (args_.use_suspend_aware_timer) {
- timer_fd_ = CreateTimerFd(args_);
- if (timer_fd_) {
- auto weak_this = weak_ptr_factory_.GetWeakPtr();
- task_runner_->AddFileDescriptorWatch(
- *timer_fd_,
- std::bind(PeriodicTask::RunTaskAndPostNext, weak_this, generation_));
- } else {
- PERFETTO_DPLOG("timerfd not supported, falling back on PostDelayedTask");
- }
- } // if (use_suspend_aware_timer).
+void ListOps::PopFront() {
+ PERFETTO_DCHECK(front_);
+ front_ = front_->next;
- if (!timer_fd_)
- PostNextTask();
+ if (front_) {
+ front_->prev = nullptr;
+ }
- if (args_.start_first_task_immediately)
- args_.task();
+ PERFETTO_DCHECK(size_ > 0);
+ --size_;
}
-void PeriodicTask::PostNextTask() {
- PERFETTO_DCHECK_THREAD(thread_checker_);
- PERFETTO_DCHECK(args_.period_ms > 0);
- PERFETTO_DCHECK(!timer_fd_);
- uint32_t delay_ms = GetNextDelayMs(GetWallTimeMs(), args_);
- auto weak_this = weak_ptr_factory_.GetWeakPtr();
- task_runner_->PostDelayedTask(
- std::bind(PeriodicTask::RunTaskAndPostNext, weak_this, generation_),
- delay_ms);
-}
+void ListOps::Erase(IntrusiveListNode* node) {
+ auto* prev = node->prev;
+ auto* next = node->next;
-// static
-// This function can be called in two ways (both from the TaskRunner):
-// 1. When using a timerfd, this task is registered as a FD watch.
-// 2. When using PostDelayedTask, this is the task posted on the TaskRunner.
-void PeriodicTask::RunTaskAndPostNext(WeakPtr<PeriodicTask> thiz,
- uint32_t generation) {
- if (!thiz || !thiz->args_.task || generation != thiz->generation_)
- return; // Destroyed or Reset() in the meanwhile.
- PERFETTO_DCHECK_THREAD(thiz->thread_checker_);
- if (thiz->timer_fd_) {
-#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
- PERFETTO_FATAL("timerfd for periodic tasks unsupported on Windows");
-#else
- // If we are using a timerfd there is no need to repeatedly call
- // PostDelayedTask(). The kernel will wakeup the timer fd periodically. We
- // just need to read() it.
- uint64_t ignored = 0;
- errno = 0;
- auto rsize = Read(*thiz->timer_fd_, &ignored, sizeof(&ignored));
- if (rsize != sizeof(uint64_t)) {
- if (errno == EAGAIN)
- return; // A spurious wakeup. Rare, but can happen, just ignore.
- PERFETTO_PLOG("read(timerfd) failed, falling back on PostDelayedTask");
- thiz->ResetTimerFd();
- }
-#endif
+ if (node == front_) {
+ front_ = next;
}
- // Create a copy of the task to deal with either:
- // 1. one_shot causing a Reset().
- // 2. task() invoking internally Reset().
- // That would cause a reset of the args_.task itself, which would invalidate
- // the task bind state while we are invoking it.
- auto task = thiz->args_.task;
-
- // The repetition of the if() is to deal with the ResetTimerFd() case above.
- if (thiz->args_.one_shot) {
- thiz->Reset();
- } else if (!thiz->timer_fd_) {
- thiz->PostNextTask();
+ if (prev) {
+ prev->next = next;
}
- task();
-}
-
-void PeriodicTask::Reset() {
- PERFETTO_DCHECK_THREAD(thread_checker_);
- ++generation_;
- args_ = Args();
- PERFETTO_DCHECK(!args_.task);
- ResetTimerFd();
-}
+ if (next) {
+ next->prev = prev;
+ }
-void PeriodicTask::ResetTimerFd() {
- if (!timer_fd_)
- return;
- task_runner_->RemoveFileDescriptorWatch(*timer_fd_);
- timer_fd_.reset();
+ PERFETTO_DCHECK(size_ > 0);
+ --size_;
}
-} // namespace base
-} // namespace perfetto
-// gen_amalgamated begin source: src/base/pipe.cc
+} // namespace perfetto::base::internal
+// gen_amalgamated begin source: src/base/intrusive_tree.cc
+// gen_amalgamated begin header: include/perfetto/ext/base/intrusive_tree.h
/*
- * Copyright (C) 2018 The Android Open Source Project
+ * Copyright (C) 2025 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.
@@ -7372,275 +7646,241 @@ void PeriodicTask::ResetTimerFd() {
* limitations under the License.
*/
-// gen_amalgamated expanded: #include "perfetto/ext/base/pipe.h"
+#ifndef INCLUDE_PERFETTO_EXT_BASE_INTRUSIVE_TREE_H_
+#define INCLUDE_PERFETTO_EXT_BASE_INTRUSIVE_TREE_H_
-// gen_amalgamated expanded: #include "perfetto/base/build_config.h"
+#include <cstddef>
+#include <cstdint>
+#include <functional>
-#include <fcntl.h> // For O_BINARY (Windows) and F_SETxx (UNIX)
+// gen_amalgamated expanded: #include "perfetto/base/logging.h"
-#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
-#include <windows.h>
+// An intrusive tree implementation, inspired from BSD kernel's tree.h
+// Unlike std::set<>, the nodes being inserted into the tree need to explicitly
+// declare a RBNode structure (one for each tree they are part of).
+// The user must specify a TreeTraits for each tree the struct is part of.
+// The traits struct defines the type of the key and how to get to the node
+// entry from the outer object.
+// Usage example:
+// class Person {
+// public:
+// struct Traits {
+// using KeyType = std::string;
+// static const KeyType& GetKey(const Person& p) { return p->unique_id; }
+// static constexpr size_t NodeOffset() { return offsetof(Person, node); }
+// };
+// std::string unique_id;
+// std::string name;
+// std::string surname;
+// IntrusiveTreeNode node{};
+// }
+// IntrusiveTree<Person, Person::Traits> tree;
+// tree.insert(&person1);
+// ...
-#include <namedpipeapi.h>
-#else
-#include <sys/types.h>
-#include <unistd.h>
-#endif
+namespace perfetto::base {
-// gen_amalgamated expanded: #include "perfetto/base/logging.h"
+namespace internal {
-namespace perfetto {
-namespace base {
+enum RBColor : uint8_t {
+ BLACK = 0,
+ RED = 1,
+};
-Pipe::Pipe() = default;
-Pipe::Pipe(Pipe&&) noexcept = default;
-Pipe& Pipe::operator=(Pipe&&) = default;
+struct RBNode {
+ RBNode* left = nullptr;
+ RBNode* right = nullptr;
+ RBNode* parent = nullptr;
+ RBColor color = RBColor::BLACK;
+};
-Pipe Pipe::Create(Flags flags) {
- PlatformHandle fds[2];
-#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
- PERFETTO_CHECK(::CreatePipe(&fds[0], &fds[1], /*lpPipeAttributes=*/nullptr,
- 0 /*default size*/));
-#else
- PERFETTO_CHECK(pipe(fds) == 0);
- PERFETTO_CHECK(fcntl(fds[0], F_SETFD, FD_CLOEXEC) == 0);
- PERFETTO_CHECK(fcntl(fds[1], F_SETFD, FD_CLOEXEC) == 0);
-#endif
- Pipe p;
- p.rd.reset(fds[0]);
- p.wr.reset(fds[1]);
+void RBInsertColor(RBNode** root, RBNode* elm);
+void RBRemove(RBNode** root, RBNode* elm);
-#if !PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
- if (flags == kBothNonBlock || flags == kRdNonBlock) {
- int cur_flags = fcntl(*p.rd, F_GETFL, 0);
- PERFETTO_CHECK(cur_flags >= 0);
- PERFETTO_CHECK(fcntl(*p.rd, F_SETFL, cur_flags | O_NONBLOCK) == 0);
- }
+// Returns nullptr after reaching the last leaf (the max element).
+const RBNode* RBNext(const RBNode* node);
- if (flags == kBothNonBlock || flags == kWrNonBlock) {
- int cur_flags = fcntl(*p.wr, F_GETFL, 0);
- PERFETTO_CHECK(cur_flags >= 0);
- PERFETTO_CHECK(fcntl(*p.wr, F_SETFL, cur_flags | O_NONBLOCK) == 0);
- }
-#else
- PERFETTO_CHECK(flags == kBothBlock);
-#endif
- return p;
+// KeyCompare tries first to use the CompareKey function in Traits, if present.
+// The signature of that function is int(const KeyType&, const KeyType&).
+// If the comparator function doesn't exist, falls backk on std::less<KeyType>.
+template <
+ class Traits,
+ class = std::enable_if_t<std::is_function_v<typename Traits::CompareKey>,
+ void> >
+int KeyCompare(const typename Traits::KeyType& k1,
+ const typename Traits::KeyType& k2) {
+ return Traits::CompareKey(k1, k2);
}
-} // namespace base
-} // namespace perfetto
-// gen_amalgamated begin source: src/base/rt_mutex.cc
-// gen_amalgamated begin header: include/perfetto/ext/base/rt_mutex.h
-/*
- * Copyright (C) 2025 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_RT_MUTEX_H_
-#define INCLUDE_PERFETTO_EXT_BASE_RT_MUTEX_H_
-
-// This header introduces the RtMutex class for priority-inheritance mutexes.
-// RtMutex is NOT a blanket replacement for std::mutex and should be used only
-// in cases where we know we are expect to be used on a RT thread.
-// In the contended case RtMutex is generally slower than a std::mutex (or any
-// non-RT implementation).
-// Under the hoods this class does the following:
-// - Android: it uses PI futexes.
-// - Linux/MacOS/iOS: it uses pthread_mutex with PTHREAD_PRIO_INHERIT.
-// - Other platforms: falls back on a standard std::mutex. On Windows 11+
-// std::mutex has effectively PI semantics due to AutoBoost
-// https://github.com/MicrosoftDocs/win32/commit/a43cb3b5039c5cfc53642bfcea174003a2f1168f
-
-// gen_amalgamated expanded: #include "perfetto/base/build_config.h"
-// gen_amalgamated expanded: #include "perfetto/base/thread_annotations.h"
-// gen_amalgamated expanded: #include "perfetto/public/compiler.h"
-
-#define _PERFETTO_MUTEX_MODE_STD 0
-#define _PERFETTO_MUTEX_MODE_RT_FUTEX 1
-#define _PERFETTO_MUTEX_MODE_RT_MUTEX 2
-
-// The logic below determines which mutex implementation to use.
-// For Android platform builds, the choice is controlled by aconfig flags.
-// For other builds, it's determined by OS support and GN build arguments.
-//
-// Rationale for platform-specific choices:
-// 1. `RtFutex` is enabled only on Android because it relies on `gettid()` being
-// a cheap thread-local storage access provided by Bionic. On Linux with
-// glibc, `gettid()` is a full syscall, making the pthread-based
-// implementation faster.
-// 2. The pthread-based `RtPosixMutex` is not viable on all Android versions, as
-// `pthread_mutexattr_setprotocol` was introduced in API level 28. Using
-// `dlsym` to backport it can lead to deadlocks with the loader lock if
-// tracing is initialized from a static constructor (see b/443178555).
-#if PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID) && \
- PERFETTO_BUILDFLAG(PERFETTO_ANDROID_BUILD)
-#define _PERFETTO_MUTEX_MODE _PERFETTO_MUTEX_MODE_RT_FUTEX
-#elif PERFETTO_BUILDFLAG(PERFETTO_ENABLE_RT_MUTEX)
-#if PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID)
-#define _PERFETTO_MUTEX_MODE _PERFETTO_MUTEX_MODE_RT_FUTEX
-#elif PERFETTO_BUILDFLAG(PERFETTO_OS_LINUX) || \
- PERFETTO_BUILDFLAG(PERFETTO_OS_APPLE)
-#define _PERFETTO_MUTEX_MODE _PERFETTO_MUTEX_MODE_RT_MUTEX
-#endif
-#endif
-
-// If no RT implementation was selected, default to std::mutex.
-#ifndef _PERFETTO_MUTEX_MODE
-#define _PERFETTO_MUTEX_MODE _PERFETTO_MUTEX_MODE_STD
-#endif
-
-// Public macros for conditional compilation based on the selected mutex type.
-#define PERFETTO_HAS_POSIX_RT_MUTEX() \
- (_PERFETTO_MUTEX_MODE == _PERFETTO_MUTEX_MODE_RT_MUTEX)
-#define PERFETTO_HAS_RT_FUTEX() \
- (_PERFETTO_MUTEX_MODE == _PERFETTO_MUTEX_MODE_RT_FUTEX)
+// SFINAE fallback on std::less<KeyType>
+template <class Traits>
+int KeyCompare(const typename Traits::KeyType& k1,
+ const typename Traits::KeyType& k2) {
+ std::less<typename Traits::KeyType> less_cmp;
+ return less_cmp(k1, k2) ? -1 : (less_cmp(k2, k1) ? 1 : 0);
+}
-#include <atomic>
-#include <mutex>
-#include <type_traits>
+} // namespace internal
-#if PERFETTO_HAS_POSIX_RT_MUTEX()
-#include <pthread.h>
-#endif
+using IntrusiveTreeNode = internal::RBNode;
-#if !PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
-#include <unistd.h> // For gettid().
-#endif
+// T is the class that has one or more IntrusiveTreeNode as fiels.
+// Traits defines the key type, getter and offset between node and T.
+// Traits is separate to allow the same T to be part of different trees (which
+// necessitate a different Traits, at very least for the offset).
+template <typename T, typename Traits>
+class IntrusiveTree {
+ public:
+ using Key = typename Traits::KeyType;
-namespace perfetto::base {
+ class Iterator {
+ public:
+ Iterator() = default;
+ explicit Iterator(const internal::RBNode* node) : node_(node) {}
+ ~Iterator() = default;
+ Iterator(const Iterator&) = default;
+ Iterator& operator=(const Iterator&) = default;
+ Iterator(Iterator&&) noexcept = default;
+ Iterator& operator=(Iterator&&) noexcept = default;
-namespace internal {
+ bool operator==(const Iterator& o) const { return node_ == o.node_; }
+ bool operator!=(const Iterator& o) const { return !(*this == o); }
+ const T* operator->() const { return entryof(node_); }
+ const T& operator*() const {
+ PERFETTO_DCHECK(node_ != nullptr);
+ return *operator->();
+ }
+ T* operator->() { return const_cast<T*>(entryof(node_)); }
+ T& operator*() {
+ PERFETTO_DCHECK(node_ != nullptr);
+ return *operator->();
+ }
+ explicit operator bool() const { return node_ != nullptr; }
-#if PERFETTO_HAS_RT_FUTEX()
-// A wrapper around PI Futexes. A futex is a wrapper around an atomic integer
-// with an ABI shared with the kernel to handle the slowpath in the cases when
-// the mutex is held, or we find out that there are waiters queued when we
-// unlock. The operating principle is the following:
-// - In the no-contention case, a futex boils down to an atomic
-// compare-and-exchange, without involving the kernel.
-// - If a lock is contented at acquire time, we have to enter the kernel to
-// suspend our execution and join a wait chain.
-// - It could still happen that we acquire the mutex via the fastpath (without
-// involving the kernel) but other waiters might queue up while we hold the
-// mutex. In that case the kernel will add a bit to the atomic int. That bit
-// will cause the unlock() compare-and-exchange to fail (because it no longer
-// matches our tid) which in turn will signal us to do a syscall to notify the
-// waiters.
-class PERFETTO_LOCKABLE RtFutex {
- public:
- RtFutex() { PERFETTO_TSAN_MUTEX_CREATE(this, __tsan_mutex_not_static); }
- ~RtFutex() { PERFETTO_TSAN_MUTEX_DESTROY(this, __tsan_mutex_not_static); }
+ Iterator& operator++() {
+ node_ = internal::RBNext(node_);
+ return *this;
+ }
- // Disable copy or move. Copy doesn't make sense. Move isn't feasible because
- // the pointer to the atomic integer is the handle used by the kernel to setup
- // the wait chain. A movable futex would require the atomic integer to be heap
- // allocated, but that would create an indirection layer that is not needed in
- // most cases. If you really need a movable RtMutex, wrap it in a unique_ptr.
- RtFutex(const RtFutex&) = delete;
- RtFutex& operator=(const RtFutex&) = delete;
- RtFutex(RtFutex&&) = delete;
- RtFutex& operator=(RtFutex&&) = delete;
+ private:
+ const internal::RBNode* node_ = nullptr;
+ }; // Iterator
- inline bool TryLockFastpath() noexcept {
- int expected = 0;
- return lock_.compare_exchange_strong(expected, ::gettid(),
- std::memory_order_acquire,
- std::memory_order_relaxed);
- }
+ using value_type = T;
+ using const_pointer = const T*;
+ using const_iterator = Iterator;
- bool try_lock() noexcept PERFETTO_EXCLUSIVE_TRYLOCK_FUNCTION(true) {
- PERFETTO_TSAN_MUTEX_PRE_LOCK(this, __tsan_mutex_try_lock);
- if (PERFETTO_LIKELY(TryLockFastpath()) || TryLockSlowpath()) {
- PERFETTO_TSAN_MUTEX_POST_LOCK(this, __tsan_mutex_try_lock, 0);
- return true;
+ std::pair<Iterator, bool> Insert(T& entry) {
+ // The insertion preamble is inlined because it's few instructions and
+ // out-lining it would require std::function indirections for getting the
+ // key and the comparator.
+ int comp = 0;
+ internal::RBNode* tmp = root_;
+ internal::RBNode* parent = nullptr;
+ internal::RBNode* const entry_node = nodeof(&entry);
+ while (tmp) {
+ parent = tmp;
+ comp = key_compare(entry_node, parent);
+ if (comp < 0) {
+ tmp = tmp->left;
+ } else if (comp > 0) {
+ tmp = tmp->right;
+ } else {
+ return {Iterator(tmp), false}; // The key exists already.
+ }
+ } // while(tmp)
+ entry_node->left = entry_node->right = nullptr;
+ entry_node->parent = parent;
+ entry_node->color = internal::RBColor::RED;
+ if (parent) {
+ if (comp < 0) {
+ PERFETTO_DCHECK(parent->left == nullptr);
+ parent->left = entry_node;
+ } else {
+ PERFETTO_DCHECK(parent->right == nullptr);
+ parent->right = entry_node;
+ }
+ } else {
+ root_ = entry_node;
}
- PERFETTO_TSAN_MUTEX_POST_LOCK(
- this, __tsan_mutex_try_lock | __tsan_mutex_try_lock_failed, 0);
- return false;
+ internal::RBInsertColor(&root_, entry_node);
+ ++size_;
+ return {Iterator(entry_node), true};
}
- void lock() PERFETTO_EXCLUSIVE_LOCK_FUNCTION() {
- PERFETTO_TSAN_MUTEX_PRE_LOCK(this, 0);
- if (!PERFETTO_LIKELY(TryLockFastpath())) {
- LockSlowpath();
+ Iterator Find(const Key& key) const {
+ internal::RBNode* tmp = root_;
+ while (tmp) {
+ int comp =
+ internal::KeyCompare<Traits>(key, Traits::GetKey(*entryof(tmp)));
+ if (comp < 0) {
+ tmp = tmp->left;
+ } else if (comp > 0) {
+ tmp = tmp->right;
+ } else {
+ return Iterator(tmp);
+ }
}
- PERFETTO_TSAN_MUTEX_POST_LOCK(this, 0, 0);
+ return Iterator(nullptr);
}
- void unlock() noexcept PERFETTO_UNLOCK_FUNCTION() {
- PERFETTO_TSAN_MUTEX_PRE_UNLOCK(this, 0);
- int expected = ::gettid();
- // If the current value is our tid, we can unlock without a syscall since
- // there are no current waiters.
- if (!PERFETTO_LIKELY(lock_.compare_exchange_strong(
- expected, 0, std::memory_order_release,
- std::memory_order_relaxed))) {
- // The tid doesn't match because the kernel appended the FUTEX_WAITERS
- // bit. There are waiters, tell the kernel to notify them and unlock.
- UnlockSlowpath();
- }
- PERFETTO_TSAN_MUTEX_POST_UNLOCK(this, 0);
+ bool Remove(const Key& key) {
+ Iterator it = Find(key);
+ if (!it)
+ return false;
+ internal::RBRemove(&root_, nodeof(std::addressof(*it)));
+ --size_;
+ return true;
}
- private:
- std::atomic<int> lock_{};
-
- void LockSlowpath();
- bool TryLockSlowpath();
- void UnlockSlowpath();
-};
+ Iterator Remove(T& entry) { return Remove(Iterator(nodeof(&entry))); }
-#endif // PERFETTO_HAS_RT_FUTEX
+ Iterator Remove(Iterator it) {
+ Iterator next = it;
+ ++next;
+ internal::RBRemove(&root_, nodeof(std::addressof(*it)));
+ --size_;
+ return next;
+ }
-#if PERFETTO_HAS_POSIX_RT_MUTEX()
-class PERFETTO_LOCKABLE RtPosixMutex {
- public:
- RtPosixMutex() noexcept;
- ~RtPosixMutex() noexcept;
+ size_t Size() const { return size_; }
- RtPosixMutex(const RtPosixMutex&) = delete;
- RtPosixMutex& operator=(const RtPosixMutex&) = delete;
- RtPosixMutex(RtPosixMutex&&) = delete;
- RtPosixMutex& operator=(RtPosixMutex&&) = delete;
+ Iterator begin() const {
+ const internal::RBNode* node = root_;
+ while (node && node->left)
+ node = node->left;
+ return Iterator(node);
+ }
- bool try_lock() noexcept PERFETTO_EXCLUSIVE_TRYLOCK_FUNCTION(true);
- void lock() noexcept PERFETTO_EXCLUSIVE_LOCK_FUNCTION();
- void unlock() noexcept PERFETTO_UNLOCK_FUNCTION();
+ Iterator end() const { return Iterator(nullptr); }
private:
- pthread_mutex_t mutex_;
-};
-
-#endif // PERFETTO_HAS_POSIX_RT_MUTEX
-} // namespace internal
+ static constexpr size_t off_ = Traits::NodeOffset();
+ static internal::RBNode* nodeof(T* t) {
+ PERFETTO_DCHECK(t != nullptr);
+ return reinterpret_cast<internal::RBNode*>(reinterpret_cast<uintptr_t>(t) +
+ off_);
+ }
+ static const T* entryof(const internal::RBNode* n) {
+ PERFETTO_DCHECK(n != nullptr);
+ return reinterpret_cast<T*>(reinterpret_cast<uintptr_t>(n) - off_);
+ }
+ static int key_compare(const internal::RBNode* node_a,
+ const internal::RBNode* node_b) {
+ auto* a = entryof(node_a);
+ auto* b = entryof(node_b);
+ return internal::KeyCompare<Traits>(Traits::GetKey(*a), Traits::GetKey(*b));
+ }
-// Select the best real-time mutex implementation for the target platform, or
-// fall back to std::mutex if none is available.
-#if PERFETTO_HAS_RT_FUTEX()
-using MaybeRtMutex = internal::RtFutex;
-#elif PERFETTO_HAS_POSIX_RT_MUTEX()
-using MaybeRtMutex = internal::RtPosixMutex;
-#else
-using MaybeRtMutex = std::mutex;
-#endif
+ internal::RBNode* root_ = nullptr;
+ size_t size_ = 0;
+};
} // namespace perfetto::base
-#endif // INCLUDE_PERFETTO_EXT_BASE_RT_MUTEX_H_
+#endif // INCLUDE_PERFETTO_EXT_BASE_INTRUSIVE_TREE_H_
/*
- * Copyright (C) 2018 The Android Open Source Project
+ * Copyright (C) 2025 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.
@@ -7654,95 +7894,290 @@ using MaybeRtMutex = std::mutex;
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+/* Part of this work is inspired by the original OpenBSD's tree.h */
+/* $OpenBSD: tree.h,v 1.31 2023/03/08 04:43:09 guenther Exp $ */
+/*
+ * Copyright 2002 Niels Provos <provos@citi.umich.edu>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
-// gen_amalgamated expanded: #include "perfetto/ext/base/rt_mutex.h"
-
-#include <errno.h>
-
-// gen_amalgamated expanded: #include "perfetto/base/logging.h"
-// gen_amalgamated expanded: #include "perfetto/ext/base/utils.h"
-
-#if PERFETTO_HAS_RT_FUTEX()
-#include <linux/futex.h>
-#include <sys/syscall.h>
-#include <unistd.h>
-#endif
-
-namespace perfetto::base {
-
-namespace internal {
-
-#if PERFETTO_HAS_RT_FUTEX()
+// gen_amalgamated expanded: #include "perfetto/ext/base/intrusive_tree.h"
-void RtFutex::LockSlowpath() {
- auto res = PERFETTO_EINTR(
- syscall(SYS_futex, &lock_, FUTEX_LOCK_PI_PRIVATE, 0, nullptr));
- PERFETTO_CHECK(res == 0);
-}
+namespace perfetto::base::internal {
-bool RtFutex::TryLockSlowpath() {
- auto res = PERFETTO_EINTR(
- syscall(SYS_futex, &lock_, FUTEX_TRYLOCK_PI_PRIVATE, 0, nullptr));
- if (res == 0)
- return true;
- if (errno == EBUSY || errno == EDEADLK)
- return false;
- PERFETTO_FATAL("FUTEX_TRYLOCK_PI_PRIVATE failed");
-}
+namespace {
-void RtFutex::UnlockSlowpath() {
- auto res = PERFETTO_EINTR(
- syscall(SYS_futex, &lock_, FUTEX_UNLOCK_PI_PRIVATE, 0, nullptr));
- PERFETTO_CHECK(res == 0);
+void RBSetBlackRed(RBNode* black, RBNode* red) {
+ black->color = RBColor::BLACK;
+ red->color = RBColor::RED;
}
-#endif // PERFETTO_HAS_RT_FUTEX
-
-#if PERFETTO_HAS_POSIX_RT_MUTEX()
-
-RtPosixMutex::RtPosixMutex() noexcept {
-#if PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID) && __ANDROID_API__ < 28
- // pthread_mutexattr_setprotocol is only available on API 28.
-#error \
- "Priority-inheritance RtMutex is not available in this version of Android."
-#endif
- pthread_mutexattr_t at{};
- PERFETTO_CHECK(pthread_mutexattr_init(&at) == 0);
- PERFETTO_CHECK(pthread_mutexattr_setprotocol(&at, PTHREAD_PRIO_INHERIT) == 0);
- PERFETTO_CHECK(pthread_mutex_init(&mutex_, &at) == 0);
+void RBRotateLeft(RBNode** root, RBNode* elm, RBNode* tmp) {
+ tmp = elm->right;
+ if ((elm->right = tmp->left)) {
+ tmp->left->parent = elm;
+ }
+ // RB_AUGMENT(elm);
+ if ((tmp->parent = elm->parent)) {
+ if (elm == elm->parent->left)
+ elm->parent->left = tmp;
+ else
+ elm->parent->right = tmp;
+ } else
+ *root = tmp;
+ tmp->left = elm;
+ elm->parent = tmp;
+ // RB_AUGMENT(tmp);
+ // if ((tmp->parent))
+ // RB_AUGMENT(tmp->parent);
}
-RtPosixMutex::~RtPosixMutex() noexcept {
- pthread_mutex_destroy(&mutex_);
+void RBRotateRight(RBNode** root, RBNode* elm, RBNode* tmp) {
+ tmp = elm->left;
+ if ((elm->left = tmp->right)) {
+ tmp->right->parent = elm;
+ }
+ // RB_AUGMENT(elm);
+ if ((tmp->parent = elm->parent)) {
+ if (elm == elm->parent->left)
+ elm->parent->left = tmp;
+ else
+ elm->parent->right = tmp;
+ } else
+ *root = tmp;
+ tmp->right = elm;
+ elm->parent = tmp;
+ // RB_AUGMENT(tmp);
+ // if ((tmp->parent))
+ // RB_AUGMENT(tmp->parent);
}
-bool RtPosixMutex::try_lock() noexcept {
- int res = pthread_mutex_trylock(&mutex_);
- if (res == 0)
- return true;
- // NOTE: Unlike most Linux APIs, pthread_mutex_trylock "returns" the error
- // code, it does NOT use errno.
- if (res == EBUSY)
- return false;
- PERFETTO_FATAL("pthread_mutex_trylock() failed");
+void RBRemoveColor(RBNode** root, RBNode* parent, RBNode* elm) {
+ RBNode* tmp;
+ while ((elm == nullptr || elm->color == RBColor::BLACK) && elm != *root) {
+ if (parent->left == elm) {
+ tmp = parent->right;
+ if (tmp->color == RBColor::RED) {
+ RBSetBlackRed(tmp, parent);
+ RBRotateLeft(root, parent, tmp);
+ tmp = parent->right;
+ }
+ if ((tmp->left == nullptr || tmp->left->color == RBColor::BLACK) &&
+ (tmp->right == nullptr || tmp->right->color == RBColor::BLACK)) {
+ tmp->color = RBColor::RED;
+ elm = parent;
+ parent = elm->parent;
+ } else {
+ if (tmp->right == nullptr || tmp->right->color == RBColor::BLACK) {
+ RBNode* oleft;
+ if ((oleft = tmp->left))
+ oleft->color = RBColor::BLACK;
+ tmp->color = RBColor::RED;
+ RBRotateRight(root, tmp, oleft);
+ tmp = parent->right;
+ }
+ tmp->color = parent->color;
+ parent->color = RBColor::BLACK;
+ if (tmp->right)
+ tmp->right->color = RBColor::BLACK;
+ RBRotateLeft(root, parent, tmp);
+ elm = *root;
+ break;
+ }
+ } else {
+ tmp = parent->left;
+ if (tmp->color == RBColor::RED) {
+ RBSetBlackRed(tmp, parent);
+ RBRotateRight(root, parent, tmp);
+ tmp = parent->left;
+ }
+ if ((tmp->left == nullptr || tmp->left->color == RBColor::BLACK) &&
+ (tmp->right == nullptr || tmp->right->color == RBColor::BLACK)) {
+ tmp->color = RBColor::RED;
+ elm = parent;
+ parent = elm->parent;
+ } else {
+ if (tmp->left == nullptr || tmp->left->color == RBColor::BLACK) {
+ RBNode* oright;
+ if ((oright = tmp->right))
+ oright->color = RBColor::BLACK;
+ tmp->color = RBColor::RED;
+ RBRotateLeft(root, tmp, oright);
+ tmp = parent->left;
+ }
+ tmp->color = parent->color;
+ parent->color = RBColor::BLACK;
+ if (tmp->left)
+ tmp->left->color = RBColor::BLACK;
+ RBRotateRight(root, parent, tmp);
+ elm = *root;
+ break;
+ }
+ }
+ }
+ if (elm)
+ elm->color = RBColor::BLACK;
}
-void RtPosixMutex::lock() noexcept {
- PERFETTO_CHECK(pthread_mutex_lock(&mutex_) == 0);
+} // namespace
+
+void RBInsertColor(RBNode** root, RBNode* elm) {
+ RBNode *parent, *gparent, *tmp;
+ while ((parent = elm->parent) && parent->color == RBColor::RED) {
+ gparent = parent->parent;
+ if (parent == gparent->left) {
+ tmp = gparent->right;
+ if (tmp && tmp->color == RBColor::RED) {
+ tmp->color = RBColor::BLACK;
+ RBSetBlackRed(parent, gparent);
+ elm = gparent;
+ continue;
+ }
+ if (parent->right == elm) {
+ RBRotateLeft(root, parent, tmp);
+ tmp = parent;
+ parent = elm;
+ elm = tmp;
+ }
+ RBSetBlackRed(parent, gparent);
+ RBRotateRight(root, gparent, tmp);
+ } else {
+ tmp = gparent->left;
+ if (tmp && tmp->color == RBColor::RED) {
+ tmp->color = RBColor::BLACK;
+ RBSetBlackRed(parent, gparent);
+ elm = gparent;
+ continue;
+ }
+ if (parent->left == elm) {
+ RBRotateRight(root, parent, tmp);
+ tmp = parent;
+ parent = elm;
+ elm = tmp;
+ }
+ RBSetBlackRed(parent, gparent);
+ RBRotateLeft(root, gparent, tmp);
+ }
+ }
+ (*root)->color = RBColor::BLACK;
}
-void RtPosixMutex::unlock() noexcept {
- PERFETTO_CHECK(pthread_mutex_unlock(&mutex_) == 0);
+void RBRemove(RBNode** root, RBNode* elm) {
+ RBNode* child = elm;
+ RBNode* parent = elm;
+ RBNode* old = elm;
+ RBColor color;
+
+ if (elm->left == nullptr)
+ child = elm->right;
+ else if (elm->right == nullptr)
+ child = elm->left;
+ else {
+ RBNode* left;
+ elm = elm->right;
+ while ((left = elm->left))
+ elm = left;
+ child = elm->right;
+ parent = elm->parent;
+ color = elm->color;
+ if (child)
+ child->parent = parent;
+ if (parent) {
+ if (parent->left == elm) {
+ parent->left = child;
+ } else {
+ parent->right = child;
+ }
+ // RB_AUGMENT(parent);
+ } else {
+ *root = child;
+ }
+ if (elm->parent == old)
+ parent = elm;
+ *elm = *old;
+ if (old->parent) {
+ if (old->parent->left == old) {
+ old->parent->left = elm;
+ } else {
+ old->parent->right = elm;
+ }
+ // RB_AUGMENT(old->parent);
+ } else {
+ *root = elm;
+ }
+ old->left->parent = elm;
+ if (old->right)
+ old->right->parent = elm;
+ if (parent) {
+ left = parent;
+ // do {
+ // RB_AUGMENT(left);
+ // } while ((left = left->parent));
+ }
+ goto color;
+ }
+ parent = elm->parent;
+ color = elm->color;
+ if (child)
+ child->parent = parent;
+ if (parent) {
+ if (parent->left == elm)
+ parent->left = child;
+ else
+ parent->right = child;
+ // RB_AUGMENT(parent);
+ } else {
+ *root = child;
+ }
+color:
+ if (color == RBColor::BLACK)
+ RBRemoveColor(root, parent, child);
}
-#endif // PERFETTO_HAS_POSIX_RT_MUTEX
+// Returns nullptr after reaching the last leaf (the max element).
+const RBNode* RBNext(const RBNode* node) {
+ if (node->right) {
+ node = node->right;
+ while (node->left)
+ node = node->left;
+ } else {
+ if (node->parent && node == node->parent->left) {
+ node = node->parent;
+ } else {
+ while (node->parent && node == node->parent->right) {
+ node = node->parent;
+ }
+ node = node->parent;
+ }
+ }
+ return node;
+}
-} // namespace internal
-} // namespace perfetto::base
-// gen_amalgamated begin source: src/base/scoped_mmap.cc
-// gen_amalgamated begin header: include/perfetto/ext/base/scoped_mmap.h
+} // namespace perfetto::base::internal
+// gen_amalgamated begin source: src/base/logging.cc
+// gen_amalgamated begin header: include/perfetto/ext/base/progress_reporter.h
/*
- * Copyright (C) 2024 The Android Open Source Project
+ * Copyright (C) 2026 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.
@@ -7757,86 +8192,60 @@ void RtPosixMutex::unlock() noexcept {
* limitations under the License.
*/
-#ifndef INCLUDE_PERFETTO_EXT_BASE_SCOPED_MMAP_H_
-#define INCLUDE_PERFETTO_EXT_BASE_SCOPED_MMAP_H_
-
-#include <cstddef>
+#ifndef INCLUDE_PERFETTO_EXT_BASE_PROGRESS_REPORTER_H_
+#define INCLUDE_PERFETTO_EXT_BASE_PROGRESS_REPORTER_H_
-// gen_amalgamated expanded: #include "perfetto/base/build_config.h"
-// gen_amalgamated expanded: #include "perfetto/ext/base/scoped_file.h"
+#include <cstdint>
+#include <mutex>
+#include <string_view>
-#if PERFETTO_BUILDFLAG(PERFETTO_OS_LINUX) || \
- PERFETTO_BUILDFLAG(PERFETTO_OS_APPLE) || \
- PERFETTO_BUILDFLAG(PERFETTO_OS_FREEBSD) || \
- PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID) || \
- PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
-#define PERFETTO_HAS_MMAP() 1
-#else
-#define PERFETTO_HAS_MMAP() 0
-#endif
+// gen_amalgamated expanded: #include "perfetto/base/thread_annotations.h"
namespace perfetto::base {
-// RAII wrapper that holds ownership of an mmap()d area and of a file. Calls
-// unmap() and close() on destruction.
-class ScopedMmap {
- public:
- // Creates a memory mapping for the first `length` bytes of `file`.
- static ScopedMmap FromHandle(base::ScopedPlatformHandle file, size_t length);
-
- ScopedMmap() {}
- ~ScopedMmap();
- ScopedMmap(ScopedMmap&& other) noexcept;
-
- ScopedMmap& operator=(ScopedMmap&& other) noexcept;
-
- // Returns a pointer to the mapped memory area. Only valid if `IsValid()` is
- // true.
- void* data() const { return ptr_; }
+// True if stderr is an interactive terminal (and TERM is not "dumb"). On WASM
+// this is always true: the embedder consumes stderr line by line.
+bool StderrSupportsProgress();
- // Returns true if this object contains a successfully mapped area.
- bool IsValid() const { return ptr_ != nullptr; }
+// True if ANSI colors should be emitted on stderr. Nonempty FORCE_COLOR forces
+// them on, otherwise nonempty NO_COLOR forces them off, otherwise they are
+// used when stderr is an interactive terminal.
+bool StderrSupportsColor();
- // Returns the length of the mapped area.
- size_t length() const { return length_; }
+// Process-wide, throttled, single-line progress display on stderr. Updates are
+// only shown when StderrSupportsProgress(). Log messages clear the line before
+// printing, so diagnostics never get merged with progress text.
+class ProgressReporter {
+ public:
+ static ProgressReporter& GetInstance();
- // Unmaps the area and closes the file. Returns false if this held a mmap()d
- // area and unmapping failed. In any case, after this method, `IsValid()` will
- // return false.
- bool reset() noexcept;
+ // Suppresses all progress output. Diagnostics are unaffected.
+ void set_enabled(bool enabled);
-#if PERFETTO_BUILDFLAG(PERFETTO_OS_LINUX) || \
- PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID) || \
- PERFETTO_BUILDFLAG(PERFETTO_OS_FREEBSD) || \
- PERFETTO_BUILDFLAG(PERFETTO_OS_APPLE)
- // Takes ownership of an mmap()d area that starts at `data`, `size` bytes
- // long. `data` should not be MAP_FAILED.
- static ScopedMmap InheritMmappedRange(void* data, size_t size);
-#endif
+ // |message| must be plain ASCII without newlines or terminal escapes.
+ void Update(std::string_view message);
+ void Clear();
private:
- ScopedMmap(const ScopedMmap&) = delete;
- ScopedMmap& operator=(const ScopedMmap&) = delete;
-
- size_t length_ = 0;
- void* ptr_ = nullptr;
- ScopedPlatformHandle file_;
-#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
- ScopedPlatformHandle map_;
-#endif
-};
+ ProgressReporter() = default;
+ ~ProgressReporter() = default;
+ ProgressReporter(const ProgressReporter&) = delete;
+ ProgressReporter& operator=(const ProgressReporter&) = delete;
-// Tries to open `file_path` and maps its first `length` bytes in memory.
-ScopedMmap ReadMmapFilePart(const std::string& file_path, size_t length);
+ void ClearLocked() PERFETTO_EXCLUSIVE_LOCKS_REQUIRED(mutex_);
-// Tries to open `file_path` and maps the whole file into memory.
-ScopedMmap ReadMmapWholeFile(const std::string& file_path);
+ std::mutex mutex_;
+ bool enabled_ PERFETTO_GUARDED_BY(mutex_) = true;
+ int64_t last_update_ms_ PERFETTO_GUARDED_BY(mutex_) = 0;
+ size_t visible_width_ PERFETTO_GUARDED_BY(mutex_) = 0;
+};
} // namespace perfetto::base
-
-#endif // INCLUDE_PERFETTO_EXT_BASE_SCOPED_MMAP_H_
+#endif // INCLUDE_PERFETTO_EXT_BASE_PROGRESS_REPORTER_H_
+// gen_amalgamated begin header: src/base/log_ring_buffer.h
+// gen_amalgamated begin header: include/perfetto/ext/base/thread_annotations.h
/*
- * Copyright (C) 2024 The Android Open Source Project
+ * 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.
@@ -7851,169 +8260,30 @@ ScopedMmap ReadMmapWholeFile(const std::string& file_path);
* limitations under the License.
*/
-// gen_amalgamated expanded: #include "perfetto/ext/base/scoped_mmap.h"
-
-#include <utility>
-
-// gen_amalgamated expanded: #include "perfetto/ext/base/file_utils.h"
-// gen_amalgamated expanded: #include "perfetto/ext/base/scoped_file.h"
-
-#if PERFETTO_BUILDFLAG(PERFETTO_OS_LINUX) || \
- PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID) || \
- PERFETTO_BUILDFLAG(PERFETTO_OS_FREEBSD) || \
- PERFETTO_BUILDFLAG(PERFETTO_OS_APPLE)
-#include <sys/mman.h>
-#include <unistd.h>
-#elif PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
-#include <windows.h>
-#endif
-
-namespace perfetto::base {
-namespace {
-
-ScopedPlatformHandle OpenFileForMmap(const std::string& file_path) {
-#if PERFETTO_BUILDFLAG(PERFETTO_OS_LINUX) || \
- PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID) || \
- PERFETTO_BUILDFLAG(PERFETTO_OS_FREEBSD) || \
- PERFETTO_BUILDFLAG(PERFETTO_OS_APPLE)
- return OpenFile(file_path, O_RDONLY);
-#elif PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
- // This does not use base::OpenFile to avoid getting an exclusive lock.
- //
- // The share flags mirror the POSIX open(O_RDONLY) above, which has no notion
- // of share modes. Same flags as LLVM's openNativeFileInternal():
- // https://github.com/llvm/llvm-project/blob/main/llvm/lib/Support/Windows/Path.inc
- return ScopedPlatformHandle(
- CreateFileA(file_path.c_str(), GENERIC_READ,
- FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
- nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr));
-#else
- // mmap is not supported. Do not even open the file.
- base::ignore_result(file_path);
- return ScopedPlatformHandle();
-#endif
-}
-
-} // namespace
-
-ScopedMmap::ScopedMmap(ScopedMmap&& other) noexcept {
- *this = std::move(other);
-}
-
-ScopedMmap& ScopedMmap::operator=(ScopedMmap&& other) noexcept {
- if (this == &other) {
- return *this;
- }
- reset();
- std::swap(ptr_, other.ptr_);
- std::swap(length_, other.length_);
- std::swap(file_, other.file_);
-#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
- std::swap(map_, other.map_);
-#endif
- return *this;
-}
-
-ScopedMmap::~ScopedMmap() {
- reset();
-}
-
-// static
-ScopedMmap ScopedMmap::FromHandle(base::ScopedPlatformHandle file,
- size_t length) {
- ScopedMmap ret;
- if (!file) {
- return ret;
- }
-#if PERFETTO_BUILDFLAG(PERFETTO_OS_LINUX) || \
- PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID) || \
- PERFETTO_BUILDFLAG(PERFETTO_OS_FREEBSD) || \
- PERFETTO_BUILDFLAG(PERFETTO_OS_APPLE)
- void* ptr = mmap(nullptr, length, PROT_READ, MAP_PRIVATE, *file, 0);
- if (ptr != MAP_FAILED) {
- ret.ptr_ = ptr;
- ret.length_ = length;
- ret.file_ = std::move(file);
- }
-#elif PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
- ScopedPlatformHandle map(
- CreateFileMapping(*file, nullptr, PAGE_READONLY, 0, 0, nullptr));
- if (!map) {
- return ret;
- }
- void* ptr = MapViewOfFile(*map, FILE_MAP_READ, 0, 0, length);
- if (ptr != nullptr) {
- ret.ptr_ = ptr;
- ret.length_ = length;
- ret.file_ = std::move(file);
- ret.map_ = std::move(map);
- }
-#else
- base::ignore_result(length);
-#endif
- return ret;
-}
-
-bool ScopedMmap::reset() noexcept {
- bool ret = true;
-#if PERFETTO_BUILDFLAG(PERFETTO_OS_LINUX) || \
- PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID) || \
- PERFETTO_BUILDFLAG(PERFETTO_OS_FREEBSD) || \
- PERFETTO_BUILDFLAG(PERFETTO_OS_APPLE)
- if (ptr_ != nullptr) {
- ret = munmap(ptr_, length_) == 0;
- }
-#elif PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
- if (ptr_ != nullptr) {
- ret = UnmapViewOfFile(ptr_);
- }
- map_.reset();
-#endif
- ptr_ = nullptr;
- length_ = 0;
- file_.reset();
- return ret;
-}
+#ifndef INCLUDE_PERFETTO_EXT_BASE_THREAD_ANNOTATIONS_H_
+#define INCLUDE_PERFETTO_EXT_BASE_THREAD_ANNOTATIONS_H_
-#if PERFETTO_BUILDFLAG(PERFETTO_OS_LINUX) || \
- PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID) || \
- PERFETTO_BUILDFLAG(PERFETTO_OS_FREEBSD) || \
- PERFETTO_BUILDFLAG(PERFETTO_OS_APPLE)
-// static
-ScopedMmap ScopedMmap::InheritMmappedRange(void* data, size_t size) {
- ScopedMmap ret;
- ret.ptr_ = data;
- ret.length_ = size;
- return ret;
-}
-#endif
+// gen_amalgamated expanded: #include "perfetto/base/build_config.h"
-ScopedMmap ReadMmapFilePart(const std::string& fname, size_t length) {
- return ScopedMmap::FromHandle(OpenFileForMmap(fname), length);
+// Windows TSAN doesn't currently support these annotations.
+#if defined(THREAD_SANITIZER) && !PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
+extern "C" {
+void AnnotateBenignRaceSized(const char* file,
+ int line,
+ const volatile void* address,
+ size_t size,
+ const char* description);
}
-ScopedMmap ReadMmapWholeFile(const std::string& fname) {
- ScopedPlatformHandle file = OpenFileForMmap(fname);
- if (!file) {
- return ScopedMmap();
- }
- std::optional<uint64_t> file_size = GetFileSize(file.get());
- if (!file_size.has_value()) {
- return ScopedMmap();
- }
- size_t size = static_cast<size_t>(*file_size);
- if (static_cast<uint64_t>(size) != *file_size) {
- return ScopedMmap();
- }
- return ScopedMmap::FromHandle(std::move(file), size);
-}
+#define PERFETTO_ANNOTATE_BENIGN_RACE_SIZED(pointer, size, description) \
+ AnnotateBenignRaceSized(__FILE__, __LINE__, pointer, size, description);
+#else // defined(ADDRESS_SANITIZER)
+#define PERFETTO_ANNOTATE_BENIGN_RACE_SIZED(pointer, size, description)
+#endif // defined(ADDRESS_SANITIZER)
-} // namespace perfetto::base
-// gen_amalgamated begin source: src/base/scoped_sched_boost.cc
-// gen_amalgamated begin header: include/perfetto/ext/base/scoped_sched_boost.h
-// gen_amalgamated begin header: include/perfetto/ext/base/status_or.h
+#endif // INCLUDE_PERFETTO_EXT_BASE_THREAD_ANNOTATIONS_H_
/*
- * Copyright (C) 2022 The Android Open Source Project
+ * Copyright (C) 2021 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.
@@ -8028,75 +8298,152 @@ ScopedMmap ReadMmapWholeFile(const std::string& fname) {
* limitations under the License.
*/
-#ifndef INCLUDE_PERFETTO_EXT_BASE_STATUS_OR_H_
-#define INCLUDE_PERFETTO_EXT_BASE_STATUS_OR_H_
+#ifndef SRC_BASE_LOG_RING_BUFFER_H_
+#define SRC_BASE_LOG_RING_BUFFER_H_
-#include <optional>
+#include <stddef.h>
+#include <stdio.h>
-// gen_amalgamated expanded: #include "perfetto/base/status.h"
+#include <array>
+#include <atomic>
+
+// gen_amalgamated expanded: #include "perfetto/ext/base/string_view.h"
+// gen_amalgamated expanded: #include "perfetto/ext/base/thread_annotations.h"
namespace perfetto {
namespace base {
-// Union of a object of type |T| with a |base::Status|. Useful for cases where
-// a |T| indicates a successful result of an operation and |base::Status|
-// represents an error.
+// Defined out of line because a static constexpr requires static storage if
+// ODR-used, not worth adding a .cc file just for tests.
+constexpr size_t kLogRingBufEntries = 8;
+constexpr size_t kLogRingBufMsgLen = 256;
+
+// A static non-allocating ring-buffer to hold the most recent log events.
+// This class is really an implementation detail of logging.cc. The only reason
+// why is fully defined in a dedicated header is for allowing unittesting,
+// without leaking extra headers into logging.h (which is a high-fanout header).
+// This is used to report the last logs in a crash report when a CHECK/FATAL
+// is encountered.
+// This class has just an Append() method to insert events into the buffer and
+// a Read() to read the events in FIFO order. Read() is non-destructive.
//
-// This class is modelled closely on absl::Status and should essentially 1:1
-// match it's API.
-template <typename T>
-class StatusOr {
+// Thread safety considerations:
+// - The Append() method can be called concurrently by several threads, unless
+// there are > kLogRingBufEntries concurrent threads. Even if that happens,
+// case some events will contain a mix of strings but the behavior of
+// further Append() and Read() is still defined.
+// - The Read() method is not thread safe but it's fine in practice. Even if
+// it's called concurrently with other Append(), it only causes some partial
+// events to be emitted in output.
+// In both cases, we never rely purely on \0, all operations are size-bound.
+//
+// See logging_unittest.cc for tests.
+class LogRingBuffer {
public:
- // Matches naming of declarations in similar types e.g. std::optional,
- // std::variant.
- using value_type = T;
+ LogRingBuffer() = default;
+ LogRingBuffer(const LogRingBuffer&) = delete;
+ LogRingBuffer& operator=(const LogRingBuffer&) = delete;
+ LogRingBuffer(LogRingBuffer&&) = delete;
+ LogRingBuffer& operator=(LogRingBuffer&&) = delete;
- // Intentionally implicit to allow idomatic usage (e.g. returning value/status
- // from base::StatusOr returning function).
- StatusOr(base::Status status) : StatusOr(std::move(status), std::nullopt) {
- if (status_.ok()) {
- // Matches what Abseil's approach towards OkStatus being passed to
- // absl::StatusOr<T>.
- PERFETTO_FATAL("base::OkStatus passed to StatusOr: this is not allowed");
- }
- }
- StatusOr(T value) : StatusOr(base::OkStatus(), std::move(value)) {}
-
- bool ok() const { return status_.ok(); }
- const base::Status& status() const { return status_; }
+ // This takes three arguments because it fits its only caller (logging.cc).
+ // The args are just concatenated together (plus one space before the msg).
+ void Append(StringView tstamp, StringView source, StringView log_msg) {
+ // Reserve atomically a slot in the ring buffer, so any concurrent Append()
+ // won't overlap (unless too many concurrent Append() happen together).
+ // There is no strict synchronization here, |event_slot_| is atomic only for
+ // the sake of avoiding colliding on the same slot but does NOT guarantee
+ // full consistency and integrity of the log messages written in each slot.
+ // A release-store (or acq+rel) won't be enough for full consistency. Two
+ // threads that race on Append() and take the N+1 and N+2 slots could finish
+ // the write in reverse order. So Read() would need to synchronize with
+ // something else (either a per-slot atomic flag or with a second atomic
+ // counter which is incremented after the snprintf). Both options increase
+ // the cost of Append() with no huge benefits (90% of the perfetto services
+ // where we use it is single thread, and the log ring buffer is disabled
+ // on non-standalone builds like the SDK).
+ uint32_t slot = event_slot_.fetch_add(1, std::memory_order_relaxed);
+ slot = slot % kLogRingBufEntries;
- T& value() {
- PERFETTO_DCHECK(status_.ok());
- return *value_;
+ char* const msg = events_[slot];
+ PERFETTO_ANNOTATE_BENIGN_RACE_SIZED(msg, kLogRingBufMsgLen,
+ "see comments in log_ring_buffer.h")
+ snprintf(msg, kLogRingBufMsgLen, "%.*s%.*s %.*s",
+ static_cast<int>(tstamp.size()), tstamp.data(),
+ static_cast<int>(source.size()), source.data(),
+ static_cast<int>(log_msg.size()), log_msg.data());
}
- const T& value() const { return *value_; }
-
- T& operator*() { return value(); }
- const T& operator*() const { return value(); }
- T* operator->() { return &value(); }
- const T* operator->() const { return &value(); }
+ // Reads back the buffer in FIFO order, up to |len - 1| characters at most
+ // (the -1 is because a NUL terminator is always appended, unless |len| == 0).
+ // The string written in |dst| is guaranteed to be NUL-terminated, even if
+ // |len| < buffer contents length.
+ // Returns the number of bytes written in output, excluding the \0 terminator.
+ size_t Read(char* dst, size_t len) {
+ if (len == 0)
+ return 0;
+ // This is a relaxed-load because we don't need to fully synchronize on the
+ // writing path for the reasons described in the fetch_add() above.
+ const uint32_t event_slot = event_slot_.load(std::memory_order_relaxed);
+ size_t dst_written = 0;
+ for (uint32_t pos = 0; pos < kLogRingBufEntries; ++pos) {
+ const uint32_t slot = (event_slot + pos) % kLogRingBufEntries;
+ const char* src = events_[slot];
+ if (*src == '\0')
+ continue; // Empty slot. Skip.
+ char* const wptr = dst + dst_written;
+ // |src| might not be null terminated. This can happen if some
+ // thread-race happened. Limit the copy length.
+ const size_t limit = std::min(len - dst_written, kLogRingBufMsgLen);
+ for (size_t i = 0; i < limit; ++i) {
+ const char c = src[i];
+ ++dst_written;
+ if (c == '\0' || i == limit - 1) {
+ wptr[i] = '\n';
+ break;
+ }
+ // Skip non-printable ASCII characters to avoid confusing crash reports.
+ // Note that this deliberately mangles \n. Log messages should not have
+ // a \n in the middle and are NOT \n terminated. The trailing \n between
+ // each line is appended by the if () branch above.
+ const bool is_printable = c >= ' ' && c <= '~';
+ wptr[i] = is_printable ? c : '?';
+ }
+ }
+ // Ensure that the output string is null-terminated.
+ PERFETTO_DCHECK(dst_written <= len);
+ if (dst_written == len) {
+ // In case of truncation we replace the last char with \0. But the return
+ // value is the number of chars without \0, hence the --.
+ dst[--dst_written] = '\0';
+ } else {
+ dst[dst_written] = '\0';
+ }
+ return dst_written;
+ }
private:
- StatusOr(base::Status status, std::optional<T> value)
- : status_(std::move(status)), value_(std::move(value)) {
- PERFETTO_DCHECK(!status_.ok() || value_.has_value());
- }
+ using EventBuf = char[kLogRingBufMsgLen];
+ EventBuf events_[kLogRingBufEntries]{};
- base::Status status_;
- std::optional<T> value_;
-};
+ static_assert((kLogRingBufEntries & (kLogRingBufEntries - 1)) == 0,
+ "kLogRingBufEntries must be a power of two");
-// Deduction guide to make returning StatusOr less verbose.
-template <typename T>
-StatusOr(T) -> StatusOr<T>;
+ // A monotonically increasing counter incremented on each event written.
+ // It determines which of the kLogRingBufEntries indexes in |events_| should
+ // be used next.
+ // It grows >> kLogRingBufEntries, it's supposed to be always used
+ // mod(kLogRingBufEntries). A static_assert in the .cc file ensures that
+ // kLogRingBufEntries is a power of two so wraps are aligned.
+ std::atomic<uint32_t> event_slot_{};
+};
} // namespace base
} // namespace perfetto
-#endif // INCLUDE_PERFETTO_EXT_BASE_STATUS_OR_H_
+#endif // SRC_BASE_LOG_RING_BUFFER_H_
/*
- * Copyright (C) 2025 The Android Open Source Project
+ * 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.
@@ -8111,134 +8458,233 @@ StatusOr(T) -> StatusOr<T>;
* limitations under the License.
*/
-#ifndef INCLUDE_PERFETTO_EXT_BASE_SCOPED_SCHED_BOOST_H_
-#define INCLUDE_PERFETTO_EXT_BASE_SCOPED_SCHED_BOOST_H_
+// gen_amalgamated expanded: #include "perfetto/base/logging.h"
+// gen_amalgamated expanded: #include "perfetto/ext/base/progress_reporter.h"
-// gen_amalgamated expanded: #include "perfetto/ext/base/status_or.h"
-// gen_amalgamated expanded: #include "perfetto/ext/base/thread_checker.h"
+#include <stdarg.h>
+#include <stdio.h>
-namespace perfetto::base {
+#if !PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
+#include <unistd.h> // For isatty()
+#endif
-// kSchedOther: it's the default policy (e.g., CFS on Linux). Range: 0-20.
-// prio is interpreted as -(nice), i.e., 1 is slightly higher prio
-// than default 0, 20 is the highest priority.
-// Note that this is the opposite semantic of the cmdline nice, and
-// is done for consistency with kSchedFifo, so higher
-// number == higher prio.
-// kSchedFifo: real-time priority. Range: 1-99. 1 is the lowest priority, 99 the
-// highest.
-struct SchedPolicyAndPrio {
- enum class Policy {
- kSchedOther,
- kSchedFifo
- }; // Order matters for operator<().
+#include <atomic>
+#include <memory>
- bool operator<(const SchedPolicyAndPrio& other) const {
- return std::tie(policy, prio) < std::tie(other.policy, other.prio);
- }
+// gen_amalgamated expanded: #include "perfetto/base/build_config.h"
+// gen_amalgamated expanded: #include "perfetto/base/time.h"
+// gen_amalgamated expanded: #include "perfetto/ext/base/crash_keys.h"
+// gen_amalgamated expanded: #include "perfetto/ext/base/string_utils.h"
+// gen_amalgamated expanded: #include "perfetto/ext/base/string_view.h"
+// gen_amalgamated expanded: #include "src/base/log_ring_buffer.h"
- bool operator==(const SchedPolicyAndPrio& other) const {
- return policy == other.policy && prio == other.prio;
- }
+#if PERFETTO_ENABLE_LOG_RING_BUFFER() && PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID)
+#include <android/set_abort_message.h>
+#endif
- bool operator!=(const SchedPolicyAndPrio& other) const {
- return !(*this == other);
- }
+// The __attribute__((constructor)) below is intentional, it sets the crash
+// reporter globally for Perfetto. It's only enabled on debug builds so should
+// be pretty safe.
+#if defined(__clang__)
+#pragma clang diagnostic ignored "-Wglobal-constructors"
+#endif
- Policy policy = Policy::kSchedOther;
- uint32_t prio = 0;
-};
+namespace perfetto {
+namespace base {
-// Used to mock Linux scheduling policy and parameters API in tests.
-// In production code calls the Linux API, the class is stateless.
-class SchedOsHooks {
- public:
- struct SchedOsConfig {
- int policy;
- int rt_prio;
- int nice;
- };
+namespace {
+const char kReset[] = "\x1b[0m";
+const char kDefault[] = "\x1b[39m";
+const char kDim[] = "\x1b[2m";
+const char kRed[] = "\x1b[31m";
+const char kBoldGreen[] = "\x1b[1m\x1b[32m";
+const char kLightGray[] = "\x1b[90m";
- virtual ~SchedOsHooks() = default;
- static SchedOsHooks* GetInstance();
- // virtual for testing
- virtual Status SetSchedConfig(const SchedOsConfig& arg);
- // virtual for testing
- virtual StatusOr<SchedOsConfig> GetCurrentSchedConfig() const;
-};
+std::atomic<LogMessageCallback> g_log_callback{};
-// RAII helper to temporarily boost the scheduler priority of the current
-// thread. The priority is reverted to the original value when the object goes
-// out of scope.
-// It is supported only on Linux/Android, fails on other platforms.
-class ScopedSchedBoost {
- public:
- static StatusOr<ScopedSchedBoost> Boost(SchedPolicyAndPrio);
- ScopedSchedBoost(ScopedSchedBoost&&) noexcept;
- ScopedSchedBoost& operator=(ScopedSchedBoost&&) noexcept;
- ~ScopedSchedBoost();
+#if PERFETTO_BUILDFLAG(PERFETTO_STDERR_CRASH_DUMP)
+// __attribute__((constructor)) causes a static initializer that automagically
+// early runs this function before the main().
+void PERFETTO_EXPORT_COMPONENT __attribute__((constructor))
+InitDebugCrashReporter() {
+ // This function is defined in debug_crash_stack_trace.cc.
+ // The dynamic initializer is in logging.cc because logging.cc is included
+ // in virtually any target that depends on base. Having it in
+ // debug_crash_stack_trace.cc would require figuring out -Wl,whole-archive
+ // which is not worth it.
+ EnableStacktraceOnCrashForDebug();
+}
+#endif
- // No copy constructors.
- ScopedSchedBoost(const ScopedSchedBoost&) = delete;
- ScopedSchedBoost& operator=(const ScopedSchedBoost&) = delete;
+#if PERFETTO_ENABLE_LOG_RING_BUFFER()
+LogRingBuffer g_log_ring_buffer{};
- static void ResetForTesting(SchedOsHooks*);
+// This is global to avoid allocating memory or growing too much the stack
+// in MaybeSerializeLastLogsForCrashReporting(), which is called from
+// arbitrary code paths hitting PERFETTO_CHECK()/FATAL().
+char g_crash_buf[kLogRingBufEntries * kLogRingBufMsgLen];
+#endif
- private:
- explicit ScopedSchedBoost(SchedPolicyAndPrio p) : policy_and_prio_(p) {}
+} // namespace
- std::optional<SchedPolicyAndPrio> policy_and_prio_;
- ThreadChecker thread_checker_;
-};
-} // namespace perfetto::base
+void SetLogMessageCallback(LogMessageCallback callback) {
+ g_log_callback.store(callback, std::memory_order_relaxed);
+}
-#endif // INCLUDE_PERFETTO_EXT_BASE_SCOPED_SCHED_BOOST_H_
-// gen_amalgamated begin header: include/perfetto/ext/base/status_macros.h
-/*
- * 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.
- */
+void LogMessage(LogLev level,
+ const char* fname,
+ int line,
+ const char* fmt,
+ ...) {
+ char stack_buf[512];
+ std::unique_ptr<char[]> large_buf;
+ char* log_msg = &stack_buf[0];
+ size_t log_msg_len = 0;
-#ifndef INCLUDE_PERFETTO_EXT_BASE_STATUS_MACROS_H_
-#define INCLUDE_PERFETTO_EXT_BASE_STATUS_MACROS_H_
+ // By default use a stack allocated buffer because most log messages are quite
+ // short. In rare cases they can be larger (e.g. --help). In those cases we
+ // pay the cost of allocating the buffer on the heap.
+ for (size_t max_len = sizeof(stack_buf);;) {
+ va_list args;
+ va_start(args, fmt);
+ int res = vsnprintf(log_msg, max_len, fmt, args);
+ va_end(args);
-// gen_amalgamated expanded: #include "perfetto/base/status.h"
+ // If for any reason the print fails, overwrite the message but still print
+ // it. The code below will attach the filename and line, which is still
+ // useful.
+ if (res < 0) {
+ snprintf(log_msg, max_len, "%s", "[printf format error]");
+ break;
+ }
-// Evaluates |expr|, which should return a base::Status. If the status is an
-// error status, returns the status from the current function.
-#define RETURN_IF_ERROR(expr) \
- do { \
- ::perfetto::base::Status status_macro_internal_status = (expr); \
- if (!status_macro_internal_status.ok()) \
- return status_macro_internal_status; \
- } while (0)
+ // if res == max_len, vsnprintf saturated the input buffer. Retry with a
+ // larger buffer in that case (within reasonable limits).
+ if (res < static_cast<int>(max_len) || max_len >= 128 * 1024) {
+ // In case of truncation vsnprintf returns the len that "would have been
+ // written if the string was longer", not the actual chars written.
+ log_msg_len = std::min(static_cast<size_t>(res), max_len - 1);
+ break;
+ }
+ max_len *= 4;
+ large_buf.reset(new char[max_len]);
+ log_msg = &large_buf[0];
+ }
-#define PERFETTO_INTERNAL_CONCAT_IMPL(x, y) x##y
-#define PERFETTO_INTERNAL_MACRO_CONCAT(x, y) PERFETTO_INTERNAL_CONCAT_IMPL(x, y)
+ ProgressReporter::GetInstance().Clear();
+ LogMessageCallback cb = g_log_callback.load(std::memory_order_relaxed);
+ if (cb) {
+ cb({level, line, fname, log_msg});
+ return;
+ }
-// Evalues |rhs| which should return a base::StatusOr<T> and assigns this
-// to |lhs|. If the status is an error status, returns the status from the
-// current function.
-#define ASSIGN_OR_RETURN(lhs, rhs) \
- PERFETTO_INTERNAL_MACRO_CONCAT(auto status_or, __LINE__) = rhs; \
- RETURN_IF_ERROR( \
- PERFETTO_INTERNAL_MACRO_CONCAT(status_or, __LINE__).status()); \
- lhs = std::move(PERFETTO_INTERNAL_MACRO_CONCAT(status_or, __LINE__).value())
+ const char* color = kDefault;
+ switch (level) {
+ case kLogDebug:
+ color = kDim;
+ break;
+ case kLogInfo:
+ color = kDefault;
+ break;
+ case kLogImportant:
+ color = kBoldGreen;
+ break;
+ case kLogError:
+ color = kRed;
+ break;
+ }
-#endif // INCLUDE_PERFETTO_EXT_BASE_STATUS_MACROS_H_
+ const bool use_colors = StderrSupportsColor();
+
+ // Formats file.cc:line as a space-padded fixed width string. If the file name
+ // |fname| is too long, truncate it on the left-hand side.
+ StackString<10> line_str("%d", line);
+
+ // 24 will be the width of the file.cc:line column in the log event.
+ static constexpr size_t kMaxNameAndLine = 24;
+ size_t fname_len = strlen(fname);
+ size_t fname_max = kMaxNameAndLine - line_str.len() - 2; // 2 = ':' + '\0'.
+ size_t fname_offset = fname_len <= fname_max ? 0 : fname_len - fname_max;
+ StackString<kMaxNameAndLine> file_and_line(
+ "%*s:%s", static_cast<int>(fname_max), &fname[fname_offset],
+ line_str.c_str());
+
+#if PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID)
+ // Logcat has already timestamping, don't re-emit it.
+ __android_log_print(int{ANDROID_LOG_DEBUG} + level, "perfetto", "%s %s",
+ file_and_line.c_str(), log_msg);
+#endif
+
+ // When printing on stderr, print also the timestamp. We don't really care
+ // about the actual time. We just need some reference clock that can be used
+ // to correlated events across different processes (e.g. traced and
+ // traced_probes). The wall time % 1000 is good enough.
+ uint32_t t_ms = static_cast<uint32_t>(GetWallTimeMs().count());
+ uint32_t t_sec = t_ms / 1000;
+ t_ms -= t_sec * 1000;
+ t_sec = t_sec % 1000;
+ StackString<32> timestamp("[%03u.%03u] ", t_sec, t_ms);
+
+ if (use_colors) {
+ fprintf(stderr, "%s%s%s%s %s%s%s\n", kLightGray, timestamp.c_str(),
+ file_and_line.c_str(), kReset, color, log_msg, kReset);
+ } else {
+ fprintf(stderr, "%s%s %s\n", timestamp.c_str(), file_and_line.c_str(),
+ log_msg);
+ }
+
+#if PERFETTO_ENABLE_LOG_RING_BUFFER()
+ // Append the message to the ring buffer for crash reporting postmortems.
+ StringView timestamp_sv = timestamp.string_view();
+ StringView file_and_line_sv = file_and_line.string_view();
+ StringView log_msg_sv(log_msg, static_cast<size_t>(log_msg_len));
+ g_log_ring_buffer.Append(timestamp_sv, file_and_line_sv, log_msg_sv);
+#else
+ ignore_result(log_msg_len);
+#endif
+}
+
+#if PERFETTO_ENABLE_LOG_RING_BUFFER()
+void MaybeSerializeLastLogsForCrashReporting() {
+ // Keep this function minimal. This is called from the watchdog thread, often
+ // when the system is thrashing.
+
+ // This is racy because two threads could hit a CHECK/FATAL at the same time.
+ // But if that happens we have bigger problems, not worth designing around it.
+ // The behaviour is still defined in the race case (the string attached to
+ // the crash report will contain a mixture of log strings).
+ size_t wr = 0;
+ wr += SerializeCrashKeys(&g_crash_buf[wr], sizeof(g_crash_buf) - wr);
+ wr += g_log_ring_buffer.Read(&g_crash_buf[wr], sizeof(g_crash_buf) - wr);
+
+ // Read() null-terminates the string properly. This is just to avoid UB when
+ // two threads race on each other (T1 writes a shorter string, T2
+ // overwrites the \0 writing a longer string. T1 continues here before T2
+ // finishes writing the longer string with the \0 -> boom.
+ g_crash_buf[sizeof(g_crash_buf) - 1] = '\0';
+
+#if PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID)
+ // android_set_abort_message() will cause debuggerd to report the message
+ // in the tombstone and in the crash log in logcat.
+ // NOTE: android_set_abort_message() can be called only once. This should
+ // be called only when we are sure we are about to crash.
+ android_set_abort_message(g_crash_buf);
+#else
+ // Print out the message on stderr on Linux/Mac/Win.
+ fputs("\n-----BEGIN PERFETTO PRE-CRASH LOG-----\n", stderr);
+ fputs(g_crash_buf, stderr);
+ fputs("\n-----END PERFETTO PRE-CRASH LOG-----\n", stderr);
+#endif
+}
+#endif // PERFETTO_ENABLE_LOG_RING_BUFFER
+
+} // namespace base
+} // namespace perfetto
+// gen_amalgamated begin source: src/base/metatrace.cc
+// gen_amalgamated begin header: include/perfetto/ext/base/metatrace.h
+// gen_amalgamated begin header: include/perfetto/ext/base/metatrace_events.h
/*
- * Copyright (C) 2018 The Android Open Source Project
+ * 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.
@@ -8253,249 +8699,132 @@ class ScopedSchedBoost {
* limitations under the License.
*/
-// gen_amalgamated expanded: #include "perfetto/ext/base/scoped_sched_boost.h"
-
-// gen_amalgamated expanded: #include "perfetto/ext/base/status_macros.h"
-
-#if PERFETTO_BUILDFLAG(PERFETTO_OS_LINUX) || \
- PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID)
-#include <sched.h> // for 'SCHED_' macros and 'sched_' functions
-#include <sys/resource.h> // for 'setpriority', 'getpriority', 'PRIO_PROCESS'
-#include <sys/types.h> // for 'pid_t'
-
-#include <algorithm>
-#include <vector>
-
-#endif // PERFETTO_OS_LINUX || PERFETTO_OS_ANDROID
-
-namespace perfetto::base {
-
-#if PERFETTO_BUILDFLAG(PERFETTO_OS_LINUX) || \
- PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID)
-
-namespace {
-constexpr pid_t kCurrentPid = 0;
-
-class ThreadMgr {
- public:
- // In this class we manage the boost state for the whole process.
- // If we want to use it for each single thread, this needs to become
- // 'GetInstanceForThread()'.
- static ThreadMgr* GetInstance();
-
- explicit ThreadMgr(SchedOsHooks*);
-
- Status Add(SchedPolicyAndPrio);
- void Remove(SchedPolicyAndPrio);
- Status RecalcAndUpdatePrio();
+#ifndef INCLUDE_PERFETTO_EXT_BASE_METATRACE_EVENTS_H_
+#define INCLUDE_PERFETTO_EXT_BASE_METATRACE_EVENTS_H_
- ThreadMgr(const ThreadMgr&) = delete;
- ThreadMgr& operator=(const ThreadMgr&) = delete;
- ThreadMgr(ThreadMgr&&) = delete;
- ThreadMgr& operator=(ThreadMgr&&) = delete;
+#include <stdint.h>
- void ResetForTesting(SchedOsHooks*);
+namespace perfetto {
+namespace metatrace {
- private:
- SchedOsHooks* os_hooks_;
- SchedOsHooks::SchedOsConfig initial_config_{};
- std::vector<SchedPolicyAndPrio> prios_;
+enum Tags : uint32_t {
+ TAG_NONE = 0,
+ TAG_ANY = uint32_t(-1),
+ TAG_FTRACE = 1 << 0,
+ TAG_PROC_POLLERS = 1 << 1,
+ TAG_TRACE_WRITER = 1 << 2,
+ TAG_TRACE_SERVICE = 1 << 3,
+ TAG_PRODUCER = 1 << 4,
};
-ThreadMgr* ThreadMgr::GetInstance() {
- static auto* instance = new ThreadMgr(SchedOsHooks::GetInstance());
- return instance;
-}
-ThreadMgr::ThreadMgr(SchedOsHooks* os_hooks) : os_hooks_(os_hooks) {
- auto res = os_hooks_->GetCurrentSchedConfig();
- if (!res.ok()) {
- // Should never fail: even without CAP_SYS_NICE we can always get our own
- // policy and prio. If something goes very wrong, log an error and use
- // SCHED_OTHER as initial config.
- PERFETTO_DFATAL_OR_ELOG("Failed to get default sched config: %s",
- res.status().c_message());
- initial_config_ = SchedOsHooks::SchedOsConfig{SCHED_OTHER, 0, 0};
- } else {
- initial_config_ = res.value();
- }
-}
+// The macros below generate matching enums and arrays of string literals.
+// This is to avoid maintaining string maps manually.
-Status ThreadMgr::Add(SchedPolicyAndPrio spp) {
- prios_.push_back(spp);
- return RecalcAndUpdatePrio();
-}
+// clang-format off
-void ThreadMgr::Remove(SchedPolicyAndPrio spp) {
- auto it = std::find(prios_.begin(), prios_.end(), spp);
- if (it != prios_.end()) {
- prios_.erase(it);
- }
- // It is possible that we previously added the wrongly configured policy,
- // that wasn't the max policy. In that case the policy will be validated now,
- // in 'RecalcAndUpdatePrio'.
- // This for loop makes us ignore all wrongly configured policies and fallback
- // to the first correct (or the initial one).
- for (;;) {
- if (auto res = RecalcAndUpdatePrio(); !res.ok()) {
- PERFETTO_ELOG("%s", res.c_message());
- } else {
- break;
- }
- }
-}
-
-Status ThreadMgr::RecalcAndUpdatePrio() {
- if (prios_.empty()) {
- return os_hooks_->SetSchedConfig(initial_config_);
- }
- // TODO(ktimofeev): Check previously set prio to skip unnecessary syscall?
- auto max_prio = std::max_element(prios_.begin(), prios_.end());
- SchedOsHooks::SchedOsConfig os_config{};
- switch (max_prio->policy) {
- case SchedPolicyAndPrio::Policy::kSchedOther:
- os_config = SchedOsHooks::SchedOsConfig{
- SCHED_OTHER, 0, -1 * static_cast<int>(max_prio->prio)};
- break;
- case SchedPolicyAndPrio::Policy::kSchedFifo:
- os_config = SchedOsHooks::SchedOsConfig{
- SCHED_FIFO, static_cast<int>(max_prio->prio), 0};
- break;
- }
- Status res = os_hooks_->SetSchedConfig(os_config);
- if (!res.ok()) {
- prios_.erase(max_prio);
- return res;
- }
- return OkStatus();
-}
-
-void ThreadMgr::ResetForTesting(SchedOsHooks* os_hooks) {
- os_hooks_ = os_hooks;
- initial_config_ = os_hooks_->GetCurrentSchedConfig().value();
- prios_.clear();
-}
-
-} // namespace
-
-SchedOsHooks* SchedOsHooks::GetInstance() {
- static auto* instance = new SchedOsHooks();
- return instance;
-}
-
-Status SchedOsHooks::SetSchedConfig(const SchedOsConfig& arg) {
- sched_param param{};
- param.sched_priority = arg.rt_prio;
- int ret = sched_setscheduler(kCurrentPid, arg.policy, ¶m);
- if (ret == -1) {
- return ErrStatus("sched_setscheduler(%d, %d) failed (errno: %d, %s)",
- arg.policy, arg.rt_prio, errno, strerror(errno));
- }
- // For the real-time policies the 'arg.rt_prio' value is >= 1.
- // The userspace policies (SCHED_OTHER, SCHED_BATCH, SCHED_IDLE) use the nice
- // value.
- if (arg.rt_prio == 0) {
- ret = setpriority(PRIO_PROCESS, kCurrentPid, arg.nice);
- if (ret == -1) {
- return ErrStatus("setpriority(%d) failed (errno: %d, %s)", arg.nice,
- errno, strerror(errno));
- }
- }
- return OkStatus();
-}
-
-StatusOr<SchedOsHooks::SchedOsConfig> SchedOsHooks::GetCurrentSchedConfig()
- const {
- int policy = sched_getscheduler(kCurrentPid);
- if (policy == -1) {
- return ErrStatus("sched_getscheduler failed (errno: %d, %s)", errno,
- strerror(errno));
- }
- sched_param param{};
- if (sched_getparam(kCurrentPid, ¶m) == -1) {
- return ErrStatus("sched_getparam failed (errno: %d, %s)", errno,
- strerror(errno));
- }
- int nice = 0;
- // For the real-time policies the 'param.sched_priority' value is >= 1.
- // The userspace policies (SCHED_OTHER, SCHED_BATCH, SCHED_IDLE) use the nice
- // value.
- if (param.sched_priority == 0) {
- errno = 0;
- nice = getpriority(PRIO_PROCESS, kCurrentPid);
- if (nice == -1 && errno != 0) {
- return ErrStatus("getpriority failed (errno: %d, %s)", errno,
- strerror(errno));
- }
- }
- return SchedOsConfig{policy, param.sched_priority, nice};
-}
-
-// static
-StatusOr<ScopedSchedBoost> ScopedSchedBoost::Boost(SchedPolicyAndPrio spp) {
- auto res = ThreadMgr::GetInstance()->Add(spp);
- RETURN_IF_ERROR(res);
- return ScopedSchedBoost(spp);
-}
-
-ScopedSchedBoost::ScopedSchedBoost(ScopedSchedBoost&& other) noexcept {
- this->policy_and_prio_ = other.policy_and_prio_;
- other.policy_and_prio_ = std::nullopt;
-}
-
-ScopedSchedBoost& ScopedSchedBoost::operator=(
- ScopedSchedBoost&& other) noexcept {
- if (this != &other) {
- this->~ScopedSchedBoost();
- new (this) ScopedSchedBoost(std::move(other));
- }
- return *this;
-}
-
-ScopedSchedBoost::~ScopedSchedBoost() {
- PERFETTO_DCHECK_THREAD(thread_checker_);
- if (!policy_and_prio_.has_value())
- return;
- ThreadMgr::GetInstance()->Remove(*policy_and_prio_);
- policy_and_prio_ = std::nullopt;
-}
+// DO NOT remove or reshuffle items in this list, only append. The ID of these
+// events are an ABI, the trace processor relies on these to open old traces.
+#define PERFETTO_METATRACE_EVENTS(F) \
+ F(EVENT_ZERO_UNUSED), \
+ F(FTRACE_CPU_READER_READ), /*unused*/ \
+ F(FTRACE_DRAIN_CPUS), /*unused*/ \
+ F(FTRACE_UNBLOCK_READERS), /*unused*/ \
+ F(FTRACE_CPU_READ_NONBLOCK), /*unused*/ \
+ F(FTRACE_CPU_READ_BLOCK), /*unused*/ \
+ F(FTRACE_CPU_SPLICE_NONBLOCK), /*unused*/ \
+ F(FTRACE_CPU_SPLICE_BLOCK), /*unused*/ \
+ F(FTRACE_CPU_WAIT_CMD), /*unused*/ \
+ F(FTRACE_CPU_RUN_CYCLE), /*unused*/ \
+ F(FTRACE_CPU_FLUSH), \
+ F(FTRACE_CPU_BUFFER_WATERMARK), \
+ F(READ_SYS_STATS), \
+ F(PS_WRITE_ALL_PROCESSES), \
+ F(PS_ON_PIDS), \
+ F(PS_ON_RENAME_PIDS), \
+ F(PS_WRITE_ALL_PROCESS_STATS), \
+ F(TRACE_WRITER_COMMIT_STARTUP_WRITER_BATCH), \
+ F(FTRACE_READ_TICK), \
+ F(FTRACE_CPU_READ_CYCLE), \
+ F(FTRACE_CPU_READ_BATCH), \
+ F(KALLSYMS_PARSE), \
+ F(PROFILER_READ_TICK), \
+ F(PROFILER_READ_CPU), \
+ F(PROFILER_UNWIND_TICK), \
+ F(PROFILER_UNWIND_SAMPLE), \
+ F(PROFILER_UNWIND_INITIAL_ATTEMPT), \
+ F(PROFILER_UNWIND_ATTEMPT), \
+ F(PROFILER_MAPS_PARSE), \
+ F(PROFILER_MAPS_REPARSE), \
+ F(PROFILER_UNWIND_CACHE_CLEAR), \
+ F(ANDROID_CPU_PER_UID_TICK), \
+ F(ANDROID_KERNEL_WAKELOCKS_TICK), \
+ F(ANDROID_POWER_TICK), \
+ F(ANDROID_POWER_WRITE_BATTERY_COUNTERS), \
+ F(ANDROID_POWER_WRITE_ENERGY_ESTIMATION_BREAKDOWN), \
+ F(ANDROID_POWER_WRITE_ENTITY_STATE_RESIDENCY), \
+ F(ANDROID_POWER_WRITE_POWER_RAILS_DATA), \
+ F(LINUX_POWER_SYSFS_TICK), \
+ F(LINUX_SMAPS_ENQUEUE), \
+ F(LINUX_SMAPS_SERIALIZE)
-// static
-void ScopedSchedBoost::ResetForTesting(SchedOsHooks* os_manager) {
- ThreadMgr::GetInstance()->ResetForTesting(os_manager);
-}
+// Append only, see above.
+//
+// Values that aren't used as counters:
+// * FTRACE_SERVICE_COMMIT_DATA is a bit-packed representation of an event, see
+// tracing_service_impl.cc for the format.
+// * PROFILER_UNWIND_CURRENT_PID represents the PID that is being unwound.
+// * WATCHDOG_CRASH_REASON represents the base::WatchdogCrashReason enum.
+// * WATCHDOG_CRASH_TIME_BOOT_MS The time in ms since boot when the watchdog
+// timeout alarm triggered (i.e. when it would have caused a crash, without
+// counting for the optional handler time).
+// * WATCHDOG_CRASH_ACTUAL_{MONO,BOOT,CPU} are the elapsed seconds (since the
+// offending fatal timer was created) sampled from CLOCK_MONOTONIC,
+// CLOCK_BOOTTIME and CLOCK_PROCESS_CPUTIME_ID respectively.
+//
+#define PERFETTO_METATRACE_COUNTERS(F) \
+ F(COUNTER_ZERO_UNUSED),\
+ F(FTRACE_PAGES_DRAINED), \
+ F(PS_PIDS_SCANNED), \
+ F(TRACE_SERVICE_COMMIT_DATA), \
+ F(PROFILER_UNWIND_QUEUE_SZ), \
+ F(PROFILER_UNWIND_CURRENT_PID), \
+ F(WATCHDOG_CRASH_REASON), \
+ F(WATCHDOG_CRASH_TIME_BOOT_MS), \
+ F(WATCHDOG_CRASH_ACTUAL_MONO), \
+ F(WATCHDOG_CRASH_ACTUAL_BOOT), \
+ F(WATCHDOG_CRASH_ACTUAL_CPU), \
+ F(FTRACE_SESSIONS)
-#else
+// clang-format on
-// static
-SchedOsHooks* SchedOsHooks::GetInstance() {
- return nullptr;
-}
+#define PERFETTO_METATRACE_IDENTITY(name) name
+#define PERFETTO_METATRACE_TOSTRING(name) #name
-Status SchedOsHooks::SetSchedConfig(const SchedOsHooks::SchedOsConfig&) {
- return ErrStatus("SchedOsHooks is supported only on Linux/Android");
-}
+enum Events : uint16_t {
+ PERFETTO_METATRACE_EVENTS(PERFETTO_METATRACE_IDENTITY),
+ EVENTS_MAX
+};
+constexpr char const* kEventNames[] = {
+ PERFETTO_METATRACE_EVENTS(PERFETTO_METATRACE_TOSTRING)};
-StatusOr<SchedOsHooks::SchedOsConfig> SchedOsHooks::GetCurrentSchedConfig()
- const {
- return ErrStatus("SchedOsHooks is supported only on Linux/Android");
-}
+enum Counters : uint16_t {
+ PERFETTO_METATRACE_COUNTERS(PERFETTO_METATRACE_IDENTITY),
+ COUNTERS_MAX
+};
+constexpr char const* kCounterNames[] = {
+ PERFETTO_METATRACE_COUNTERS(PERFETTO_METATRACE_TOSTRING)};
-// static
-StatusOr<ScopedSchedBoost> ScopedSchedBoost::Boost(SchedPolicyAndPrio) {
- return ErrStatus("ScopedSchedBoost is supported only on Linux/Android");
+inline void SuppressUnusedVarsInAmalgamatedBuild() {
+ (void)kCounterNames;
+ (void)kEventNames;
}
-ScopedSchedBoost::ScopedSchedBoost(ScopedSchedBoost&&) noexcept = default;
-ScopedSchedBoost& ScopedSchedBoost::operator=(ScopedSchedBoost&&) noexcept =
- default;
-ScopedSchedBoost::~ScopedSchedBoost() = default;
-
-#endif // PERFETTO_OS_LINUX || PERFETTO_OS_ANDROID
+} // namespace metatrace
+} // namespace perfetto
-} // namespace perfetto::base
-// gen_amalgamated begin source: src/base/status.cc
+#endif // INCLUDE_PERFETTO_EXT_BASE_METATRACE_EVENTS_H_
/*
- * Copyright (C) 2020 The Android Open Source Project
+ * 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.
@@ -8510,190 +8839,308 @@ ScopedSchedBoost::~ScopedSchedBoost() = default;
* limitations under the License.
*/
-// gen_amalgamated expanded: #include "perfetto/base/status.h"
+#ifndef INCLUDE_PERFETTO_EXT_BASE_METATRACE_H_
+#define INCLUDE_PERFETTO_EXT_BASE_METATRACE_H_
-#include <algorithm>
-#include <cstdarg>
-#include <cstdio>
+#include <array>
+#include <atomic>
+#include <functional>
#include <string>
-#include <utility>
-namespace perfetto::base {
+// gen_amalgamated expanded: #include "perfetto/base/logging.h"
+// gen_amalgamated expanded: #include "perfetto/base/thread_utils.h"
+// gen_amalgamated expanded: #include "perfetto/base/time.h"
+// gen_amalgamated expanded: #include "perfetto/ext/base/metatrace_events.h"
+// gen_amalgamated expanded: #include "perfetto/ext/base/utils.h"
-Status ErrStatus(const char* format, ...) {
- std::string buf;
- buf.resize(1024);
- for (;;) {
- va_list ap;
- va_start(ap, format);
- int N = vsnprintf(buf.data(), buf.size() - 1, format, ap);
- va_end(ap);
+// A facility to trace execution of the perfetto codebase itself.
+// The meta-tracing framework is organized into three layers:
+//
+// 1. A static ring-buffer in base/ (this file) that supports concurrent writes
+// and a single reader.
+// The responsibility of this layer is to store events and counters as
+// efficiently as possible without re-entering any tracing code.
+// This is really a static-storage-based ring-buffer based on a POD array.
+// This layer does NOT deal with serializing the meta-trace buffer.
+// It posts a task when it's half full and expects something outside of
+// base/ to drain the ring-buffer and serialize it, eventually writing it
+// into the trace itself, before it gets 100% full.
+//
+// 2. A class in tracing/core which takes care of serializing the meta-trace
+// buffer into the trace using a TraceWriter. See metatrace_writer.h .
+//
+// 3. A data source in traced_probes that, when be enabled via the trace config,
+// injects metatrace events into the trace. See metatrace_data_source.h .
+//
+// The available events and tags are defined in metatrace_events.h .
- if (N <= 0) {
- buf = "[printf format error]";
- break;
- }
+namespace perfetto {
- auto sN = static_cast<size_t>(N);
- if (sN > buf.size() - 1) {
- // Indicates that the string was truncated and sN is the "number of
- // non-null bytes which would be needed to fit the result". This is the
- // C99 standard behaviour in the case of truncation. In that case, resize
- // the buffer to match the returned value (with + 1 for the null
- // terminator) and try again.
- buf.resize(sN + 1);
- continue;
- }
- if (sN == buf.size() - 1) {
- // Indicates that the string was likely truncated and sN is just the
- // number of bytes written into the string. This is the behaviour of
- // non-standard compilers (MSVC) etc. In that case, just double the
- // storage and try again.
- buf.resize(sN * 2);
- continue;
- }
+namespace base {
+class TaskRunner;
+} // namespace base
- // Otherwise, indicates the string was written successfully: we need to
- // resize to match the number of non-null bytes and return.
- buf.resize(sN);
- break;
- }
- return Status(std::move(buf));
+namespace metatrace {
+
+// Meta-tracing is organized in "tags" that can be selectively enabled. This is
+// to enable meta-tracing only of one sub-system. This word has one "enabled"
+// bit for each tag. 0 -> meta-tracing off.
+extern std::atomic<uint32_t> g_enabled_tags;
+
+// Time of the Enable() call. Used as a reference for keeping delta timestmaps
+// in Record.
+extern std::atomic<uint64_t> g_enabled_timestamp;
+
+// Enables meta-tracing for one or more tags. Once enabled it will discard any
+// further Enable() calls and return false until disabled,
+// |read_task| is a closure that will be called enqueued |task_runner| when the
+// meta-tracing ring buffer is half full. The task is expected to read the ring
+// buffer using RingBuffer::GetReadIterator() and serialize the contents onto a
+// file or into the trace itself.
+// Must be called on the |task_runner| passed.
+// |task_runner| must have static lifetime.
+bool Enable(std::function<void()> read_task, base::TaskRunner*, uint32_t tags);
+
+// Disables meta-tracing.
+// Must be called on the same |task_runner| as Enable().
+void Disable();
+
+inline uint64_t TraceTimeNowNs() {
+ return static_cast<uint64_t>(base::GetBootTimeNs().count());
}
-std::optional<std::string_view> Status::GetPayload(
- std::string_view type_url) const {
- if (ok()) {
- return std::nullopt;
- }
- for (const auto& kv : payloads_) {
- if (kv.type_url == type_url) {
- return kv.payload;
- }
- }
- return std::nullopt;
+// Returns a relaxed view of whether metatracing is enabled for the given tag.
+// Useful for skipping unnecessary argument computation if metatracing is off.
+inline bool IsEnabled(uint32_t tag) {
+ auto enabled_tags = g_enabled_tags.load(std::memory_order_relaxed);
+ return PERFETTO_UNLIKELY((enabled_tags & tag) != 0);
}
-void Status::SetPayload(std::string_view type_url, std::string value) {
- if (ok()) {
- return;
- }
- for (auto& kv : payloads_) {
- if (kv.type_url == type_url) {
- kv.payload = value;
- return;
- }
+// Holds the data for a metatrace event or counter.
+struct Record {
+ static constexpr uint16_t kTypeMask = 0x8000;
+ static constexpr uint16_t kTypeCounter = 0x8000;
+ static constexpr uint16_t kTypeEvent = 0;
+
+ uint64_t timestamp_ns() const {
+ auto base_ns = g_enabled_timestamp.load(std::memory_order_relaxed);
+ PERFETTO_DCHECK(base_ns);
+ return base_ns + ((static_cast<uint64_t>(timestamp_ns_high) << 32) |
+ timestamp_ns_low);
}
- payloads_.push_back(Payload{std::string(type_url), std::move(value)});
-}
-bool Status::ErasePayload(std::string_view type_url) {
- if (ok()) {
- return false;
+ void set_timestamp(uint64_t ts) {
+ auto t_start = g_enabled_timestamp.load(std::memory_order_relaxed);
+ uint64_t diff = ts - t_start;
+ PERFETTO_DCHECK(diff < (1ull << 48));
+ timestamp_ns_low = static_cast<uint32_t>(diff);
+ timestamp_ns_high = static_cast<uint16_t>(diff >> 32);
}
- auto it = std::remove_if(
- payloads_.begin(), payloads_.end(),
- [type_url](const Payload& p) { return p.type_url == type_url; });
- bool erased = it != payloads_.end();
- payloads_.erase(it, payloads_.end());
- return erased;
-}
-} // namespace perfetto::base
-// gen_amalgamated begin source: src/base/string_splitter.cc
-/*
- * 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.
- */
+ // We can't just memset() this class because on MSVC std::atomic<> is not
+ // trivially constructible anymore. Also std::atomic<> has a deleted copy
+ // constructor so we cant just do "*this = Record()" either.
+ // See http://bit.ly/339Jlzd .
+ void clear() {
+ this->~Record();
+ new (this) Record();
+ }
-// gen_amalgamated expanded: #include "perfetto/ext/base/string_splitter.h"
+ // This field holds the type (counter vs event) in the MSB and event ID (as
+ // defined in metatrace_events.h) in the lowest 15 bits. It is also used also
+ // as a linearization point: this is always written after all the other
+ // fields with a release-store. This is so the reader can determine whether it
+ // can safely process the other event fields after a load-acquire.
+ std::atomic<uint16_t> type_and_id{};
-#include <utility>
+ // Timestamp is stored as a 48-bits value diffed against g_enabled_timestamp.
+ // This gives us 78 hours from Enabled().
+ uint16_t timestamp_ns_high = 0;
+ uint32_t timestamp_ns_low = 0;
-// gen_amalgamated expanded: #include "perfetto/base/logging.h"
+ uint32_t thread_id = 0;
-namespace perfetto {
-namespace base {
+ union {
+ // Only one of the two elements can be zero initialized, clang complains
+ // about "initializing multiple members of union" otherwise.
+ uint32_t duration_ns = 0; // If type == event.
+ int32_t counter_value; // If type == counter.
+ };
+};
-StringSplitter::StringSplitter(std::string str,
- char delimiter,
- EmptyTokenMode empty_token_mode)
- : str_(std::move(str)),
- delimiter_(delimiter),
- empty_token_mode_(empty_token_mode) {
- // It's legal to access str[str.size()] in C++11 (it always returns \0),
- // hence the +1 (which becomes just size() after the -1 in Initialize()).
- Initialize(&str_[0], str_.size() + 1);
-}
+// Hold the meta-tracing data into a statically allocated array.
+// This class uses static storage (as opposite to being a singleton) to:
+// - Have the guarantee of always valid storage, so that meta-tracing can be
+// safely used in any part of the codebase, including base/ itself.
+// - Avoid barriers that thread-safe static locals would require.
+class RingBuffer {
+ public:
+ static constexpr size_t kCapacity = 4096; // 4096 * 16 bytes = 64K.
-StringSplitter::StringSplitter(char* str,
- size_t size,
- char delimiter,
- EmptyTokenMode empty_token_mode)
- : delimiter_(delimiter), empty_token_mode_(empty_token_mode) {
- Initialize(str, size);
-}
+ // This iterator is not idempotent and will bump the read index in the buffer
+ // at the end of the reads. There can be only one reader at any time.
+ // Usage: for (auto it = RingBuffer::GetReadIterator(); it; ++it) { it->... }
+ class ReadIterator {
+ public:
+ ReadIterator(ReadIterator&& other) {
+ PERFETTO_DCHECK(other.valid_);
+ cur_ = other.cur_;
+ end_ = other.end_;
+ valid_ = other.valid_;
+ other.valid_ = false;
+ }
-StringSplitter::StringSplitter(StringSplitter* outer,
- char delimiter,
- EmptyTokenMode empty_token_mode)
- : delimiter_(delimiter), empty_token_mode_(empty_token_mode) {
- Initialize(outer->cur_token(), outer->cur_token_size() + 1);
-}
+ ~ReadIterator() {
+ if (!valid_)
+ return;
+ PERFETTO_DCHECK(cur_ >= RingBuffer::rd_index_);
+ PERFETTO_DCHECK(cur_ <= RingBuffer::wr_index_);
+ RingBuffer::rd_index_.store(cur_, std::memory_order_release);
+ }
-void StringSplitter::Initialize(char* str, size_t size) {
- PERFETTO_DCHECK(!size || str);
- next_ = str;
- end_ = str + size;
- cur_ = nullptr;
- cur_size_ = 0;
- if (size)
- next_[size - 1] = '\0';
-}
+ explicit operator bool() const { return cur_ < end_; }
+ const Record* operator->() const { return RingBuffer::At(cur_); }
+ const Record& operator*() const { return *operator->(); }
-bool StringSplitter::Next() {
- for (; next_ < end_; next_++) {
- if (*next_ == delimiter_ &&
- empty_token_mode_ == EmptyTokenMode::DISALLOW_EMPTY_TOKENS) {
- // If empty tokens are disallowed, find fist non-delimiter character.
- continue;
- }
- cur_ = next_;
- for (;; next_++) {
- if (*next_ == delimiter_) {
- cur_size_ = static_cast<size_t>(next_ - cur_);
- *(next_++) = '\0';
- break;
- }
- if (*next_ == '\0') {
- cur_size_ = static_cast<size_t>(next_ - cur_);
- next_ = end_;
- break;
- }
+ // This is for ++it. it++ is deliberately not supported.
+ ReadIterator& operator++() {
+ PERFETTO_DCHECK(cur_ < end_);
+ // Once a record has been read, mark it as free clearing its type_and_id,
+ // so if we encounter it in another read iteration while being written
+ // we know it's not fully written yet.
+ // The memory_order_relaxed below is enough because:
+ // - The reader is single-threaded and doesn't re-read the same records.
+ // - Before starting a read batch, the reader has an acquire barrier on
+ // |rd_index_|.
+ // - After terminating a read batch, the ~ReadIterator dtor updates the
+ // |rd_index_| with a release-store.
+ // - Reader and writer are typically kCapacity/2 apart. So unless an
+ // overrun happens a writer won't reuse a newly released record any time
+ // soon. If an overrun happens, everything is busted regardless.
+ At(cur_)->type_and_id.store(0, std::memory_order_relaxed);
+ ++cur_;
+ return *this;
}
- if (*cur_ || empty_token_mode_ == EmptyTokenMode::ALLOW_EMPTY_TOKENS)
- return true;
- break;
+
+ private:
+ friend class RingBuffer;
+ ReadIterator(uint64_t begin, uint64_t end)
+ : cur_(begin), end_(end), valid_(true) {}
+ ReadIterator& operator=(const ReadIterator&) = delete;
+ ReadIterator(const ReadIterator&) = delete;
+
+ uint64_t cur_;
+ uint64_t end_;
+ bool valid_;
+ };
+
+ static Record* At(uint64_t index) {
+ // Doesn't really have to be pow2, but if not the compiler will emit
+ // arithmetic operations to compute the modulo instead of a bitwise AND.
+ static_assert(!(kCapacity & (kCapacity - 1)), "kCapacity must be pow2");
+ PERFETTO_DCHECK(index >= rd_index_);
+ PERFETTO_DCHECK(index <= wr_index_);
+ return &records_[index % kCapacity];
}
- cur_ = nullptr;
- cur_size_ = 0;
- return false;
+
+ // Must be called on the same task runner passed to Enable()
+ static ReadIterator GetReadIterator() {
+ PERFETTO_DCHECK(RingBuffer::IsOnValidTaskRunner());
+ return ReadIterator(rd_index_.load(std::memory_order_acquire),
+ wr_index_.load(std::memory_order_acquire));
+ }
+
+ static Record* AppendNewRecord();
+ static void Reset();
+
+ static bool has_overruns() {
+ return has_overruns_.load(std::memory_order_acquire);
+ }
+
+ // Can temporarily return a value >= kCapacity but is eventually consistent.
+ // This would happen in case of overruns until threads hit the --wr_index_
+ // in AppendNewRecord().
+ static uint64_t GetSizeForTesting() {
+ auto wr_index = wr_index_.load(std::memory_order_relaxed);
+ auto rd_index = rd_index_.load(std::memory_order_relaxed);
+ PERFETTO_DCHECK(wr_index >= rd_index);
+ return wr_index - rd_index;
+ }
+
+ private:
+ friend class ReadIterator;
+
+ // Returns true if the caller is on the task runner passed to Enable().
+ // Used only for DCHECKs.
+ static bool IsOnValidTaskRunner();
+
+ static std::array<Record, kCapacity> records_;
+ static std::atomic<bool> read_task_queued_;
+ static std::atomic<uint64_t> wr_index_;
+ static std::atomic<uint64_t> rd_index_;
+ static std::atomic<bool> has_overruns_;
+ static Record bankruptcy_record_; // Used in case of overruns.
+};
+
+inline void TraceCounter(uint32_t tag, uint16_t id, int32_t value) {
+ // memory_order_relaxed is okay because the storage has static lifetime.
+ // It is safe to accidentally log an event soon after disabling.
+ auto enabled_tags = g_enabled_tags.load(std::memory_order_relaxed);
+ if (PERFETTO_LIKELY((enabled_tags & tag) == 0))
+ return;
+ Record* record = RingBuffer::AppendNewRecord();
+ record->thread_id = static_cast<uint32_t>(base::GetThreadId());
+ record->set_timestamp(TraceTimeNowNs());
+ record->counter_value = value;
+ record->type_and_id.store(Record::kTypeCounter | id,
+ std::memory_order_release);
}
-} // namespace base
+class ScopedEvent {
+ public:
+ ScopedEvent(uint32_t tag, uint16_t event_id) {
+ auto enabled_tags = g_enabled_tags.load(std::memory_order_relaxed);
+ if (PERFETTO_LIKELY((enabled_tags & tag) == 0))
+ return;
+ event_id_ = event_id;
+ record_ = RingBuffer::AppendNewRecord();
+ record_->thread_id = static_cast<uint32_t>(base::GetThreadId());
+ record_->set_timestamp(TraceTimeNowNs());
+ }
+
+ ~ScopedEvent() {
+ if (PERFETTO_LIKELY(!record_))
+ return;
+ auto now = TraceTimeNowNs();
+ record_->duration_ns = static_cast<uint32_t>(now - record_->timestamp_ns());
+ record_->type_and_id.store(Record::kTypeEvent | event_id_,
+ std::memory_order_release);
+ }
+
+ private:
+ Record* record_ = nullptr;
+ uint16_t event_id_ = 0;
+ ScopedEvent(const ScopedEvent&) = delete;
+ ScopedEvent& operator=(const ScopedEvent&) = delete;
+};
+
+// Boilerplate to derive a unique variable name for the event.
+#define PERFETTO_METATRACE_UID2(a, b) a##b
+#define PERFETTO_METATRACE_UID(x) PERFETTO_METATRACE_UID2(metatrace_, x)
+
+#define PERFETTO_METATRACE_SCOPED(TAG, ID) \
+ ::perfetto::metatrace::ScopedEvent PERFETTO_METATRACE_UID(__COUNTER__)( \
+ ::perfetto::metatrace::TAG, ::perfetto::metatrace::ID)
+
+#define PERFETTO_METATRACE_COUNTER(TAG, ID, VALUE) \
+ ::perfetto::metatrace::TraceCounter(::perfetto::metatrace::TAG, \
+ ::perfetto::metatrace::ID, \
+ static_cast<int32_t>(VALUE))
+
+} // namespace metatrace
} // namespace perfetto
-// gen_amalgamated begin source: src/base/string_utils.cc
+
+#endif // INCLUDE_PERFETTO_EXT_BASE_METATRACE_H_
/*
* Copyright (C) 2018 The Android Open Source Project
*
@@ -8710,393 +9157,303 @@ bool StringSplitter::Next() {
* limitations under the License.
*/
-// gen_amalgamated expanded: #include "perfetto/ext/base/string_utils.h"
-
-#include <locale.h>
-#include <stdarg.h>
-#include <string.h>
+// gen_amalgamated expanded: #include "perfetto/ext/base/metatrace.h"
-#include <algorithm>
+// gen_amalgamated expanded: #include "perfetto/base/compiler.h"
+// gen_amalgamated expanded: #include "perfetto/base/task_runner.h"
+// gen_amalgamated expanded: #include "perfetto/base/time.h"
+// gen_amalgamated expanded: #include "perfetto/ext/base/file_utils.h"
+// gen_amalgamated expanded: #include "perfetto/ext/base/thread_annotations.h"
-#if PERFETTO_BUILDFLAG(PERFETTO_OS_APPLE)
-#include <xlocale.h>
-#elif PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
-#include <windows.h>
-#endif
+namespace perfetto {
+namespace metatrace {
-#include <cinttypes>
+std::atomic<uint32_t> g_enabled_tags{0};
+std::atomic<uint64_t> g_enabled_timestamp{0};
-// gen_amalgamated expanded: #include "perfetto/base/compiler.h"
-// gen_amalgamated expanded: #include "perfetto/base/logging.h"
+// static members
+std::array<Record, RingBuffer::kCapacity> RingBuffer::records_;
+std::atomic<bool> RingBuffer::read_task_queued_;
+std::atomic<uint64_t> RingBuffer::wr_index_;
+std::atomic<uint64_t> RingBuffer::rd_index_;
+std::atomic<bool> RingBuffer::has_overruns_;
+Record RingBuffer::bankruptcy_record_;
-namespace perfetto {
-namespace base {
+namespace {
-// Locale-independent as possible version of strtod.
-double StrToD(const char* nptr, char** endptr) {
-#if PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID) || \
- PERFETTO_BUILDFLAG(PERFETTO_OS_LINUX_BUT_NOT_QNX) || \
- PERFETTO_BUILDFLAG(PERFETTO_OS_APPLE)
- static auto c_locale = newlocale(LC_ALL, "C", nullptr);
- return strtod_l(nptr, endptr, c_locale);
-#else
- return strtod(nptr, endptr);
-#endif
-}
+// std::function<> is not trivially de/constructible. This struct wraps it in a
+// heap-allocated struct to avoid static initializers.
+struct Delegate {
+ static Delegate* GetInstance() {
+ static Delegate* instance = new Delegate();
+ return instance;
+ }
-bool StartsWith(const std::string& str, const std::string& prefix) {
- return str.compare(0, prefix.length(), prefix) == 0;
-}
+ base::TaskRunner* task_runner = nullptr;
+ std::function<void()> read_task;
+};
-bool StartsWithAny(const std::string& str,
- const std::vector<std::string>& prefixes) {
- return std::any_of(
- prefixes.begin(), prefixes.end(),
- [&str](const std::string& prefix) { return StartsWith(str, prefix); });
-}
+} // namespace
-bool EndsWith(const std::string& str, const std::string& suffix) {
- if (suffix.size() > str.size())
+bool Enable(std::function<void()> read_task,
+ base::TaskRunner* task_runner,
+ uint32_t tags) {
+ PERFETTO_DCHECK(read_task);
+ PERFETTO_DCHECK(task_runner->RunsTasksOnCurrentThread());
+ if (g_enabled_tags.load(std::memory_order_acquire))
return false;
- return str.compare(str.size() - suffix.size(), suffix.size(), suffix) == 0;
-}
-bool Contains(const std::string& haystack, const std::string& needle) {
- return haystack.find(needle) != std::string::npos;
+ Delegate* dg = Delegate::GetInstance();
+ dg->task_runner = task_runner;
+ dg->read_task = std::move(read_task);
+ RingBuffer::Reset();
+ g_enabled_timestamp.store(TraceTimeNowNs(), std::memory_order_relaxed);
+ g_enabled_tags.store(tags, std::memory_order_release);
+ return true;
}
-bool Contains(const std::string& haystack, const char needle) {
- return haystack.find(needle) != std::string::npos;
+void Disable() {
+ g_enabled_tags.store(0, std::memory_order_release);
+ Delegate* dg = Delegate::GetInstance();
+ PERFETTO_DCHECK(!dg->task_runner ||
+ dg->task_runner->RunsTasksOnCurrentThread());
+ dg->task_runner = nullptr;
+ dg->read_task = nullptr;
}
-bool Contains(const std::vector<std::string>& haystack,
- const std::string& needle) {
- return std::find(haystack.begin(), haystack.end(), needle) != haystack.end();
+// static
+void RingBuffer::Reset() {
+ bankruptcy_record_.clear();
+ for (Record& record : records_)
+ record.clear();
+ wr_index_ = 0;
+ rd_index_ = 0;
+ has_overruns_ = false;
+ read_task_queued_ = false;
}
-size_t Find(const StringView& needle, const StringView& haystack) {
- if (needle.empty())
- return 0;
- if (needle.size() > haystack.size())
- return std::string::npos;
- for (size_t i = 0; i < haystack.size() - (needle.size() - 1); ++i) {
- if (strncmp(haystack.data() + i, needle.data(), needle.size()) == 0)
- return i;
- }
- return std::string::npos;
-}
+// static
+Record* RingBuffer::AppendNewRecord() {
+ auto wr_index = wr_index_.fetch_add(1, std::memory_order_acq_rel);
-bool CaseInsensitiveEqual(const std::string& first, const std::string& second) {
- return first.size() == second.size() &&
- std::equal(
- first.begin(), first.end(), second.begin(),
- [](char a, char b) { return Lowercase(a) == Lowercase(b); });
-}
+ // rd_index can only monotonically increase, we don't care if we read an
+ // older value, we'll just hit the slow-path a bit earlier if it happens.
+ auto rd_index = rd_index_.load(std::memory_order_relaxed);
-std::string Join(const std::vector<std::string>& parts,
- const std::string& delim) {
- std::string acc;
- for (size_t i = 0; i < parts.size(); ++i) {
- acc += parts[i];
- if (i + 1 != parts.size()) {
- acc += delim;
+ PERFETTO_DCHECK(wr_index >= rd_index);
+ auto size = wr_index - rd_index;
+ if (PERFETTO_LIKELY(size < kCapacity / 2))
+ return At(wr_index);
+
+ // Slow-path: Enqueue the read task and handle overruns.
+ bool expected = false;
+ if (RingBuffer::read_task_queued_.compare_exchange_strong(expected, true)) {
+ Delegate* dg = Delegate::GetInstance();
+ if (dg->task_runner) {
+ dg->task_runner->PostTask([] {
+ // Meta-tracing might have been disabled in the meantime.
+ auto read_task = Delegate::GetInstance()->read_task;
+ if (read_task)
+ read_task();
+ RingBuffer::read_task_queued_ = false;
+ });
}
}
- return acc;
-}
-std::vector<std::string> SplitString(const std::string& text,
- const std::string& delimiter) {
- PERFETTO_CHECK(!delimiter.empty());
+ if (PERFETTO_LIKELY(size < kCapacity))
+ return At(wr_index);
- std::vector<std::string> output;
- size_t start = 0;
- size_t next;
- for (;;) {
- next = std::min(text.find(delimiter, start), text.size());
- if (next > start)
- output.emplace_back(&text[start], next - start);
- start = next + delimiter.size();
- if (start >= text.size())
- break;
- }
- return output;
-}
+ has_overruns_.store(true, std::memory_order_release);
+ wr_index_.fetch_sub(1, std::memory_order_acq_rel);
-std::string_view TrimWhitespace(std::string_view str) {
- static constexpr char kWhitespaces[] = "\t\n ";
- size_t front_idx = str.find_first_not_of(kWhitespaces);
- if (front_idx == std::string_view::npos)
- return {};
- std::string_view front_trimmed = str.substr(front_idx);
- size_t end_idx = front_trimmed.find_last_not_of(kWhitespaces);
- PERFETTO_DCHECK(end_idx != std::string_view::npos);
- return front_trimmed.substr(0, end_idx + 1);
+ // In the case of overflows, threads will race writing on the same memory
+ // location and TSan will rightly complain. This is fine though because nobody
+ // will read the bankruptcy record and it's designed to contain garbage.
+ PERFETTO_ANNOTATE_BENIGN_RACE_SIZED(&bankruptcy_record_, sizeof(Record),
+ "nothing reads bankruptcy_record_")
+ return &bankruptcy_record_;
}
-std::string TrimWhitespace(const std::string& str) {
- return std::string(TrimWhitespace(std::string_view(str)));
+// static
+bool RingBuffer::IsOnValidTaskRunner() {
+ auto* task_runner = Delegate::GetInstance()->task_runner;
+ return task_runner && task_runner->RunsTasksOnCurrentThread();
}
-std::string_view TrimWhitespace(const char* str) {
- return TrimWhitespace(std::string_view(str));
-}
+} // namespace metatrace
+} // namespace perfetto
+// gen_amalgamated begin source: src/base/paged_memory.cc
+// gen_amalgamated begin header: include/perfetto/ext/base/paged_memory.h
+// gen_amalgamated begin header: include/perfetto/ext/base/container_annotations.h
+/*
+ * 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.
+ */
-std::string StripPrefix(const std::string& str, const std::string& prefix) {
- return StartsWith(str, prefix) ? str.substr(prefix.size()) : str;
-}
+#ifndef INCLUDE_PERFETTO_EXT_BASE_CONTAINER_ANNOTATIONS_H_
+#define INCLUDE_PERFETTO_EXT_BASE_CONTAINER_ANNOTATIONS_H_
-std::string StripSuffix(const std::string& str, const std::string& suffix) {
- return EndsWith(str, suffix) ? str.substr(0, str.size() - suffix.size())
- : str;
-}
+// gen_amalgamated expanded: #include "perfetto/base/build_config.h"
-std::string ToUpper(const std::string& str) {
- // Don't use toupper(), it depends on the locale.
- std::string res(str);
- auto end = res.end();
- for (auto c = res.begin(); c != end; ++c)
- *c = Uppercase(*c);
- return res;
-}
+// Windows ASAN doesn't currently support these annotations.
+#if defined(ADDRESS_SANITIZER) && !PERFETTO_BUILDFLAG(PERFETTO_OS_WIN) && \
+ !defined(ADDRESS_SANITIZER_WITHOUT_INSTRUMENTATION)
-std::string ToLower(const std::string& str) {
- // Don't use tolower(), it depends on the locale.
- std::string res(str);
- auto end = res.end();
- for (auto c = res.begin(); c != end; ++c)
- *c = Lowercase(*c);
- return res;
-}
+#include <sanitizer/common_interface_defs.h>
-std::string ToHex(const char* data, size_t size) {
- std::string hex(2 * size + 1, 'x');
- for (size_t i = 0; i < size; ++i) {
- // snprintf prints 3 characters, the two hex digits and a null byte. As we
- // write left to right, we keep overwriting the nullbytes, except for the
- // last call to snprintf.
- snprintf(&(hex[2 * i]), 3, "%02hhx", data[i]);
+#define ANNOTATE_NEW_BUFFER(buffer, capacity, new_size) \
+ if (buffer) { \
+ __sanitizer_annotate_contiguous_container(buffer, (buffer) + (capacity), \
+ (buffer) + (capacity), \
+ (buffer) + (new_size)); \
}
- // Remove the trailing nullbyte produced by the last snprintf.
- hex.resize(2 * size);
- return hex;
-}
-
-std::string IntToHexString(uint32_t number) {
- size_t max_size = 11; // Max uint32 is 0xFFFFFFFF + 1 for null byte.
- std::string buf;
- buf.resize(max_size);
- size_t final_len = SprintfTrunc(&buf[0], max_size, "0x%02x", number);
- buf.resize(static_cast<size_t>(final_len)); // Cuts off the final null byte.
- return buf;
-}
+#define ANNOTATE_DELETE_BUFFER(buffer, capacity, old_size) \
+ if (buffer) { \
+ __sanitizer_annotate_contiguous_container(buffer, (buffer) + (capacity), \
+ (buffer) + (old_size), \
+ (buffer) + (capacity)); \
+ }
+#define ANNOTATE_CHANGE_SIZE(buffer, capacity, old_size, new_size) \
+ if (buffer) { \
+ __sanitizer_annotate_contiguous_container(buffer, (buffer) + (capacity), \
+ (buffer) + (old_size), \
+ (buffer) + (new_size)); \
+ }
+#define ANNOTATE_CHANGE_CAPACITY(buffer, old_capacity, buffer_size, \
+ new_capacity) \
+ ANNOTATE_DELETE_BUFFER(buffer, old_capacity, buffer_size); \
+ ANNOTATE_NEW_BUFFER(buffer, new_capacity, buffer_size);
+// Annotations require buffers to begin on an 8-byte boundary.
+#else // defined(ADDRESS_SANITIZER)
+#define ANNOTATE_NEW_BUFFER(buffer, capacity, new_size)
+#define ANNOTATE_DELETE_BUFFER(buffer, capacity, old_size)
+#define ANNOTATE_CHANGE_SIZE(buffer, capacity, old_size, new_size)
+#define ANNOTATE_CHANGE_CAPACITY(buffer, old_capacity, buffer_size, \
+ new_capacity)
+#endif // defined(ADDRESS_SANITIZER)
-std::string Uint64ToHexString(uint64_t number) {
- return "0x" + Uint64ToHexStringNoPrefix(number);
-}
+#endif // INCLUDE_PERFETTO_EXT_BASE_CONTAINER_ANNOTATIONS_H_
+/*
+ * 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.
+ */
-std::string Uint64ToHexStringNoPrefix(uint64_t number) {
- size_t max_size = 17; // Max uint64 is FFFFFFFFFFFFFFFF + 1 for null byte.
- std::string buf;
- buf.resize(max_size);
- size_t final_len = SprintfTrunc(&buf[0], max_size, "%" PRIx64 "", number);
- buf.resize(static_cast<size_t>(final_len)); // Cuts off the final null byte.
- return buf;
-}
+#ifndef INCLUDE_PERFETTO_EXT_BASE_PAGED_MEMORY_H_
+#define INCLUDE_PERFETTO_EXT_BASE_PAGED_MEMORY_H_
-std::string StripChars(const std::string& str,
- const std::string& chars,
- char replacement) {
- std::string res(str);
- const char* start = res.c_str();
- const char* remove = chars.c_str();
- for (const char* c = strpbrk(start, remove); c; c = strpbrk(c + 1, remove))
- res[static_cast<uintptr_t>(c - start)] = replacement;
- return res;
-}
+#include <cstddef>
+#include <memory>
-std::string ReplaceAll(std::string str,
- const std::string& to_replace,
- const std::string& replacement) {
- PERFETTO_CHECK(!to_replace.empty());
- size_t pos = 0;
- while ((pos = str.find(to_replace, pos)) != std::string::npos) {
- str.replace(pos, to_replace.length(), replacement);
- pos += replacement.length();
- }
- return str;
-}
+// gen_amalgamated expanded: #include "perfetto/base/build_config.h"
+// gen_amalgamated expanded: #include "perfetto/ext/base/container_annotations.h"
-bool CheckAsciiAndRemoveInvalidUTF8(base::StringView str, std::string& output) {
- bool is_ascii = std::all_of(str.begin(), str.end(), [](char c) {
- return (static_cast<unsigned char>(c) & 0b10000000) == 0b00000000;
- });
- if (is_ascii) {
- return true;
- }
+// We need to track the committed size on windows and when ASAN is enabled.
+#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN) || defined(ADDRESS_SANITIZER)
+#define TRACK_COMMITTED_SIZE() 1
+#else
+#define TRACK_COMMITTED_SIZE() 0
+#endif
- // https://www.rfc-editor.org/rfc/rfc3629.txt
- output.clear();
- output.reserve(str.size());
- for (size_t i = 0; i < str.size();) {
- unsigned char c = static_cast<unsigned char>(str.data()[i]);
- size_t num_bytes = 0;
- bool valid_sequence = true;
+namespace perfetto {
+namespace base {
- if ((c & 0b10000000) == 0b00000000) {
- num_bytes = 1;
- } else if ((c & 0b11100000) == 0b11000000) {
- num_bytes = 2;
- } else if ((c & 0b11110000) == 0b11100000) {
- num_bytes = 3;
- } else if ((c & 0b11111000) == 0b11110000) {
- num_bytes = 4;
- } else {
- valid_sequence = false;
- // Skip this byte
- num_bytes = 1;
- }
+class PagedMemory {
+ public:
+ // Initializes an invalid PagedMemory pointing to nullptr.
+ PagedMemory();
- if (valid_sequence) {
- // Check if enough bytes are available in the string
- if (i + num_bytes > str.size()) {
- valid_sequence = false;
- num_bytes = 1; // Treat as a single invalid byte for advancement
- } else {
- // Check for overlong encodings, surrogates, and out-of-range
- if (num_bytes == 2 && c < 0b11000010) { // 0xC2
- valid_sequence = false; // Overlong
- } else if (num_bytes == 3) {
- unsigned char byte2 = static_cast<unsigned char>(str.data()[i + 1]);
- if ((c == 0b11100000 && byte2 < 0b10100000) || // Overlong E0
- (c == 0b11101101 && byte2 >= 0b10100000)) { // Surrogate ED
- valid_sequence = false;
- }
- } else if (num_bytes == 4) {
- unsigned char byte2 = static_cast<unsigned char>(str.data()[i + 1]);
- if ((c == 0b11110000 && byte2 < 0b10010000) || // Overlong F0
- (c == 0b11110100 && byte2 > 0b10001111)) { // Out of range F4
- valid_sequence = false;
- }
- }
+ ~PagedMemory();
- if (valid_sequence && num_bytes > 1) {
- for (size_t j = 1; j < num_bytes; ++j) {
- unsigned char continuation_byte =
- static_cast<unsigned char>(str.data()[i + j]);
- if ((continuation_byte & 0b11000000) != 0b10000000) {
- valid_sequence = false;
- break;
- }
- }
- }
- }
- }
+ PagedMemory(PagedMemory&& other) noexcept;
+ PagedMemory& operator=(PagedMemory&& other);
- if (valid_sequence) {
- for (size_t j = 0; j < num_bytes; ++j) {
- output.push_back(str.data()[i + j]);
- }
- }
+ enum AllocationFlags {
+ // By default, Allocate() crashes if the underlying mmap fails (e.g., if out
+ // of virtual address space). When this flag is provided, an invalid
+ // PagedMemory pointing to nullptr is returned in this case instead.
+ kMayFail = 1 << 0,
- i += num_bytes;
- }
- return false;
-}
+ // By default, Allocate() commits the allocated memory immediately. When
+ // this flag is provided, the memory virtual address space may only be
+ // reserved and the user should call EnsureCommitted() before writing to
+ // memory addresses.
+ kDontCommit = 1 << 1,
+ };
-#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
-bool WideToUTF8(const std::wstring& source, std::string& output) {
- if (source.empty() ||
- source.size() > static_cast<size_t>(std::numeric_limits<int>::max())) {
- return false;
- }
- int size = ::WideCharToMultiByte(CP_UTF8, 0, &source[0],
- static_cast<int>(source.size()), nullptr, 0,
- nullptr, nullptr);
- output.assign(static_cast<size_t>(size), '\0');
- if (::WideCharToMultiByte(CP_UTF8, 0, &source[0],
- static_cast<int>(source.size()), &output[0], size,
- nullptr, nullptr) != size) {
- return false;
- }
- return true;
-}
-#endif // PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
+ // Allocates |size| bytes using mmap(MAP_ANONYMOUS). The returned memory is
+ // guaranteed to be page-aligned and guaranteed to be zeroed.
+ // For |flags|, see the AllocationFlags enum above.
+ static PagedMemory Allocate(size_t size, int flags = 0);
-#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
-bool UTF8ToWide(const std::string& source, std::wstring& output) {
- if (source.empty() ||
- source.size() > static_cast<size_t>(std::numeric_limits<int>::max())) {
- return false;
- }
- int size = ::MultiByteToWideChar(CP_UTF8, 0, &source[0],
- static_cast<int>(source.size()), nullptr, 0);
- output.assign(static_cast<size_t>(size), L'\0');
- if (::MultiByteToWideChar(CP_UTF8, 0, &source[0],
- static_cast<int>(source.size()), &output[0],
- size) != size) {
- return false;
- }
- return true;
-}
-#endif // PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
+ // Hint to the OS that the whole pages within [offset, size()) are not needed
+ // and can be discarded.
+ // Partial pages at both ends of the range are preserved.
+ // The memory remains accessible, and the discarded pages may keep their
+ // contents or be zeroed.
+ // This function may be a NOP on some platforms.
+ // Requires a valid allocation and |offset| <= size().
+ void AdviseDontNeedAfter(size_t offset);
-size_t SprintfTrunc(char* dst, size_t dst_size, const char* fmt, ...) {
- if (PERFETTO_UNLIKELY(dst_size == 0))
- return 0;
+ // Ensures that at least the first |committed_size| bytes of the allocated
+ // memory region are committed. The implementation may commit memory in larger
+ // chunks above |committed_size|. Crashes if the memory couldn't be committed.
+#if TRACK_COMMITTED_SIZE()
+ void EnsureCommitted(size_t committed_size);
+#else // TRACK_COMMITTED_SIZE()
+ void EnsureCommitted(size_t /*committed_size*/) {}
+#endif // TRACK_COMMITTED_SIZE()
- va_list args;
- va_start(args, fmt);
- int src_size = vsnprintf(dst, dst_size, fmt, args);
- va_end(args);
+ inline void* Get() const noexcept { return p_; }
+ inline bool IsValid() const noexcept { return !!p_; }
+ inline size_t size() const noexcept { return size_; }
- if (PERFETTO_UNLIKELY(src_size <= 0)) {
- dst[0] = '\0';
- return 0;
- }
+ private:
+ PagedMemory(char* p, size_t size);
- size_t res;
- if (PERFETTO_LIKELY(src_size < static_cast<int>(dst_size))) {
- // Most common case.
- res = static_cast<size_t>(src_size);
- } else {
- // Truncation case.
- res = dst_size - 1;
- }
+ PagedMemory(const PagedMemory&) = delete;
+ // Defaulted for implementation of move constructor + assignment.
+ PagedMemory& operator=(const PagedMemory&) = default;
- PERFETTO_DCHECK(res < dst_size);
- PERFETTO_DCHECK(dst[res] == '\0');
- return res;
-}
+ char* p_ = nullptr;
-std::optional<LineWithOffset> FindLineWithOffset(base::StringView str,
- uint32_t offset) {
- static constexpr char kNewLine = '\n';
- uint32_t line_offset = 0;
- uint32_t line_count = 1;
- for (uint32_t i = 0; i < str.size(); ++i) {
- if (str.at(i) == kNewLine) {
- line_offset = i + 1;
- line_count++;
- continue;
- }
- if (i == offset) {
- size_t end_offset = str.find(kNewLine, i);
- if (end_offset == std::string::npos) {
- end_offset = str.size();
- }
- base::StringView line = str.substr(line_offset, end_offset - line_offset);
- return LineWithOffset{line, offset - line_offset, line_count};
- }
- }
- return std::nullopt;
-}
+ // The size originally passed to Allocate(). The actual virtual memory
+ // reservation will be larger due to: (i) guard pages; (ii) rounding up to
+ // the system page size.
+ size_t size_ = 0;
+
+#if TRACK_COMMITTED_SIZE()
+ size_t committed_size_ = 0u;
+#endif // TRACK_COMMITTED_SIZE()
+};
} // namespace base
} // namespace perfetto
-// gen_amalgamated begin source: src/base/string_view.cc
+
+#endif // INCLUDE_PERFETTO_EXT_BASE_PAGED_MEMORY_H_
/*
- * Copyright (C) 2019 The Android Open Source Project
+ * 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.
@@ -9111,33 +9468,168 @@ std::optional<LineWithOffset> FindLineWithOffset(base::StringView str,
* limitations under the License.
*/
-// gen_amalgamated expanded: #include "perfetto/ext/base/string_view.h"
+// gen_amalgamated expanded: #include "perfetto/ext/base/paged_memory.h"
+
+#include <algorithm>
+#include <cmath>
+#include <cstddef>
+
+#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
+#include <windows.h>
+#else // PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
+#include <sys/mman.h>
+#endif // PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
+
+// gen_amalgamated expanded: #include "perfetto/base/logging.h"
+// gen_amalgamated expanded: #include "perfetto/ext/base/container_annotations.h"
+// gen_amalgamated expanded: #include "perfetto/ext/base/utils.h"
namespace perfetto {
namespace base {
-// Without ignoring this warning we get the message:
-// error: out-of-line definition of constexpr static data member is redundant
-// in C++17 and is deprecated
-// when using clang-cl in Windows.
-#if defined(__GNUC__) // GCC & clang
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wdeprecated"
-#endif // __GNUC__
+namespace {
+
+#if TRACK_COMMITTED_SIZE()
+constexpr size_t kCommitChunkSize = 4 * 1024 * 1024; // 4MB
+#endif
+
+size_t RoundUpToSysPageSize(size_t req_size) {
+ const size_t page_size = GetSysPageSize();
+ return (req_size + page_size - 1) & ~(page_size - 1);
+}
+
+size_t GuardSize() {
+ return GetSysPageSize();
+}
+
+} // namespace
// static
-constexpr size_t StringView::npos;
+PagedMemory PagedMemory::Allocate(size_t req_size, int flags) {
+ size_t rounded_up_size = RoundUpToSysPageSize(req_size);
+ PERFETTO_CHECK(rounded_up_size >= req_size);
+ size_t outer_size = rounded_up_size + GuardSize() * 2;
+#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
+ void* ptr = VirtualAlloc(nullptr, outer_size, MEM_RESERVE, PAGE_NOACCESS);
+ if (!ptr && (flags & kMayFail))
+ return PagedMemory();
+ PERFETTO_CHECK(ptr);
+ char* usable_region = reinterpret_cast<char*>(ptr) + GuardSize();
+#else // PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
+ void* ptr = mmap(nullptr, outer_size, PROT_READ | PROT_WRITE,
+ MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+ if (ptr == MAP_FAILED && (flags & kMayFail))
+ return PagedMemory();
+ PERFETTO_CHECK(ptr && ptr != MAP_FAILED);
+ char* usable_region = reinterpret_cast<char*>(ptr) + GuardSize();
+ int res = mprotect(ptr, GuardSize(), PROT_NONE);
+ res |= mprotect(usable_region + rounded_up_size, GuardSize(), PROT_NONE);
+ PERFETTO_CHECK(res == 0);
+#endif // PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
-#if defined(__GNUC__)
-#pragma GCC diagnostic pop
-#endif
+ auto memory = PagedMemory(usable_region, req_size);
+#if TRACK_COMMITTED_SIZE()
+ size_t initial_commit = req_size;
+ if (flags & kDontCommit)
+ initial_commit = std::min(initial_commit, kCommitChunkSize);
+ memory.EnsureCommitted(initial_commit);
+#endif // TRACK_COMMITTED_SIZE()
+ return memory;
+}
+
+PagedMemory::PagedMemory() {}
+
+// clang-format off
+PagedMemory::PagedMemory(char* p, size_t size) : p_(p), size_(size) {
+ ANNOTATE_NEW_BUFFER(p_, size_, committed_size_)
+}
+
+PagedMemory::PagedMemory(PagedMemory&& other) noexcept {
+ *this = other;
+ other.p_ = nullptr;
+}
+// clang-format on
+
+PagedMemory& PagedMemory::operator=(PagedMemory&& other) {
+ this->~PagedMemory();
+ new (this) PagedMemory(std::move(other));
+ return *this;
+}
+
+PagedMemory::~PagedMemory() {
+ if (!p_)
+ return;
+ PERFETTO_CHECK(size_);
+ char* start = p_ - GuardSize();
+#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
+ BOOL res = VirtualFree(start, 0, MEM_RELEASE);
+ PERFETTO_CHECK(res != 0);
+#else // PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
+ const size_t outer_size = RoundUpToSysPageSize(size_) + GuardSize() * 2;
+ int res = munmap(start, outer_size);
+ PERFETTO_CHECK(res == 0);
+#endif // PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
+ ANNOTATE_DELETE_BUFFER(p_, size_, committed_size_)
+}
+
+void PagedMemory::AdviseDontNeedAfter(size_t offset) {
+ PERFETTO_CHECK(p_ && offset <= size_);
+#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN) || PERFETTO_BUILDFLAG(PERFETTO_OS_NACL)
+ // Discarding pages on Windows has more CPU cost than is justified for the
+ // possible memory savings.
+#else
+ const size_t release_begin = RoundUpToSysPageSize(offset);
+ const size_t release_end = AlignDown(size_, GetSysPageSize());
+ if (release_begin >= release_end)
+ return;
+ char* const release_ptr = p_ + release_begin;
+ const size_t release_size = release_end - release_begin;
+#if PERFETTO_BUILDFLAG(PERFETTO_OS_QNX)
+ int res = posix_madvise(release_ptr, release_size, POSIX_MADV_DISCARD_NP);
+#else
+ // http://man7.org/linux/man-pages/man2/madvise.2.html
+ int res = madvise(release_ptr, release_size, MADV_DONTNEED);
+#endif // PERFETTO_BUILDFLAG(PERFETTO_OS_QNX)
+ PERFETTO_DCHECK(res == 0);
+#endif // PERFETTO_BUILDFLAG(PERFETTO_OS_WIN) ||
+ // PERFETTO_BUILDFLAG(PERFETTO_OS_NACL)
+}
+
+#if TRACK_COMMITTED_SIZE()
+void PagedMemory::EnsureCommitted(size_t committed_size) {
+ PERFETTO_DCHECK(committed_size <= size_);
+#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
+ if (committed_size_ >= committed_size)
+ return;
+ // Rounding up.
+ size_t delta = committed_size - committed_size_;
+ size_t num_additional_chunks =
+ (delta + kCommitChunkSize - 1) / kCommitChunkSize;
+ PERFETTO_DCHECK(num_additional_chunks * kCommitChunkSize >= delta);
+ // Don't commit more than the total size.
+ size_t commit_size = std::min(num_additional_chunks * kCommitChunkSize,
+ size_ - committed_size_);
+ void* res = VirtualAlloc(p_ + committed_size_, commit_size, MEM_COMMIT,
+ PAGE_READWRITE);
+ PERFETTO_CHECK(res);
+ ANNOTATE_CHANGE_SIZE(p_, size_, committed_size_,
+ committed_size_ + commit_size)
+ committed_size_ += commit_size;
+#else // PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
+ // mmap commits automatically as needed, so we only track here for ASAN.
+ committed_size = std::max(committed_size_, committed_size);
+ ANNOTATE_CHANGE_SIZE(p_, size_, committed_size_, committed_size)
+ committed_size_ = committed_size;
+#endif // PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
+}
+#endif // TRACK_COMMITTED_SIZE()
} // namespace base
} // namespace perfetto
-// gen_amalgamated begin source: src/base/string_view_splitter.cc
-// gen_amalgamated begin header: include/perfetto/ext/base/string_view_splitter.h
+// gen_amalgamated begin source: src/base/periodic_task.cc
+// gen_amalgamated begin header: include/perfetto/ext/base/periodic_task.h
/*
- * Copyright (C) 2024 The Android Open Source Project
+ * Copyright (C) 2021 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.
@@ -9152,77 +9644,82 @@ constexpr size_t StringView::npos;
* limitations under the License.
*/
-#ifndef INCLUDE_PERFETTO_EXT_BASE_STRING_VIEW_SPLITTER_H_
-#define INCLUDE_PERFETTO_EXT_BASE_STRING_VIEW_SPLITTER_H_
+#ifndef INCLUDE_PERFETTO_EXT_BASE_PERIODIC_TASK_H_
+#define INCLUDE_PERFETTO_EXT_BASE_PERIODIC_TASK_H_
-// gen_amalgamated expanded: #include "perfetto/ext/base/string_view.h"
+#include <functional>
+
+// gen_amalgamated expanded: #include "perfetto/ext/base/scoped_file.h"
+// gen_amalgamated expanded: #include "perfetto/ext/base/thread_checker.h"
+// gen_amalgamated expanded: #include "perfetto/ext/base/weak_ptr.h"
namespace perfetto {
namespace base {
-// C++ version of strtok(). Splits a StringView without making copies or any
-// heap allocations. Supports the special case of using \0 as a delimiter.
-// The token returned in output are valid as long as the input string is valid.
-class StringViewSplitter {
+class TaskRunner;
+
+// A periodic task utility class. It wraps the logic necessary to do periodic
+// tasks using a TaskRunner, taking care of subtleties like ensuring that
+// outstanding tasks are cancelled after reset/dtor.
+// Tasks are aligned on wall time (unless they are |one_shot|). This is to
+// ensure that when using multiple periodic tasks, they happen at the same time,
+// minimizing context switches.
+// On Linux/Android it also supports suspend-aware mode (via timerfd). On other
+// operating systems it falls back to PostDelayedTask, which is not
+// suspend-aware.
+// TODO(primiano): this should probably become a periodic timer scheduler, so we
+// can use one FD for everything rather than one FD per task. For now we take
+// the hit of a FD-per-task to keep this low-risk.
+// TODO(primiano): consider renaming this class to TimerTask. When |one_shot|
+// is set, the "Periodic" part of the class name becomes a lie.
+class PeriodicTask {
public:
- // Whether an empty string (two delimiters side-to-side) is a valid token.
- enum class EmptyTokenMode {
- DISALLOW_EMPTY_TOKENS,
- ALLOW_EMPTY_TOKENS,
+ explicit PeriodicTask(base::TaskRunner*);
+ ~PeriodicTask(); // Calls Reset().
- DEFAULT = DISALLOW_EMPTY_TOKENS,
+ struct Args {
+ uint32_t period_ms = 0;
+ std::function<void()> task = nullptr;
+ bool start_first_task_immediately = false;
+ bool use_suspend_aware_timer = false;
+ bool one_shot = false;
};
- // Can take ownership of the string if passed via std::move(), e.g.:
- // StringViewSplitter(std::move(str), '\n');
- StringViewSplitter(base::StringView,
- char delimiter,
- EmptyTokenMode empty_token_mode = EmptyTokenMode::DEFAULT);
-
- // Splits the current token from an outer StringViewSplitter instance. This is
- // to chain splitters as follows: for (base::StringViewSplitter lines(x,
- // '\n'); ss.Next();)
- // for (base::StringViewSplitter words(&lines, ' '); words.Next();)
- StringViewSplitter(StringViewSplitter*,
- char delimiter,
- EmptyTokenMode empty_token_mode = EmptyTokenMode::DEFAULT);
-
- // Returns true if a token is found (in which case it will be stored in
- // cur_token()), false if no more tokens are found.
- bool Next();
+ void Start(Args);
- // Returns the next token if, found (in which case it will be stored in
- // cur_token()), and the empty string if no more tokens are found.
- base::StringView NextToken() { return Next() ? cur_token() : ""; }
+ // Safe to be called multiple times, even without calling Start():
+ void Reset();
- // Returns the current token iff last call to Next() returned true.
- // In all other cases (before the 1st call to Next() and after Next() returns
- // false) returns the empty string.
- base::StringView cur_token() { return cur_; }
+ // No copy or move. WeakPtr-wrapped pointers to |this| are posted on the
+ // task runner, this class is not easily movable.
+ PeriodicTask(const PeriodicTask&) = delete;
+ PeriodicTask& operator=(const PeriodicTask&) = delete;
+ PeriodicTask(PeriodicTask&&) = delete;
+ PeriodicTask& operator=(PeriodicTask&&) = delete;
- // Returns the remainder of the current input string that has not yet been
- // tokenized.
- base::StringView remainder() { return next_; }
+ base::PlatformHandle timer_fd_for_testing() { return *timer_fd_; }
private:
- StringViewSplitter(const StringViewSplitter&) = delete;
- StringViewSplitter& operator=(const StringViewSplitter&) = delete;
- void Initialize(base::StringView);
+ static void RunTaskAndPostNext(base::WeakPtr<PeriodicTask>,
+ uint32_t generation);
+ void PostNextTask();
+ void ResetTimerFd();
- base::StringView str_;
- base::StringView cur_;
- base::StringView next_;
- bool end_of_input_;
- const char delimiter_;
- const EmptyTokenMode empty_token_mode_;
+ base::TaskRunner* const task_runner_;
+ Args args_;
+ uint32_t generation_ = 0;
+ base::ScopedPlatformHandle timer_fd_;
+
+ PERFETTO_THREAD_CHECKER(thread_checker_)
+ base::WeakPtrFactory<PeriodicTask> weak_ptr_factory_; // Keep last.
};
} // namespace base
} // namespace perfetto
-#endif // INCLUDE_PERFETTO_EXT_BASE_STRING_VIEW_SPLITTER_H_
+#endif // INCLUDE_PERFETTO_EXT_BASE_PERIODIC_TASK_H_
/*
- * Copyright (C) 2024 The Android Open Source Project
+ * Copyright (C) 2021 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.
@@ -9237,170 +9734,178 @@ class StringViewSplitter {
* limitations under the License.
*/
-// gen_amalgamated expanded: #include "perfetto/ext/base/string_view_splitter.h"
+// gen_amalgamated expanded: #include "perfetto/ext/base/periodic_task.h"
-#include <utility>
+#include <limits>
+// gen_amalgamated expanded: #include "perfetto/base/build_config.h"
// gen_amalgamated expanded: #include "perfetto/base/logging.h"
+// gen_amalgamated expanded: #include "perfetto/base/task_runner.h"
+// gen_amalgamated expanded: #include "perfetto/base/time.h"
+// gen_amalgamated expanded: #include "perfetto/ext/base/file_utils.h"
+
+#if PERFETTO_BUILDFLAG(PERFETTO_OS_LINUX_BUT_NOT_QNX) || \
+ PERFETTO_BUILDFLAG(PERFETTO_OS_FREEBSD) || \
+ (PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID) && __ANDROID_API__ >= 19)
+#include <sys/timerfd.h>
+#endif
namespace perfetto {
namespace base {
-StringViewSplitter::StringViewSplitter(base::StringView str,
- char delimiter,
- EmptyTokenMode empty_token_mode)
- : str_(std::move(str)),
- delimiter_(delimiter),
- empty_token_mode_(empty_token_mode) {
- Initialize(str);
-}
+namespace {
-StringViewSplitter::StringViewSplitter(StringViewSplitter* outer,
- char delimiter,
- EmptyTokenMode empty_token_mode)
- : delimiter_(delimiter), empty_token_mode_(empty_token_mode) {
- Initialize(outer->cur_token());
-}
+uint32_t GetNextDelayMs(const TimeMillis& now_ms,
+ const PeriodicTask::Args& args) {
+ if (args.one_shot)
+ return args.period_ms;
-void StringViewSplitter::Initialize(base::StringView str) {
- next_ = str;
- cur_ = "";
- end_of_input_ = false;
+ return args.period_ms -
+ static_cast<uint32_t>(now_ms.count() % args.period_ms);
}
-bool StringViewSplitter::Next() {
- if (end_of_input_) {
- cur_ = next_ = "";
- return false;
- }
+ScopedPlatformHandle CreateTimerFd(const PeriodicTask::Args& args) {
+#if PERFETTO_BUILDFLAG(PERFETTO_OS_LINUX_BUT_NOT_QNX) || \
+ PERFETTO_BUILDFLAG(PERFETTO_OS_FREEBSD) || \
+ (PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID) && __ANDROID_API__ >= 19)
+ ScopedPlatformHandle tfd(
+ timerfd_create(CLOCK_BOOTTIME, TFD_CLOEXEC | TFD_NONBLOCK));
+ uint32_t phase_ms = GetNextDelayMs(GetBootTimeMs(), args);
- size_t substr_start = 0;
- if (empty_token_mode_ == EmptyTokenMode::DISALLOW_EMPTY_TOKENS) {
- while (substr_start < next_.size() &&
- next_.at(substr_start) == delimiter_) {
- substr_start++;
- }
+ struct itimerspec its{};
+ // The "1 +" is to make sure that we never pass a zero it_value in the
+ // unlikely case of phase_ms being 0. That would cause the timer to be
+ // considered disarmed by timerfd_settime.
+ its.it_value.tv_sec = static_cast<time_t>(phase_ms / 1000u);
+ its.it_value.tv_nsec = 1 + static_cast<long>((phase_ms % 1000u) * 1000000u);
+ if (args.one_shot) {
+ its.it_interval.tv_sec = 0;
+ its.it_interval.tv_nsec = 0;
+ } else {
+ const uint32_t period_ms = args.period_ms;
+ its.it_interval.tv_sec = static_cast<time_t>(period_ms / 1000u);
+ its.it_interval.tv_nsec = static_cast<long>((period_ms % 1000u) * 1000000u);
}
+ if (timerfd_settime(*tfd, 0, &its, nullptr) < 0)
+ return ScopedPlatformHandle();
+ return tfd;
+#else
+ ignore_result(args);
+ return ScopedPlatformHandle();
+#endif
+}
- if (substr_start >= next_.size()) {
- end_of_input_ = true;
- cur_ = next_ = "";
- return !cur_.empty() ||
- empty_token_mode_ == EmptyTokenMode::ALLOW_EMPTY_TOKENS;
- }
+} // namespace
- size_t delimiter_start = next_.find(delimiter_, substr_start);
- if (delimiter_start == base::StringView::npos) {
- cur_ = next_.substr(substr_start);
- next_ = "";
- end_of_input_ = true;
- return !cur_.empty() ||
- empty_token_mode_ == EmptyTokenMode::ALLOW_EMPTY_TOKENS;
- }
+PeriodicTask::PeriodicTask(TaskRunner* task_runner)
+ : task_runner_(task_runner), weak_ptr_factory_(this) {}
- size_t delimiter_end = delimiter_start + 1;
+PeriodicTask::~PeriodicTask() {
+ Reset();
+}
- if (empty_token_mode_ == EmptyTokenMode::DISALLOW_EMPTY_TOKENS) {
- while (delimiter_end < next_.size() &&
- next_.at(delimiter_end) == delimiter_) {
- delimiter_end++;
- }
- if (delimiter_end >= next_.size()) {
- end_of_input_ = true;
- }
+void PeriodicTask::Start(Args args) {
+ PERFETTO_DCHECK_THREAD(thread_checker_);
+ Reset();
+ if (args.period_ms == 0 || !args.task) {
+ PERFETTO_DCHECK(args.period_ms > 0);
+ PERFETTO_DCHECK(args.task);
+ return;
}
+ args_ = std::move(args);
+ if (args_.use_suspend_aware_timer) {
+ timer_fd_ = CreateTimerFd(args_);
+ if (timer_fd_) {
+ auto weak_this = weak_ptr_factory_.GetWeakPtr();
+ task_runner_->AddFileDescriptorWatch(
+ *timer_fd_,
+ std::bind(PeriodicTask::RunTaskAndPostNext, weak_this, generation_));
+ } else {
+ PERFETTO_DPLOG("timerfd not supported, falling back on PostDelayedTask");
+ }
+ } // if (use_suspend_aware_timer).
- cur_ = next_.substr(substr_start, delimiter_start - substr_start);
- next_ = next_.substr(delimiter_end);
+ if (!timer_fd_)
+ PostNextTask();
- return !cur_.empty() ||
- empty_token_mode_ == EmptyTokenMode::ALLOW_EMPTY_TOKENS;
+ if (args_.start_first_task_immediately)
+ args_.task();
}
-} // namespace base
-} // namespace perfetto
-// gen_amalgamated begin source: src/base/temp_file.cc
-// gen_amalgamated begin header: include/perfetto/ext/base/temp_file.h
-/*
- * 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.
- */
-
-#ifndef INCLUDE_PERFETTO_EXT_BASE_TEMP_FILE_H_
-#define INCLUDE_PERFETTO_EXT_BASE_TEMP_FILE_H_
-
-#include <string>
-
-// gen_amalgamated expanded: #include "perfetto/ext/base/scoped_file.h"
-
-namespace perfetto {
-namespace base {
-
-std::string GetSysTempDir();
-
-class TempFile {
- public:
- static TempFile CreateUnlinked();
- static TempFile Create();
-
- TempFile(TempFile&&) noexcept;
- TempFile& operator=(TempFile&&);
- ~TempFile();
-
- const std::string& path() const { return path_; }
- int fd() const { return *fd_; }
- int operator*() const { return *fd_; }
-
- // Unlinks the file from the filesystem but keeps the fd() open.
- // It is safe to call this multiple times.
- void Unlink();
-
- // Releases the underlying file descriptor. Will unlink the file from the
- // filesystem if it was created via CreateUnlinked().
- ScopedFile ReleaseFD();
-
- private:
- TempFile();
- TempFile(const TempFile&) = delete;
- TempFile& operator=(const TempFile&) = delete;
+void PeriodicTask::PostNextTask() {
+ PERFETTO_DCHECK_THREAD(thread_checker_);
+ PERFETTO_DCHECK(args_.period_ms > 0);
+ PERFETTO_DCHECK(!timer_fd_);
+ uint32_t delay_ms = GetNextDelayMs(GetWallTimeMs(), args_);
+ auto weak_this = weak_ptr_factory_.GetWeakPtr();
+ task_runner_->PostDelayedTask(
+ std::bind(PeriodicTask::RunTaskAndPostNext, weak_this, generation_),
+ delay_ms);
+}
- ScopedFile fd_;
- std::string path_;
-};
+// static
+// This function can be called in two ways (both from the TaskRunner):
+// 1. When using a timerfd, this task is registered as a FD watch.
+// 2. When using PostDelayedTask, this is the task posted on the TaskRunner.
+void PeriodicTask::RunTaskAndPostNext(WeakPtr<PeriodicTask> thiz,
+ uint32_t generation) {
+ if (!thiz || !thiz->args_.task || generation != thiz->generation_)
+ return; // Destroyed or Reset() in the meanwhile.
+ PERFETTO_DCHECK_THREAD(thiz->thread_checker_);
+ if (thiz->timer_fd_) {
+#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
+ PERFETTO_FATAL("timerfd for periodic tasks unsupported on Windows");
+#else
+ // If we are using a timerfd there is no need to repeatedly call
+ // PostDelayedTask(). The kernel will wakeup the timer fd periodically. We
+ // just need to read() it.
+ uint64_t ignored = 0;
+ errno = 0;
+ auto rsize = Read(*thiz->timer_fd_, &ignored, sizeof(&ignored));
+ if (rsize != sizeof(uint64_t)) {
+ if (errno == EAGAIN)
+ return; // A spurious wakeup. Rare, but can happen, just ignore.
+ PERFETTO_PLOG("read(timerfd) failed, falling back on PostDelayedTask");
+ thiz->ResetTimerFd();
+ }
+#endif
+ }
-class TempDir {
- public:
- static TempDir Create();
+ // Create a copy of the task to deal with either:
+ // 1. one_shot causing a Reset().
+ // 2. task() invoking internally Reset().
+ // That would cause a reset of the args_.task itself, which would invalidate
+ // the task bind state while we are invoking it.
+ auto task = thiz->args_.task;
- TempDir(TempDir&&) noexcept;
- TempDir& operator=(TempDir&&);
- ~TempDir();
+ // The repetition of the if() is to deal with the ResetTimerFd() case above.
+ if (thiz->args_.one_shot) {
+ thiz->Reset();
+ } else if (!thiz->timer_fd_) {
+ thiz->PostNextTask();
+ }
- const std::string& path() const { return path_; }
+ task();
+}
- private:
- TempDir();
- TempDir(const TempDir&) = delete;
- TempDir& operator=(const TempDir&) = delete;
+void PeriodicTask::Reset() {
+ PERFETTO_DCHECK_THREAD(thread_checker_);
+ ++generation_;
+ args_ = Args();
+ PERFETTO_DCHECK(!args_.task);
+ ResetTimerFd();
+}
- std::string path_;
-};
+void PeriodicTask::ResetTimerFd() {
+ if (!timer_fd_)
+ return;
+ task_runner_->RemoveFileDescriptorWatch(*timer_fd_);
+ timer_fd_.reset();
+}
} // namespace base
} // namespace perfetto
-
-#endif // INCLUDE_PERFETTO_EXT_BASE_TEMP_FILE_H_
+// gen_amalgamated begin source: src/base/pipe.cc
/*
* Copyright (C) 2018 The Android Open Source Project
*
@@ -9417,151 +9922,67 @@ class TempDir {
* limitations under the License.
*/
-// gen_amalgamated expanded: #include "perfetto/ext/base/temp_file.h"
+// gen_amalgamated expanded: #include "perfetto/ext/base/pipe.h"
// gen_amalgamated expanded: #include "perfetto/base/build_config.h"
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
+#include <fcntl.h> // For O_BINARY (Windows) and F_SETxx (UNIX)
#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
#include <windows.h>
-#include <direct.h>
-#include <fileapi.h>
-#include <io.h>
+#include <namedpipeapi.h>
#else
+#include <sys/types.h>
#include <unistd.h>
#endif
// gen_amalgamated expanded: #include "perfetto/base/logging.h"
-// gen_amalgamated expanded: #include "perfetto/ext/base/file_utils.h"
-// gen_amalgamated expanded: #include "perfetto/ext/base/string_utils.h"
namespace perfetto {
namespace base {
-#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
-namespace {
-std::string GetTempFilePathWin() {
- std::string tmplt = GetSysTempDir() + "\\perfetto-XXXXXX";
- StackString<255> name("%s\\perfetto-XXXXXX", GetSysTempDir().c_str());
- PERFETTO_CHECK(_mktemp_s(name.mutable_data(), name.len() + 1) == 0);
- return name.ToStdString();
-}
-} // namespace
-#endif
-
-std::string GetSysTempDir() {
- const char* tmpdir = nullptr;
-#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
- if ((tmpdir = getenv("TMP")))
- return tmpdir;
- if ((tmpdir = getenv("TEMP")))
- return tmpdir;
- return "C:\\TEMP";
-#else
- if ((tmpdir = getenv("TMPDIR")))
- return base::StripSuffix(tmpdir, "/");
-#if PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID)
- return "/data/local/tmp";
-#else
- return "/tmp";
-#endif // !OS_ANDROID
-#endif // !OS_WIN
-}
-
-// static
-TempFile TempFile::Create() {
- TempFile temp_file;
-#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
- temp_file.path_ = GetTempFilePathWin();
- // Several tests want to read-back the temp file while still open. On Windows,
- // that requires FILE_SHARE_READ. FILE_SHARE_READ is NOT settable when using
- // the POSIX-compat equivalent function _open(). Hence the CreateFileA +
- // _open_osfhandle dance here.
- HANDLE h =
- ::CreateFileA(temp_file.path_.c_str(), GENERIC_READ | GENERIC_WRITE,
- FILE_SHARE_DELETE | FILE_SHARE_READ, nullptr, CREATE_ALWAYS,
- FILE_ATTRIBUTE_TEMPORARY, nullptr);
- PERFETTO_CHECK(PlatformHandleChecker::IsValid(h));
- // According to MSDN, when using _open_osfhandle the caller must not call
- // CloseHandle(). Ownership is moved to the file descriptor, which then needs
- // to be closed with just with _close().
- temp_file.fd_.reset(_open_osfhandle(reinterpret_cast<intptr_t>(h), 0));
-#else
- temp_file.path_ = GetSysTempDir() + "/perfetto-XXXXXXXX";
- temp_file.fd_.reset(mkstemp(&temp_file.path_[0]));
-#endif
- if (PERFETTO_UNLIKELY(!temp_file.fd_)) {
- PERFETTO_FATAL("Could not create temp file %s", temp_file.path_.c_str());
- }
- return temp_file;
-}
-
-// static
-TempFile TempFile::CreateUnlinked() {
- TempFile temp_file = TempFile::Create();
- temp_file.Unlink();
- return temp_file;
-}
-
-TempFile::TempFile() = default;
-
-TempFile::~TempFile() {
- Unlink();
-}
-
-ScopedFile TempFile::ReleaseFD() {
- Unlink();
- return std::move(fd_);
-}
+Pipe::Pipe() = default;
+Pipe::Pipe(Pipe&&) noexcept = default;
+Pipe& Pipe::operator=(Pipe&&) = default;
-void TempFile::Unlink() {
- if (path_.empty())
- return;
+Pipe Pipe::Create(Flags flags) {
+ PlatformHandle fds[2];
#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
- // If the FD is still open DeleteFile will mark the file as pending deletion
- // and delete it only when the process exists.
- PERFETTO_CHECK(DeleteFileA(path_.c_str()));
+ PERFETTO_CHECK(::CreatePipe(&fds[0], &fds[1], /*lpPipeAttributes=*/nullptr,
+ 0 /*default size*/));
#else
- PERFETTO_CHECK(unlink(path_.c_str()) == 0);
+ PERFETTO_CHECK(pipe(fds) == 0);
+ PERFETTO_CHECK(fcntl(fds[0], F_SETFD, FD_CLOEXEC) == 0);
+ PERFETTO_CHECK(fcntl(fds[1], F_SETFD, FD_CLOEXEC) == 0);
#endif
- path_.clear();
-}
+ Pipe p;
+ p.rd.reset(fds[0]);
+ p.wr.reset(fds[1]);
-TempFile::TempFile(TempFile&&) noexcept = default;
-TempFile& TempFile::operator=(TempFile&&) = default;
+#if !PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
+ if (flags == kBothNonBlock || flags == kRdNonBlock) {
+ int cur_flags = fcntl(*p.rd, F_GETFL, 0);
+ PERFETTO_CHECK(cur_flags >= 0);
+ PERFETTO_CHECK(fcntl(*p.rd, F_SETFL, cur_flags | O_NONBLOCK) == 0);
+ }
-// static
-TempDir TempDir::Create() {
- TempDir temp_dir;
-#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
- temp_dir.path_ = GetTempFilePathWin();
- PERFETTO_CHECK(_mkdir(temp_dir.path_.c_str()) == 0);
+ if (flags == kBothNonBlock || flags == kWrNonBlock) {
+ int cur_flags = fcntl(*p.wr, F_GETFL, 0);
+ PERFETTO_CHECK(cur_flags >= 0);
+ PERFETTO_CHECK(fcntl(*p.wr, F_SETFL, cur_flags | O_NONBLOCK) == 0);
+ }
#else
- temp_dir.path_ = GetSysTempDir() + "/perfetto-XXXXXXXX";
- PERFETTO_CHECK(mkdtemp(&temp_dir.path_[0]));
+ PERFETTO_CHECK(flags == kBothBlock);
#endif
- return temp_dir;
-}
-
-TempDir::TempDir() = default;
-TempDir::TempDir(TempDir&&) noexcept = default;
-TempDir& TempDir::operator=(TempDir&&) = default;
-
-TempDir::~TempDir() {
- if (path_.empty())
- return; // For objects that get std::move()d.
- PERFETTO_CHECK(Rmdir(path_));
+ return p;
}
} // namespace base
} // namespace perfetto
-// gen_amalgamated begin source: src/base/thread_checker.cc
+// gen_amalgamated begin source: src/base/progress_reporter.cc
/*
- * Copyright (C) 2017 The Android Open Source Project
+ * Copyright (C) 2026 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.
@@ -9576,61 +9997,159 @@ TempDir::~TempDir() {
* limitations under the License.
*/
-// gen_amalgamated expanded: #include "perfetto/ext/base/thread_checker.h"
+// gen_amalgamated expanded: #include "perfetto/ext/base/progress_reporter.h"
+
+#include <algorithm>
+#include <cstdio>
+#include <cstdlib>
+#include <cstring>
+#include <mutex>
+#include <string_view>
+
+// gen_amalgamated expanded: #include "perfetto/base/build_config.h"
+// gen_amalgamated expanded: #include "perfetto/base/time.h"
+// gen_amalgamated expanded: #include "perfetto/ext/base/utils.h"
#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
#include <windows.h>
+#elif !PERFETTO_BUILDFLAG(PERFETTO_OS_WASM)
+#include <sys/ioctl.h>
+#include <termios.h>
+#include <unistd.h>
#endif
-namespace perfetto {
-namespace base {
-
+namespace perfetto::base {
namespace {
-constexpr ThreadID kDetached{};
-ThreadID CurrentThreadId() {
-#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
- return ::GetCurrentThreadId();
+constexpr int64_t kMinUpdateIntervalMs = 100;
+
+#if !PERFETTO_BUILDFLAG(PERFETTO_OS_WASM)
+bool StderrIsInteractiveTerminal() {
+#if PERFETTO_BUILDFLAG(PERFETTO_CHROMIUM_BUILD)
+ // isatty() is blocked by the Chrome seccomp-bpf sandbox (b/191235714).
+ return false;
#else
- return pthread_self();
+ const char* term = getenv("TERM");
+ return IsTty(stderr) && (!term || strcmp(term, "dumb") != 0);
+#endif
+}
+#endif
+
+#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
+// Fails when stderr is not a console or the console predates ANSI support.
+bool EnableVirtualTerminalProcessing() {
+ HANDLE handle = GetStdHandle(STD_ERROR_HANDLE);
+ DWORD mode = 0;
+ if (handle == INVALID_HANDLE_VALUE || !GetConsoleMode(handle, &mode))
+ return false;
+ return SetConsoleMode(handle, mode | ENABLE_VIRTUAL_TERMINAL_PROCESSING) != 0;
+}
#endif
+
+size_t TerminalWidth() {
+#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
+ CONSOLE_SCREEN_BUFFER_INFO info{};
+ if (GetConsoleScreenBufferInfo(GetStdHandle(STD_ERROR_HANDLE), &info))
+ return static_cast<size_t>(info.srWindow.Right - info.srWindow.Left + 1);
+#elif !PERFETTO_BUILDFLAG(PERFETTO_OS_WASM)
+ struct winsize size{};
+ if (ioctl(STDERR_FILENO, TIOCGWINSZ, &size) == 0 && size.ws_col)
+ return size.ws_col;
+#endif
+ return 80;
}
+
} // namespace
-ThreadChecker::ThreadChecker() {
- thread_id_.store(CurrentThreadId());
+bool StderrSupportsProgress() {
+#if PERFETTO_BUILDFLAG(PERFETTO_OS_WASM)
+ return true;
+#else
+ return StderrIsInteractiveTerminal();
+#endif
}
-ThreadChecker::~ThreadChecker() = default;
+bool StderrSupportsColor() {
+#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
+ // Attempt this even when colors are forced, so that escapes are interpreted
+ // wherever the console can.
+ static const bool vt_enabled = EnableVirtualTerminalProcessing();
+#endif
+ const char* force_color = getenv("FORCE_COLOR");
+ if (force_color && *force_color)
+ return true;
+ const char* no_color = getenv("NO_COLOR");
+ if (no_color && *no_color)
+ return false;
+#if PERFETTO_BUILDFLAG(PERFETTO_OS_WASM)
+ return false;
+#elif PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
+ return vt_enabled && StderrIsInteractiveTerminal();
+#else
+ return StderrIsInteractiveTerminal();
+#endif
+}
-ThreadChecker::ThreadChecker(const ThreadChecker& other)
- : thread_id_(other.thread_id_.load()) {}
+ProgressReporter& ProgressReporter::GetInstance() {
+ static ProgressReporter* instance = new ProgressReporter();
+ return *instance;
+}
-ThreadChecker& ThreadChecker::operator=(const ThreadChecker& other) {
- thread_id_ = other.thread_id_.load();
- return *this;
+void ProgressReporter::set_enabled(bool enabled) {
+ std::lock_guard<std::mutex> lock(mutex_);
+ enabled_ = enabled;
}
-bool ThreadChecker::CalledOnValidThread() const {
- auto self = CurrentThreadId();
+void ProgressReporter::Update(std::string_view message) {
+ std::lock_guard<std::mutex> lock(mutex_);
+ if (!enabled_ || !StderrSupportsProgress())
+ return;
+ int64_t now = GetWallTimeMs().count();
+ if (last_update_ms_ && now - last_update_ms_ < kMinUpdateIntervalMs)
+ return;
+#if PERFETTO_BUILDFLAG(PERFETTO_OS_WASM)
+ last_update_ms_ = now;
+ // stdio reaches the embedder only when a write ends with a newline.
+ fprintf(stderr, "%.*s\n", static_cast<int>(message.size()), message.data());
+#else
+ // Leave one column unused to avoid wrapping, including on narrow terminals.
+ size_t width = TerminalWidth();
+ size_t new_width = std::min(message.size(), width > 1 ? width - 1 : 0);
+ if (new_width < visible_width_)
+ ClearLocked();
+ // Set after clearing, which resets the throttle for the next phase.
+ last_update_ms_ = now;
+ if (!new_width)
+ return;
+ fprintf(stderr, "\r%.*s", static_cast<int>(new_width), message.data());
+ fflush(stderr);
+ visible_width_ = new_width;
+#endif
+}
- // Will re-attach if previously detached using DetachFromThread().
- auto prev_value = kDetached;
- if (thread_id_.compare_exchange_strong(prev_value, self))
- return true;
- return prev_value == self;
+void ProgressReporter::ClearLocked() {
+ if (!visible_width_)
+ return;
+ // Bound clearing by the current width in case the terminal was resized.
+ size_t width = TerminalWidth();
+ size_t clear = std::min(visible_width_, width > 1 ? width - 1 : 0);
+ fprintf(stderr, "\r%*s\r", static_cast<int>(clear), "");
+ fflush(stderr);
+ visible_width_ = 0;
+ // The next phase's first update should not be throttled by this one.
+ last_update_ms_ = 0;
}
-void ThreadChecker::DetachFromThread() {
- thread_id_.store(kDetached);
+void ProgressReporter::Clear() {
+ std::lock_guard<std::mutex> lock(mutex_);
+ ClearLocked();
}
-} // namespace base
-} // namespace perfetto
-// gen_amalgamated begin source: src/base/thread_utils.cc
-// gen_amalgamated begin header: include/perfetto/ext/base/thread_utils.h
+} // namespace perfetto::base
+// gen_amalgamated begin source: src/base/rt_mutex.cc
+// gen_amalgamated begin header: include/perfetto/ext/base/rt_mutex.h
/*
- * Copyright (C) 2020 The Android Open Source Project
+ * Copyright (C) 2025 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.
@@ -9645,177 +10164,197 @@ void ThreadChecker::DetachFromThread() {
* limitations under the License.
*/
-#ifndef INCLUDE_PERFETTO_EXT_BASE_THREAD_UTILS_H_
-#define INCLUDE_PERFETTO_EXT_BASE_THREAD_UTILS_H_
+#ifndef INCLUDE_PERFETTO_EXT_BASE_RT_MUTEX_H_
+#define INCLUDE_PERFETTO_EXT_BASE_RT_MUTEX_H_
-#include <string>
+// This header introduces the RtMutex class for priority-inheritance mutexes.
+// RtMutex is NOT a blanket replacement for std::mutex and should be used only
+// in cases where we know we are expect to be used on a RT thread.
+// In the contended case RtMutex is generally slower than a std::mutex (or any
+// non-RT implementation).
+// Under the hoods this class does the following:
+// - Android: it uses PI futexes.
+// - Linux/MacOS/iOS: it uses pthread_mutex with PTHREAD_PRIO_INHERIT.
+// - Other platforms: falls back on a standard std::mutex. On Windows 11+
+// std::mutex has effectively PI semantics due to AutoBoost
+// https://github.com/MicrosoftDocs/win32/commit/a43cb3b5039c5cfc53642bfcea174003a2f1168f
// gen_amalgamated expanded: #include "perfetto/base/build_config.h"
-// gen_amalgamated expanded: #include "perfetto/base/export.h"
-// gen_amalgamated expanded: #include "perfetto/ext/base/string_utils.h"
+// gen_amalgamated expanded: #include "perfetto/base/thread_annotations.h"
+// gen_amalgamated expanded: #include "perfetto/public/compiler.h"
-#if PERFETTO_BUILDFLAG(PERFETTO_OS_LINUX) || \
- PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID) || \
+#define _PERFETTO_MUTEX_MODE_STD 0
+#define _PERFETTO_MUTEX_MODE_RT_FUTEX 1
+#define _PERFETTO_MUTEX_MODE_RT_MUTEX 2
+
+// The logic below determines which mutex implementation to use.
+// For Android platform builds, the choice is controlled by aconfig flags.
+// For other builds, it's determined by OS support and GN build arguments.
+//
+// Rationale for platform-specific choices:
+// 1. `RtFutex` is enabled only on Android because it relies on `gettid()` being
+// a cheap thread-local storage access provided by Bionic. On Linux with
+// glibc, `gettid()` is a full syscall, making the pthread-based
+// implementation faster.
+// 2. The pthread-based `RtPosixMutex` is not viable on all Android versions, as
+// `pthread_mutexattr_setprotocol` was introduced in API level 28. Using
+// `dlsym` to backport it can lead to deadlocks with the loader lock if
+// tracing is initialized from a static constructor (see b/443178555).
+#if PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID) && \
+ PERFETTO_BUILDFLAG(PERFETTO_ANDROID_BUILD)
+#define _PERFETTO_MUTEX_MODE _PERFETTO_MUTEX_MODE_RT_FUTEX
+#elif PERFETTO_BUILDFLAG(PERFETTO_ENABLE_RT_MUTEX)
+#if PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID)
+#define _PERFETTO_MUTEX_MODE _PERFETTO_MUTEX_MODE_RT_FUTEX
+#elif PERFETTO_BUILDFLAG(PERFETTO_OS_LINUX) || \
PERFETTO_BUILDFLAG(PERFETTO_OS_APPLE)
-#include <pthread.h>
-#include <string.h>
-#include <algorithm>
+#define _PERFETTO_MUTEX_MODE _PERFETTO_MUTEX_MODE_RT_MUTEX
+#endif
#endif
-#if PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID)
-#include <sys/prctl.h>
+// If no RT implementation was selected, default to std::mutex.
+#ifndef _PERFETTO_MUTEX_MODE
+#define _PERFETTO_MUTEX_MODE _PERFETTO_MUTEX_MODE_STD
#endif
-// Internal implementation utils that aren't as widely useful/supported as
-// base/thread_utils.h.
+// Public macros for conditional compilation based on the selected mutex type.
+#define PERFETTO_HAS_POSIX_RT_MUTEX() \
+ (_PERFETTO_MUTEX_MODE == _PERFETTO_MUTEX_MODE_RT_MUTEX)
+#define PERFETTO_HAS_RT_FUTEX() \
+ (_PERFETTO_MUTEX_MODE == _PERFETTO_MUTEX_MODE_RT_FUTEX)
-namespace perfetto {
-namespace base {
+#include <atomic>
+#include <mutex>
+#include <type_traits>
-#if PERFETTO_BUILDFLAG(PERFETTO_OS_LINUX) || \
- PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID) || \
- PERFETTO_BUILDFLAG(PERFETTO_OS_APPLE)
-// Sets the "comm" of the calling thread to the first 15 chars of the given
-// string.
-inline bool MaybeSetThreadName(const std::string& name) {
- char buf[16] = {};
- StringCopy(buf, name.c_str(), sizeof(buf));
+#if PERFETTO_HAS_POSIX_RT_MUTEX()
+#include <pthread.h>
+#endif
-#if PERFETTO_BUILDFLAG(PERFETTO_OS_APPLE)
- return pthread_setname_np(buf) == 0;
-#else
- return pthread_setname_np(pthread_self(), buf) == 0;
+#if !PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
+#include <unistd.h> // For gettid().
#endif
-}
-inline bool GetThreadName(std::string& out_result) {
- char buf[16] = {};
-#if PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID)
- if (prctl(PR_GET_NAME, buf) != 0)
- return false;
-#else
- if (pthread_getname_np(pthread_self(), buf, sizeof(buf)) != 0)
- return false;
-#endif
- out_result = std::string(buf);
- return true;
-}
+namespace perfetto::base {
-#elif PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
+namespace internal {
-PERFETTO_EXPORT_COMPONENT bool MaybeSetThreadName(const std::string& name);
-PERFETTO_EXPORT_COMPONENT bool GetThreadName(std::string& out_result);
+#if PERFETTO_HAS_RT_FUTEX()
+// A wrapper around PI Futexes. A futex is a wrapper around an atomic integer
+// with an ABI shared with the kernel to handle the slowpath in the cases when
+// the mutex is held, or we find out that there are waiters queued when we
+// unlock. The operating principle is the following:
+// - In the no-contention case, a futex boils down to an atomic
+// compare-and-exchange, without involving the kernel.
+// - If a lock is contented at acquire time, we have to enter the kernel to
+// suspend our execution and join a wait chain.
+// - It could still happen that we acquire the mutex via the fastpath (without
+// involving the kernel) but other waiters might queue up while we hold the
+// mutex. In that case the kernel will add a bit to the atomic int. That bit
+// will cause the unlock() compare-and-exchange to fail (because it no longer
+// matches our tid) which in turn will signal us to do a syscall to notify the
+// waiters.
+class PERFETTO_LOCKABLE RtFutex {
+ public:
+ RtFutex() { PERFETTO_TSAN_MUTEX_CREATE(this, __tsan_mutex_not_static); }
+ ~RtFutex() { PERFETTO_TSAN_MUTEX_DESTROY(this, __tsan_mutex_not_static); }
-#else
-inline bool MaybeSetThreadName(const std::string&) {
- return false;
-}
-inline bool GetThreadName(std::string&) {
- return false;
-}
-#endif
+ // Disable copy or move. Copy doesn't make sense. Move isn't feasible because
+ // the pointer to the atomic integer is the handle used by the kernel to setup
+ // the wait chain. A movable futex would require the atomic integer to be heap
+ // allocated, but that would create an indirection layer that is not needed in
+ // most cases. If you really need a movable RtMutex, wrap it in a unique_ptr.
+ RtFutex(const RtFutex&) = delete;
+ RtFutex& operator=(const RtFutex&) = delete;
+ RtFutex(RtFutex&&) = delete;
+ RtFutex& operator=(RtFutex&&) = delete;
-} // namespace base
-} // namespace perfetto
+ inline bool TryLockFastpath() noexcept {
+ int expected = 0;
+ return lock_.compare_exchange_strong(expected, ::gettid(),
+ std::memory_order_acquire,
+ std::memory_order_relaxed);
+ }
-#endif // INCLUDE_PERFETTO_EXT_BASE_THREAD_UTILS_H_
-/*
- * 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.
- */
+ bool try_lock() noexcept PERFETTO_EXCLUSIVE_TRYLOCK_FUNCTION(true) {
+ PERFETTO_TSAN_MUTEX_PRE_LOCK(this, __tsan_mutex_try_lock);
+ if (PERFETTO_LIKELY(TryLockFastpath()) || TryLockSlowpath()) {
+ PERFETTO_TSAN_MUTEX_POST_LOCK(this, __tsan_mutex_try_lock, 0);
+ return true;
+ }
+ PERFETTO_TSAN_MUTEX_POST_LOCK(
+ this, __tsan_mutex_try_lock | __tsan_mutex_try_lock_failed, 0);
+ return false;
+ }
-// gen_amalgamated expanded: #include "perfetto/base/thread_utils.h"
-// gen_amalgamated expanded: #include "perfetto/ext/base/thread_utils.h"
+ void lock() PERFETTO_EXCLUSIVE_LOCK_FUNCTION() {
+ PERFETTO_TSAN_MUTEX_PRE_LOCK(this, 0);
+ if (!PERFETTO_LIKELY(TryLockFastpath())) {
+ LockSlowpath();
+ }
+ PERFETTO_TSAN_MUTEX_POST_LOCK(this, 0, 0);
+ }
-// gen_amalgamated expanded: #include "perfetto/base/build_config.h"
+ void unlock() noexcept PERFETTO_UNLOCK_FUNCTION() {
+ PERFETTO_TSAN_MUTEX_PRE_UNLOCK(this, 0);
+ int expected = ::gettid();
+ // If the current value is our tid, we can unlock without a syscall since
+ // there are no current waiters.
+ if (!PERFETTO_LIKELY(lock_.compare_exchange_strong(
+ expected, 0, std::memory_order_release,
+ std::memory_order_relaxed))) {
+ // The tid doesn't match because the kernel appended the FUTEX_WAITERS
+ // bit. There are waiters, tell the kernel to notify them and unlock.
+ UnlockSlowpath();
+ }
+ PERFETTO_TSAN_MUTEX_POST_UNLOCK(this, 0);
+ }
-#if PERFETTO_BUILDFLAG(PERFETTO_OS_FUCHSIA)
-#include <zircon/process.h>
-#include <zircon/syscalls.h>
-#include <zircon/types.h>
-#elif PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
-#include <windows.h>
-#endif
+ private:
+ std::atomic<int> lock_{};
-namespace perfetto {
-namespace base {
+ void LockSlowpath();
+ bool TryLockSlowpath();
+ void UnlockSlowpath();
+};
-#if PERFETTO_BUILDFLAG(PERFETTO_OS_FUCHSIA)
-static PlatformThreadId ResolveThreadId() {
- zx_info_handle_basic_t basic;
- return (zx_object_get_info(zx_thread_self(), ZX_INFO_HANDLE_BASIC, &basic,
- sizeof(basic), nullptr, nullptr) == ZX_OK)
- ? basic.koid
- : ZX_KOID_INVALID;
-}
-PlatformThreadId GetThreadId() {
- thread_local static PlatformThreadId thread_id = ResolveThreadId();
- return thread_id;
-}
+#endif // PERFETTO_HAS_RT_FUTEX
-#elif PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
+#if PERFETTO_HAS_POSIX_RT_MUTEX()
+class PERFETTO_LOCKABLE RtPosixMutex {
+ public:
+ RtPosixMutex() noexcept;
+ ~RtPosixMutex() noexcept;
-// The SetThreadDescription API was brought in version 1607 of Windows 10.
-typedef HRESULT(WINAPI* SetThreadDescription)(HANDLE hThread,
- PCWSTR lpThreadDescription);
+ RtPosixMutex(const RtPosixMutex&) = delete;
+ RtPosixMutex& operator=(const RtPosixMutex&) = delete;
+ RtPosixMutex(RtPosixMutex&&) = delete;
+ RtPosixMutex& operator=(RtPosixMutex&&) = delete;
-// The SetThreadDescription API was brought in version 1607 of Windows 10.
-typedef HRESULT(WINAPI* GetThreadDescription)(HANDLE hThread,
- PWSTR* ppszThreadDescription);
+ bool try_lock() noexcept PERFETTO_EXCLUSIVE_TRYLOCK_FUNCTION(true);
+ void lock() noexcept PERFETTO_EXCLUSIVE_LOCK_FUNCTION();
+ void unlock() noexcept PERFETTO_UNLOCK_FUNCTION();
-bool MaybeSetThreadName(const std::string& name) {
- // The SetThreadDescription API works even if no debugger is attached.
- static auto set_thread_description_func =
- reinterpret_cast<SetThreadDescription>(
- reinterpret_cast<void*>(::GetProcAddress(
- ::GetModuleHandleA("Kernel32.dll"), "SetThreadDescription")));
- if (!set_thread_description_func) {
- return false;
- }
- std::wstring wide_thread_name;
- if (!UTF8ToWide(name, wide_thread_name)) {
- return false;
- }
- HRESULT result = set_thread_description_func(::GetCurrentThread(),
- wide_thread_name.c_str());
- return !FAILED(result);
-}
+ private:
+ pthread_mutex_t mutex_;
+};
-bool GetThreadName(std::string& out_result) {
- static auto get_thread_description_func =
- reinterpret_cast<GetThreadDescription>(
- reinterpret_cast<void*>(::GetProcAddress(
- ::GetModuleHandleA("Kernel32.dll"), "GetThreadDescription")));
- if (!get_thread_description_func) {
- return false;
- }
- wchar_t* wide_thread_name;
- HRESULT result =
- get_thread_description_func(::GetCurrentThread(), &wide_thread_name);
- if (SUCCEEDED(result)) {
- bool success = WideToUTF8(std::wstring(wide_thread_name), out_result);
- LocalFree(wide_thread_name);
- return success;
- }
- return false;
-}
+#endif // PERFETTO_HAS_POSIX_RT_MUTEX
+} // namespace internal
-#endif // PERFETTO_BUILDFLAG(PERFETTO_OS_FUCHSIA)
+// Select the best real-time mutex implementation for the target platform, or
+// fall back to std::mutex if none is available.
+#if PERFETTO_HAS_RT_FUTEX()
+using MaybeRtMutex = internal::RtFutex;
+#elif PERFETTO_HAS_POSIX_RT_MUTEX()
+using MaybeRtMutex = internal::RtPosixMutex;
+#else
+using MaybeRtMutex = std::mutex;
+#endif
-} // namespace base
-} // namespace perfetto
-// gen_amalgamated begin source: src/base/time.cc
+} // namespace perfetto::base
+
+#endif // INCLUDE_PERFETTO_EXT_BASE_RT_MUTEX_H_
/*
* Copyright (C) 2018 The Android Open Source Project
*
@@ -9832,209 +10371,94 @@ bool GetThreadName(std::string& out_result) {
* limitations under the License.
*/
-#include <atomic>
+// gen_amalgamated expanded: #include "perfetto/ext/base/rt_mutex.h"
-// gen_amalgamated expanded: #include "perfetto/base/time.h"
+#include <errno.h>
-// gen_amalgamated expanded: #include "perfetto/base/build_config.h"
// gen_amalgamated expanded: #include "perfetto/base/logging.h"
-// gen_amalgamated expanded: #include "perfetto/ext/base/string_utils.h"
+// gen_amalgamated expanded: #include "perfetto/ext/base/utils.h"
-#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
-#include <windows.h>
-#else
+#if PERFETTO_HAS_RT_FUTEX()
+#include <linux/futex.h>
+#include <sys/syscall.h>
#include <unistd.h>
#endif
-namespace perfetto {
-namespace base {
-
-#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
-#if !PERFETTO_BUILDFLAG(PERFETTO_ARCH_CPU_ARM64)
-namespace {
-
-// Returns the current value of the performance counter.
-int64_t QPCNowRaw() {
- LARGE_INTEGER perf_counter_now = {};
- // According to the MSDN documentation for QueryPerformanceCounter(), this
- // will never fail on systems that run XP or later.
- // https://msdn.microsoft.com/library/windows/desktop/ms644904.aspx
- ::QueryPerformanceCounter(&perf_counter_now);
- return perf_counter_now.QuadPart;
-}
-
-double TSCTicksPerSecond() {
- // The value returned by QueryPerformanceFrequency() cannot be used as the TSC
- // frequency, because there is no guarantee that the TSC frequency is equal to
- // the performance counter frequency.
- // The TSC frequency is cached in a static variable because it takes some time
- // to compute it.
- static std::atomic<double> tsc_ticks_per_second = 0;
- double value = tsc_ticks_per_second.load(std::memory_order_relaxed);
- if (value != 0)
- return value;
-
- // Increase the thread priority to reduces the chances of having a context
- // switch during a reading of the TSC and the performance counter.
- const int previous_priority = ::GetThreadPriority(::GetCurrentThread());
- ::SetThreadPriority(::GetCurrentThread(), THREAD_PRIORITY_HIGHEST);
-
- // The first time that this function is called, make an initial reading of the
- // TSC and the performance counter. Initialization of static variable is
- // thread-safe. Threads can race initializing tsc_initial vs
- // perf_counter_initial, although they should be storing very similar values.
-
- static const uint64_t tsc_initial = __rdtsc();
- static const int64_t perf_counter_initial = QPCNowRaw();
-
- // Make a another reading of the TSC and the performance counter every time
- // that this function is called.
- const uint64_t tsc_now = __rdtsc();
- const int64_t perf_counter_now = QPCNowRaw();
-
- // Reset the thread priority.
- ::SetThreadPriority(::GetCurrentThread(), previous_priority);
-
- // Make sure that at least 50 ms elapsed between the 2 readings. The first
- // time that this function is called, we don't expect this to be the case.
- // Note: The longer the elapsed time between the 2 readings is, the more
- // accurate the computed TSC frequency will be. The 50 ms value was
- // chosen because local benchmarks show that it allows us to get a
- // stddev of less than 1 tick/us between multiple runs.
- // Note: According to the MSDN documentation for QueryPerformanceFrequency(),
- // this will never fail on systems that run XP or later.
- // https://msdn.microsoft.com/library/windows/desktop/ms644905.aspx
- LARGE_INTEGER perf_counter_frequency = {};
- ::QueryPerformanceFrequency(&perf_counter_frequency);
- PERFETTO_CHECK(perf_counter_now >= perf_counter_initial);
- const int64_t perf_counter_ticks = perf_counter_now - perf_counter_initial;
- const double elapsed_time_seconds =
- static_cast<double>(perf_counter_ticks) /
- static_cast<double>(perf_counter_frequency.QuadPart);
+namespace perfetto::base {
- constexpr double kMinimumEvaluationPeriodSeconds = 0.05;
- if (elapsed_time_seconds < kMinimumEvaluationPeriodSeconds)
- return 0;
+namespace internal {
- // Compute the frequency of the TSC.
- PERFETTO_CHECK(tsc_now >= tsc_initial);
- const uint64_t tsc_ticks = tsc_now - tsc_initial;
- // Racing with another thread to write |tsc_ticks_per_second| is benign
- // because both threads will write a valid result.
- tsc_ticks_per_second.store(
- static_cast<double>(tsc_ticks) / elapsed_time_seconds,
- std::memory_order_relaxed);
+#if PERFETTO_HAS_RT_FUTEX()
- return tsc_ticks_per_second.load(std::memory_order_relaxed);
+void RtFutex::LockSlowpath() {
+ auto res = PERFETTO_EINTR(
+ syscall(SYS_futex, &lock_, FUTEX_LOCK_PI_PRIVATE, 0, nullptr));
+ PERFETTO_CHECK(res == 0);
}
-} // namespace
-#endif // !PERFETTO_BUILDFLAG(PERFETTO_ARCH_CPU_ARM64)
-
-TimeNanos GetWallTimeNs() {
- LARGE_INTEGER freq;
- ::QueryPerformanceFrequency(&freq);
- LARGE_INTEGER counter;
- ::QueryPerformanceCounter(&counter);
- double elapsed_nanoseconds = (1e9 * static_cast<double>(counter.QuadPart)) /
- static_cast<double>(freq.QuadPart);
- return TimeNanos(static_cast<uint64_t>(elapsed_nanoseconds));
+bool RtFutex::TryLockSlowpath() {
+ auto res = PERFETTO_EINTR(
+ syscall(SYS_futex, &lock_, FUTEX_TRYLOCK_PI_PRIVATE, 0, nullptr));
+ if (res == 0)
+ return true;
+ if (errno == EBUSY || errno == EDEADLK)
+ return false;
+ PERFETTO_FATAL("FUTEX_TRYLOCK_PI_PRIVATE failed");
}
-TimeNanos GetThreadCPUTimeNs() {
-#if PERFETTO_BUILDFLAG(PERFETTO_ARCH_CPU_ARM64)
- // QueryThreadCycleTime versus TSCTicksPerSecond doesn't have much relation to
- // actual elapsed time on Windows on Arm, because QueryThreadCycleTime is
- // backed by the actual number of CPU cycles executed, rather than a
- // constant-rate timer like Intel. To work around this, use GetThreadTimes
- // (which isn't as accurate but is meaningful as a measure of elapsed
- // per-thread time).
- FILETIME dummy, kernel_ftime, user_ftime;
- ::GetThreadTimes(GetCurrentThread(), &dummy, &dummy, &kernel_ftime,
- &user_ftime);
- uint64_t kernel_time =
- kernel_ftime.dwHighDateTime * 0x100000000 + kernel_ftime.dwLowDateTime;
- uint64_t user_time =
- user_ftime.dwHighDateTime * 0x100000000 + user_ftime.dwLowDateTime;
+void RtFutex::UnlockSlowpath() {
+ auto res = PERFETTO_EINTR(
+ syscall(SYS_futex, &lock_, FUTEX_UNLOCK_PI_PRIVATE, 0, nullptr));
+ PERFETTO_CHECK(res == 0);
+}
- return TimeNanos((kernel_time + user_time) * 100);
-#else // !PERFETTO_BUILDFLAG(PERFETTO_ARCH_CPU_ARM64)
- // Get the number of TSC ticks used by the current thread.
- ULONG64 thread_cycle_time = 0;
- ::QueryThreadCycleTime(GetCurrentThread(), &thread_cycle_time);
+#endif // PERFETTO_HAS_RT_FUTEX
- // Get the frequency of the TSC.
- const double tsc_ticks_per_second = TSCTicksPerSecond();
- if (tsc_ticks_per_second == 0)
- return TimeNanos();
+#if PERFETTO_HAS_POSIX_RT_MUTEX()
- // Return the CPU time of the current thread.
- const double thread_time_seconds =
- static_cast<double>(thread_cycle_time) / tsc_ticks_per_second;
- constexpr int64_t kNanosecondsPerSecond = 1000 * 1000 * 1000;
- return TimeNanos(
- static_cast<int64_t>(thread_time_seconds * kNanosecondsPerSecond));
-#endif // !PERFETTO_BUILDFLAG(PERFETTO_ARCH_CPU_ARM64)
+RtPosixMutex::RtPosixMutex() noexcept {
+#if PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID) && __ANDROID_API__ < 28
+ // pthread_mutexattr_setprotocol is only available on API 28.
+#error \
+ "Priority-inheritance RtMutex is not available in this version of Android."
+#endif
+ pthread_mutexattr_t at{};
+ PERFETTO_CHECK(pthread_mutexattr_init(&at) == 0);
+ PERFETTO_CHECK(pthread_mutexattr_setprotocol(&at, PTHREAD_PRIO_INHERIT) == 0);
+ PERFETTO_CHECK(pthread_mutex_init(&mutex_, &at) == 0);
}
-void SleepMicroseconds(unsigned interval_us) {
- // The Windows Sleep function takes a millisecond count. Round up so that
- // short sleeps don't turn into a busy wait. Note that the sleep granularity
- // on Windows can dynamically vary from 1 ms to ~16 ms, so don't count on this
- // being a short sleep.
- ::Sleep(static_cast<DWORD>((interval_us + 999) / 1000));
+RtPosixMutex::~RtPosixMutex() noexcept {
+ pthread_mutex_destroy(&mutex_);
}
-void InitializeTime() {
-#if !PERFETTO_BUILDFLAG(PERFETTO_ARCH_CPU_ARM64)
- // Make an early first call to TSCTicksPerSecond() to start 50 ms elapsed time
- // (see comment in TSCTicksPerSecond()).
- TSCTicksPerSecond();
-#endif // !PERFETTO_BUILDFLAG(PERFETTO_ARCH_CPU_ARM64)
+bool RtPosixMutex::try_lock() noexcept {
+ int res = pthread_mutex_trylock(&mutex_);
+ if (res == 0)
+ return true;
+ // NOTE: Unlike most Linux APIs, pthread_mutex_trylock "returns" the error
+ // code, it does NOT use errno.
+ if (res == EBUSY)
+ return false;
+ PERFETTO_FATAL("pthread_mutex_trylock() failed");
}
-#else // PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
-
-void SleepMicroseconds(unsigned interval_us) {
- ::usleep(static_cast<useconds_t>(interval_us));
+void RtPosixMutex::lock() noexcept {
+ PERFETTO_CHECK(pthread_mutex_lock(&mutex_) == 0);
}
-void InitializeTime() {}
-
-#endif // PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
-
-std::string GetTimeFmt(const std::string& fmt) {
- time_t raw_time;
- time(&raw_time);
- struct tm local_tm;
-#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
- PERFETTO_CHECK(localtime_s(&local_tm, &raw_time) == 0);
-#else
- tzset();
- PERFETTO_CHECK(localtime_r(&raw_time, &local_tm) != nullptr);
-#endif
- char buf[128];
- PERFETTO_CHECK(strftime(buf, 80, fmt.c_str(), &local_tm) > 0);
- return buf;
+void RtPosixMutex::unlock() noexcept {
+ PERFETTO_CHECK(pthread_mutex_unlock(&mutex_) == 0);
}
-std::optional<int32_t> GetTimezoneOffsetMins() {
- std::string tz = GetTimeFmt("%z");
- if (tz.size() != 5 || (tz[0] != '+' && tz[0] != '-'))
- return std::nullopt;
- char sign = '\0';
- int32_t hh = 0;
- int32_t mm = 0;
- if (sscanf(tz.c_str(), "%c%2d%2d", &sign, &hh, &mm) != 3)
- return std::nullopt;
- return (hh * 60 + mm) * (sign == '-' ? -1 : 1);
-}
+#endif // PERFETTO_HAS_POSIX_RT_MUTEX
-} // namespace base
-} // namespace perfetto
-// gen_amalgamated begin source: src/base/utils.cc
+} // namespace internal
+} // namespace perfetto::base
+// gen_amalgamated begin source: src/base/scoped_mmap.cc
+// gen_amalgamated begin header: include/perfetto/ext/base/scoped_mmap.h
/*
- * Copyright (C) 2020 The Android Open Source Project
+ * Copyright (C) 2024 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.
@@ -10049,354 +10473,263 @@ std::optional<int32_t> GetTimezoneOffsetMins() {
* limitations under the License.
*/
-// gen_amalgamated expanded: #include "perfetto/ext/base/utils.h"
+#ifndef INCLUDE_PERFETTO_EXT_BASE_SCOPED_MMAP_H_
+#define INCLUDE_PERFETTO_EXT_BASE_SCOPED_MMAP_H_
-#include <string>
+#include <cstddef>
// gen_amalgamated expanded: #include "perfetto/base/build_config.h"
-// gen_amalgamated expanded: #include "perfetto/base/logging.h"
-// gen_amalgamated expanded: #include "perfetto/ext/base/file_utils.h"
-// gen_amalgamated expanded: #include "perfetto/ext/base/pipe.h"
-// gen_amalgamated expanded: #include "perfetto/ext/base/string_utils.h"
+// gen_amalgamated expanded: #include "perfetto/ext/base/scoped_file.h"
#if PERFETTO_BUILDFLAG(PERFETTO_OS_LINUX) || \
- PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID) || \
PERFETTO_BUILDFLAG(PERFETTO_OS_APPLE) || \
PERFETTO_BUILDFLAG(PERFETTO_OS_FREEBSD) || \
- PERFETTO_BUILDFLAG(PERFETTO_OS_FUCHSIA)
-#include <limits.h>
-#include <stdlib.h> // For _exit()
-#endif
-
-#if !PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
-// For isatty(), getpagesize(), geteuid(), fork() & sysconf().
-#include <unistd.h>
+ PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID) || \
+ PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
+#define PERFETTO_HAS_MMAP() 1
+#else
+#define PERFETTO_HAS_MMAP() 0
#endif
-#if PERFETTO_BUILDFLAG(PERFETTO_OS_APPLE)
-#include <mach-o/dyld.h>
-#include <mach/vm_page_size.h>
-#endif
+namespace perfetto::base {
-#if PERFETTO_BUILDFLAG(PERFETTO_OS_FREEBSD)
-#include <sys/sysctl.h>
-#endif
+// RAII wrapper that holds ownership of an mmap()d area and of a file. Calls
+// unmap() and close() on destruction.
+class ScopedMmap {
+ public:
+ // Creates a memory mapping for the first `length` bytes of `file`.
+ static ScopedMmap FromHandle(base::ScopedPlatformHandle file, size_t length);
-#if PERFETTO_BUILDFLAG(PERFETTO_OS_LINUX_BUT_NOT_QNX) || \
- PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID)
-#include <sys/prctl.h>
+ ScopedMmap() {}
+ ~ScopedMmap();
+ ScopedMmap(ScopedMmap&& other) noexcept;
-#ifndef PR_GET_TAGGED_ADDR_CTRL
-#define PR_GET_TAGGED_ADDR_CTRL 56
-#endif
+ ScopedMmap& operator=(ScopedMmap&& other) noexcept;
-#ifndef PR_TAGGED_ADDR_ENABLE
-#define PR_TAGGED_ADDR_ENABLE (1UL << 0)
-#endif
+ // Returns a pointer to the mapped memory area. Only valid if `IsValid()` is
+ // true.
+ void* data() const { return ptr_; }
-#ifndef PR_MTE_TCF_SYNC
-#define PR_MTE_TCF_SYNC (1UL << 1)
-#endif
+ // Returns true if this object contains a successfully mapped area.
+ bool IsValid() const { return ptr_ != nullptr; }
-#endif // OS_LINUX | OS_ANDROID
+ // Returns the length of the mapped area.
+ size_t length() const { return length_; }
-#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
-#include <windows.h>
+ // Unmaps the area and closes the file. Returns false if this held a mmap()d
+ // area and unmapping failed. In any case, after this method, `IsValid()` will
+ // return false.
+ bool reset() noexcept;
-#include <io.h>
-#include <malloc.h> // For _aligned_malloc().
+#if PERFETTO_BUILDFLAG(PERFETTO_OS_LINUX) || \
+ PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID) || \
+ PERFETTO_BUILDFLAG(PERFETTO_OS_FREEBSD) || \
+ PERFETTO_BUILDFLAG(PERFETTO_OS_APPLE)
+ // Takes ownership of an mmap()d area that starts at `data`, `size` bytes
+ // long. `data` should not be MAP_FAILED.
+ static ScopedMmap InheritMmappedRange(void* data, size_t size);
#endif
-#if PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID)
-#include <dlfcn.h>
-#include <malloc.h>
-
-#ifdef M_PURGE
-#define PERFETTO_M_PURGE M_PURGE
-#else
-// Only available in in-tree builds and on newer SDKs.
-#define PERFETTO_M_PURGE -101
-#endif // M_PURGE
-
-#ifdef M_PURGE_ALL
-#define PERFETTO_M_PURGE_ALL M_PURGE_ALL
-#else
-// Only available in in-tree builds and on newer SDKs.
-#define PERFETTO_M_PURGE_ALL -104
-#endif // M_PURGE
+ private:
+ ScopedMmap(const ScopedMmap&) = delete;
+ ScopedMmap& operator=(const ScopedMmap&) = delete;
-namespace {
-extern "C" {
-using MalloptType = int (*)(int, int);
-}
-} // namespace
-#endif // OS_ANDROID
+ size_t length_ = 0;
+ void* ptr_ = nullptr;
+ ScopedPlatformHandle file_;
+#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
+ ScopedPlatformHandle map_;
+#endif
+};
-namespace perfetto {
-namespace base {
+// Tries to open `file_path` and maps its first `length` bytes in memory.
+ScopedMmap ReadMmapFilePart(const std::string& file_path, size_t length);
-namespace internal {
+// Tries to open `file_path` and maps the whole file into memory.
+ScopedMmap ReadMmapWholeFile(const std::string& file_path);
-std::atomic<uint32_t> g_cached_page_size{0};
+} // namespace perfetto::base
-uint32_t GetSysPageSizeSlowpath() {
- uint32_t page_size = 0;
-#if PERFETTO_BUILDFLAG(PERFETTO_OS_LINUX) || \
- PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID)
- const int page_size_int = getpagesize();
- // If sysconf() fails for obscure reasons (e.g. SELinux denial) assume the
- // page size is 4KB. This is to avoid regressing subtle SDK usages, as old
- // versions of this code had a static constant baked in.
- page_size = static_cast<uint32_t>(page_size_int > 0 ? page_size_int : 4096);
-#elif PERFETTO_BUILDFLAG(PERFETTO_OS_APPLE)
- page_size = static_cast<uint32_t>(vm_page_size);
-#elif PERFETTO_BUILDFLAG(PERFETTO_OS_FREEBSD)
- page_size = static_cast<uint32_t>(sysconf(_SC_PAGESIZE));
-#else
- page_size = 4096;
-#endif
+#endif // INCLUDE_PERFETTO_EXT_BASE_SCOPED_MMAP_H_
+/*
+ * Copyright (C) 2024 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.
+ */
- PERFETTO_CHECK(page_size > 0 && page_size % 4096 == 0);
+// gen_amalgamated expanded: #include "perfetto/ext/base/scoped_mmap.h"
- // Races here are fine because any thread will write the same value.
- g_cached_page_size.store(page_size, std::memory_order_relaxed);
- return page_size;
-}
+#include <utility>
-} // namespace internal
+// gen_amalgamated expanded: #include "perfetto/ext/base/file_utils.h"
+// gen_amalgamated expanded: #include "perfetto/ext/base/scoped_file.h"
-void MaybeReleaseAllocatorMemToOS() {
-#if PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID)
- // mallopt() on Android requires SDK level 26. Many targets and embedders
- // still depend on a lower SDK level. Given mallopt() is a quite simple API,
- // use reflection to do this rather than bumping the SDK level for all
- // embedders. This keeps the behavior of standalone builds aligned with
- // in-tree builds.
- static MalloptType mallopt_fn =
- reinterpret_cast<MalloptType>(dlsym(RTLD_DEFAULT, "mallopt"));
- if (!mallopt_fn)
- return;
- if (mallopt_fn(PERFETTO_M_PURGE_ALL, 0) == 0) {
- mallopt_fn(PERFETTO_M_PURGE, 0);
- }
+#if PERFETTO_BUILDFLAG(PERFETTO_OS_LINUX) || \
+ PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID) || \
+ PERFETTO_BUILDFLAG(PERFETTO_OS_FREEBSD) || \
+ PERFETTO_BUILDFLAG(PERFETTO_OS_APPLE)
+#include <sys/mman.h>
+#include <unistd.h>
+#elif PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
+#include <windows.h>
#endif
-}
-uid_t GetCurrentUserId() {
+namespace perfetto::base {
+namespace {
+
+ScopedPlatformHandle OpenFileForMmap(const std::string& file_path) {
#if PERFETTO_BUILDFLAG(PERFETTO_OS_LINUX) || \
PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID) || \
PERFETTO_BUILDFLAG(PERFETTO_OS_FREEBSD) || \
PERFETTO_BUILDFLAG(PERFETTO_OS_APPLE)
- return geteuid();
+ return OpenFile(file_path, O_RDONLY);
+#elif PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
+ // This does not use base::OpenFile to avoid getting an exclusive lock.
+ //
+ // The share flags mirror the POSIX open(O_RDONLY) above, which has no notion
+ // of share modes. Same flags as LLVM's openNativeFileInternal():
+ // https://github.com/llvm/llvm-project/blob/main/llvm/lib/Support/Windows/Path.inc
+ return ScopedPlatformHandle(
+ CreateFileA(file_path.c_str(), GENERIC_READ,
+ FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
+ nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr));
#else
- // TODO(primiano): On Windows we could hash the current user SID and derive a
- // numeric user id [1]. It is not clear whether we need that. Right now that
- // would not bring any benefit. Returning 0 unil we can prove we need it.
- // [1]:https://android-review.googlesource.com/c/platform/external/perfetto/+/1513879/25/src/base/utils.cc
- return 0;
+ // mmap is not supported. Do not even open the file.
+ base::ignore_result(file_path);
+ return ScopedPlatformHandle();
#endif
}
-void SetEnv(const std::string& key, const std::string& value) {
-#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
- PERFETTO_CHECK(::_putenv_s(key.c_str(), value.c_str()) == 0);
-#else
- PERFETTO_CHECK(::setenv(key.c_str(), value.c_str(), /*overwrite=*/true) == 0);
-#endif
-}
+} // namespace
-void UnsetEnv(const std::string& key) {
-#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
- PERFETTO_CHECK(::_putenv_s(key.c_str(), "") == 0);
-#else
- PERFETTO_CHECK(::unsetenv(key.c_str()) == 0);
-#endif
+ScopedMmap::ScopedMmap(ScopedMmap&& other) noexcept {
+ *this = std::move(other);
}
-bool IsTty(int fd) {
+ScopedMmap& ScopedMmap::operator=(ScopedMmap&& other) noexcept {
+ if (this == &other) {
+ return *this;
+ }
+ reset();
+ std::swap(ptr_, other.ptr_);
+ std::swap(length_, other.length_);
+ std::swap(file_, other.file_);
#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
- return ::_isatty(fd) != 0;
-#else
- return ::isatty(fd) != 0;
+ std::swap(map_, other.map_);
#endif
+ return *this;
}
-bool IsTty(FILE* stream) {
-#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
- return IsTty(::_fileno(stream));
-#else
- return IsTty(::fileno(stream));
-#endif
+ScopedMmap::~ScopedMmap() {
+ reset();
}
-void Daemonize(std::function<int(pid_t)> parent_cb) {
+// static
+ScopedMmap ScopedMmap::FromHandle(base::ScopedPlatformHandle file,
+ size_t length) {
+ ScopedMmap ret;
+ if (!file) {
+ return ret;
+ }
#if PERFETTO_BUILDFLAG(PERFETTO_OS_LINUX) || \
PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID) || \
PERFETTO_BUILDFLAG(PERFETTO_OS_FREEBSD) || \
- (PERFETTO_BUILDFLAG(PERFETTO_OS_APPLE) && \
- !PERFETTO_BUILDFLAG(PERFETTO_OS_APPLE_TVOS))
- Pipe pipe = Pipe::Create(Pipe::kBothBlock);
- pid_t pid;
- switch (pid = fork()) {
- case -1:
- PERFETTO_FATAL("fork");
- case 0: {
- PERFETTO_CHECK(setsid() != -1);
- base::ignore_result(chdir("/"));
- base::ScopedFile null = base::OpenFile("/dev/null", O_RDONLY);
- PERFETTO_CHECK(null);
- PERFETTO_CHECK(dup2(*null, STDIN_FILENO) != -1);
- PERFETTO_CHECK(dup2(*null, STDOUT_FILENO) != -1);
- PERFETTO_CHECK(dup2(*null, STDERR_FILENO) != -1);
- // Do not accidentally close stdin/stdout/stderr.
- if (*null <= 2)
- null.release();
- WriteAll(*pipe.wr, "1", 1);
- break;
- }
- default: {
- // Wait for the child process to have reached the setsid() call. This is
- // to avoid that 'adb shell perfetto -D' destroys the terminal (hence
- // sending a SIGHUP to the child) before the child has detached from the
- // terminal (see b/238644870).
-
- // This is to unblock the read() below (with EOF, which will fail the
- // CHECK) in the unlikely case of the child crashing before WriteAll("1").
- pipe.wr.reset();
- char one = '\0';
- PERFETTO_CHECK(Read(*pipe.rd, &one, sizeof(one)) == 1 && one == '1');
- int err = parent_cb(pid);
- exit(err);
- }
+ PERFETTO_BUILDFLAG(PERFETTO_OS_APPLE)
+ void* ptr = mmap(nullptr, length, PROT_READ, MAP_PRIVATE, *file, 0);
+ if (ptr != MAP_FAILED) {
+ ret.ptr_ = ptr;
+ ret.length_ = length;
+ ret.file_ = std::move(file);
+ }
+#elif PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
+ ScopedPlatformHandle map(
+ CreateFileMapping(*file, nullptr, PAGE_READONLY, 0, 0, nullptr));
+ if (!map) {
+ return ret;
+ }
+ void* ptr = MapViewOfFile(*map, FILE_MAP_READ, 0, 0, length);
+ if (ptr != nullptr) {
+ ret.ptr_ = ptr;
+ ret.length_ = length;
+ ret.file_ = std::move(file);
+ ret.map_ = std::move(map);
}
#else
- // Avoid -Wunreachable warnings.
- if (reinterpret_cast<intptr_t>(&Daemonize) != 16)
- PERFETTO_FATAL("--background is only supported on Linux/Android/Mac");
- ignore_result(parent_cb);
-#endif // OS_WIN
+ base::ignore_result(length);
+#endif
+ return ret;
}
-std::string GetCurExecutablePath() {
- std::string self_path;
+bool ScopedMmap::reset() noexcept {
+ bool ret = true;
#if PERFETTO_BUILDFLAG(PERFETTO_OS_LINUX) || \
PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID) || \
- PERFETTO_BUILDFLAG(PERFETTO_OS_FUCHSIA)
- char buf[PATH_MAX];
- ssize_t size = readlink("/proc/self/exe", buf, sizeof(buf));
- PERFETTO_CHECK(size != -1);
- // readlink does not null terminate.
- self_path = std::string(buf, static_cast<size_t>(size));
-#elif PERFETTO_BUILDFLAG(PERFETTO_OS_APPLE)
- uint32_t size = 0;
- PERFETTO_CHECK(_NSGetExecutablePath(nullptr, &size));
- self_path.resize(size);
- PERFETTO_CHECK(_NSGetExecutablePath(&self_path[0], &size) == 0);
+ PERFETTO_BUILDFLAG(PERFETTO_OS_FREEBSD) || \
+ PERFETTO_BUILDFLAG(PERFETTO_OS_APPLE)
+ if (ptr_ != nullptr) {
+ ret = munmap(ptr_, length_) == 0;
+ }
#elif PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
- char buf[MAX_PATH];
- auto len = ::GetModuleFileNameA(nullptr /*current*/, buf, sizeof(buf));
- self_path = std::string(buf, len);
-#elif PERFETTO_BUILDFLAG(PERFETTO_OS_FREEBSD)
- char buf[PATH_MAX];
- int mib[4], ret;
- size_t len = sizeof(buf);
- mib[0] = CTL_KERN;
- mib[1] = KERN_PROC;
- mib[2] = KERN_PROC_PATHNAME;
- mib[3] = -1;
- ret = sysctl(mib, 4, buf, &len, NULL, 0);
- PERFETTO_CHECK(ret == 0);
- // This returns the full path; need to trim the executable
- self_path = std::string(buf);
-#else
- PERFETTO_FATAL(
- "GetCurExecutableDir() not implemented on the current platform");
-#endif
- return self_path;
-}
-
-std::string GetCurExecutableDir() {
- auto path = GetCurExecutablePath();
-#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
- // Paths in Windows can have both kinds of slashes (mingw vs msvc).
- path = path.substr(0, path.find_last_of('\\'));
+ if (ptr_ != nullptr) {
+ ret = UnmapViewOfFile(ptr_);
+ }
+ map_.reset();
#endif
- path = path.substr(0, path.find_last_of('/'));
- return path;
+ ptr_ = nullptr;
+ length_ = 0;
+ file_.reset();
+ return ret;
}
-void* AlignedAlloc(size_t alignment, size_t size) {
- void* res = nullptr;
- alignment = AlignUp<sizeof(void*)>(alignment); // At least pointer size.
-#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
- // Window's _aligned_malloc() has a nearly identically signature to Unix's
- // aligned_alloc() but its arguments are obviously swapped.
- res = _aligned_malloc(size, alignment);
-#else
- // aligned_alloc() has been introduced in Android only in API 28.
- // Also NaCl and Fuchsia seems to have only posix_memalign().
- ignore_result(posix_memalign(&res, alignment, size));
-#endif
- PERFETTO_CHECK(res);
- return res;
+#if PERFETTO_BUILDFLAG(PERFETTO_OS_LINUX) || \
+ PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID) || \
+ PERFETTO_BUILDFLAG(PERFETTO_OS_FREEBSD) || \
+ PERFETTO_BUILDFLAG(PERFETTO_OS_APPLE)
+// static
+ScopedMmap ScopedMmap::InheritMmappedRange(void* data, size_t size) {
+ ScopedMmap ret;
+ ret.ptr_ = data;
+ ret.length_ = size;
+ return ret;
}
-
-void AlignedFree(void* ptr) {
-#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
- _aligned_free(ptr); // MSDN says it is fine to pass nullptr.
-#else
- free(ptr);
#endif
-}
-bool IsSyncMemoryTaggingEnabled() {
-#if PERFETTO_BUILDFLAG(PERFETTO_OS_LINUX_BUT_NOT_QNX) || \
- PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID)
- // Compute only once per lifetime of the process.
- static bool cached_value = [] {
- const int res = prctl(PR_GET_TAGGED_ADDR_CTRL, 0, 0, 0, 0);
- if (res < 0)
- return false;
- const uint32_t actl = static_cast<uint32_t>(res);
- return (actl & PR_TAGGED_ADDR_ENABLE) && (actl & PR_MTE_TCF_SYNC);
- }();
- return cached_value;
-#else
- return false;
-#endif
+ScopedMmap ReadMmapFilePart(const std::string& fname, size_t length) {
+ return ScopedMmap::FromHandle(OpenFileForMmap(fname), length);
}
-std::string HexDump(const void* data_void, size_t len, size_t bytes_per_line) {
- const char* data = reinterpret_cast<const char*>(data_void);
- std::string res;
- static const size_t kPadding = bytes_per_line * 3 + 12;
- std::unique_ptr<char[]> line(new char[bytes_per_line * 4 + 128]);
- for (size_t i = 0; i < len; i += bytes_per_line) {
- char* wptr = line.get();
- wptr += base::SprintfTrunc(wptr, 19, "%08zX: ", i);
- for (size_t j = i; j < i + bytes_per_line && j < len; j++) {
- wptr += base::SprintfTrunc(wptr, 4, "%02X ",
- static_cast<unsigned>(data[j]) & 0xFF);
- }
- for (size_t j = static_cast<size_t>(wptr - line.get()); j < kPadding; ++j)
- *(wptr++) = ' ';
- for (size_t j = i; j < i + bytes_per_line && j < len; j++) {
- char c = data[j];
- *(wptr++) = (c >= 32 && c < 127) ? c : '.';
- }
- *(wptr++) = '\n';
- *(wptr++) = '\0';
- res.append(line.get());
+ScopedMmap ReadMmapWholeFile(const std::string& fname) {
+ ScopedPlatformHandle file = OpenFileForMmap(fname);
+ if (!file) {
+ return ScopedMmap();
}
- return res;
+ std::optional<uint64_t> file_size = GetFileSize(file.get());
+ if (!file_size.has_value()) {
+ return ScopedMmap();
+ }
+ size_t size = static_cast<size_t>(*file_size);
+ if (static_cast<uint64_t>(size) != *file_size) {
+ return ScopedMmap();
+ }
+ return ScopedMmap::FromHandle(std::move(file), size);
}
-} // namespace base
-} // namespace perfetto
-// gen_amalgamated begin source: src/base/uuid.cc
-// gen_amalgamated begin header: include/perfetto/ext/base/uuid.h
+} // namespace perfetto::base
+// gen_amalgamated begin source: src/base/scoped_sched_boost.cc
+// gen_amalgamated begin header: include/perfetto/ext/base/scoped_sched_boost.h
+// gen_amalgamated begin header: include/perfetto/ext/base/status_or.h
/*
- * Copyright (C) 2019 The Android Open Source Project
+ * 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.
@@ -10411,68 +10744,94 @@ std::string HexDump(const void* data_void, size_t len, size_t bytes_per_line) {
* limitations under the License.
*/
-#ifndef INCLUDE_PERFETTO_EXT_BASE_UUID_H_
-#define INCLUDE_PERFETTO_EXT_BASE_UUID_H_
+#ifndef INCLUDE_PERFETTO_EXT_BASE_STATUS_OR_H_
+#define INCLUDE_PERFETTO_EXT_BASE_STATUS_OR_H_
-#include <string.h>
-#include <array>
-#include <cstdint>
-#include <string>
+#include <optional>
+#include <utility>
-// gen_amalgamated expanded: #include "perfetto/base/export.h"
+// gen_amalgamated expanded: #include "perfetto/base/status.h"
namespace perfetto {
namespace base {
-class PERFETTO_EXPORT_COMPONENT Uuid {
+// Union of a object of type |T| with a |base::Status|. Useful for cases where
+// a |T| indicates a successful result of an operation and |base::Status|
+// represents an error.
+//
+// This class is modelled closely on absl::Status and should essentially 1:1
+// match it's API.
+template <typename T>
+class StatusOr {
public:
- explicit Uuid(const std::string& s);
- explicit Uuid(int64_t lsb, int64_t msb);
- Uuid();
-
- std::array<uint8_t, 16>* data() { return &data_; }
- const std::array<uint8_t, 16>* data() const { return &data_; }
-
- bool operator==(const Uuid& other) const { return data_ == other.data_; }
+ // Matches naming of declarations in similar types e.g. std::optional,
+ // std::variant.
+ using value_type = T;
- bool operator!=(const Uuid& other) const { return !(*this == other); }
+ // Intentionally implicit to allow idomatic usage (e.g. returning value/status
+ // from base::StatusOr returning function).
+ StatusOr(base::Status status) : StatusOr(std::move(status), std::nullopt) {
+ if (status_.ok()) {
+ // Matches what Abseil's approach towards OkStatus being passed to
+ // absl::StatusOr<T>.
+ PERFETTO_FATAL("base::OkStatus passed to StatusOr: this is not allowed");
+ }
+ }
+ StatusOr(T value) : StatusOr(base::OkStatus(), std::move(value)) {}
- explicit operator bool() const { return *this != Uuid(); }
+ bool ok() const { return status_.ok(); }
+ const base::Status& status() const { return status_; }
- int64_t msb() const {
- int64_t result;
- memcpy(&result, data_.data() + 8, 8);
- return result;
+ // For an lvalue caller, if ok(), returns a reference to the value, so the
+ // StatusOr keeps owning it.
+ // If not, we log the error message and abort.
+ T& ValueOrDie() & {
+ if (!ok())
+ PERFETTO_FATAL("%s", status_.c_message());
+ return *value_;
}
- int64_t lsb() const {
- int64_t result;
- memcpy(&result, data_.data(), 8);
- return result;
+ // For an rvalue caller, if ok(), moves the value out because the StatusOr
+ // won't be used again.
+ // If not, we log the error message and abort.
+ T ValueOrDie() && {
+ if (!ok())
+ PERFETTO_FATAL("%s", status_.c_message());
+ return std::move(*value_);
}
- void set_lsb_msb(int64_t lsb, int64_t msb) {
- set_lsb(lsb);
- set_msb(msb);
+ T& value() {
+ PERFETTO_DCHECK(status_.ok());
+ return *value_;
}
- void set_msb(int64_t msb) { memcpy(data_.data() + 8, &msb, 8); }
- void set_lsb(int64_t lsb) { memcpy(data_.data(), &lsb, 8); }
+ const T& value() const { return *value_; }
- std::string ToString() const;
- std::string ToPrettyString() const;
+ T& operator*() { return value(); }
+ const T& operator*() const { return value(); }
+
+ T* operator->() { return &value(); }
+ const T* operator->() const { return &value(); }
private:
- std::array<uint8_t, 16> data_{};
+ StatusOr(base::Status status, std::optional<T> value)
+ : status_(std::move(status)), value_(std::move(value)) {
+ PERFETTO_DCHECK(!status_.ok() || value_.has_value());
+ }
+
+ base::Status status_;
+ std::optional<T> value_;
};
-Uuid Uuidv4();
+// Deduction guide to make returning StatusOr less verbose.
+template <typename T>
+StatusOr(T) -> StatusOr<T>;
} // namespace base
} // namespace perfetto
-#endif // INCLUDE_PERFETTO_EXT_BASE_UUID_H_
+#endif // INCLUDE_PERFETTO_EXT_BASE_STATUS_OR_H_
/*
- * Copyright (C) 2019 The Android Open Source Project
+ * Copyright (C) 2025 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.
@@ -10487,96 +10846,91 @@ Uuid Uuidv4();
* limitations under the License.
*/
-// gen_amalgamated expanded: #include "perfetto/ext/base/uuid.h"
+#ifndef INCLUDE_PERFETTO_EXT_BASE_SCOPED_SCHED_BOOST_H_
+#define INCLUDE_PERFETTO_EXT_BASE_SCOPED_SCHED_BOOST_H_
-#include <random>
+// gen_amalgamated expanded: #include "perfetto/ext/base/status_or.h"
+// gen_amalgamated expanded: #include "perfetto/ext/base/thread_checker.h"
-// gen_amalgamated expanded: #include "perfetto/base/time.h"
-// gen_amalgamated expanded: #include "perfetto/ext/base/utils.h"
+namespace perfetto::base {
-namespace perfetto {
-namespace base {
-namespace {
+// kSchedOther: it's the default policy (e.g., CFS on Linux). Range: 0-20.
+// prio is interpreted as -(nice), i.e., 1 is slightly higher prio
+// than default 0, 20 is the highest priority.
+// Note that this is the opposite semantic of the cmdline nice, and
+// is done for consistency with kSchedFifo, so higher
+// number == higher prio.
+// kSchedFifo: real-time priority. Range: 1-99. 1 is the lowest priority, 99 the
+// highest.
+struct SchedPolicyAndPrio {
+ enum class Policy {
+ kSchedOther,
+ kSchedFifo
+ }; // Order matters for operator<().
-constexpr char kHexmap[] = {'0', '1', '2', '3', '4', '5', '6', '7',
- '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
+ bool operator<(const SchedPolicyAndPrio& other) const {
+ return std::tie(policy, prio) < std::tie(other.policy, other.prio);
+ }
-} // namespace
-
-// A globally unique 128-bit number.
-// In the early days of perfetto we were (sorta) respecting rfc4122. Later we
-// started replacing the LSB of the UUID with the statsd subscription ID in
-// other parts of the codebase (see perfetto_cmd.cc) for the convenience of
-// trace lookups, so rfc4122 made no sense as it just reduced entropy.
-Uuid Uuidv4() {
- // Mix different sources of entropy to reduce the chances of collisions.
- // Only using boot time is not enough. Under the assumption that most traces
- // are started around the same time at boot, within a 1s window, the birthday
- // paradox gives a chance of 90% collisions with 70k traces over a 1e9 space
- // (Number of ns in a 1s window).
- // We deliberately don't use /dev/urandom as that might block for
- // unpredictable time if the system is idle (and is not portable).
- // The UUID does NOT need to be cryptographically secure, but random enough
- // to avoid collisions across a large number of devices.
- uint64_t boot_ns = static_cast<uint64_t>(GetBootTimeNs().count());
- uint64_t epoch_ns = static_cast<uint64_t>(GetWallTimeNs().count());
+ bool operator==(const SchedPolicyAndPrio& other) const {
+ return policy == other.policy && prio == other.prio;
+ }
- // Use code ASLR as entropy source.
- uint32_t code_ptr =
- static_cast<uint32_t>(reinterpret_cast<uint64_t>(&Uuidv4) >> 12);
+ bool operator!=(const SchedPolicyAndPrio& other) const {
+ return !(*this == other);
+ }
- // Use stack ASLR as a further entropy source.
- uint32_t stack_ptr =
- static_cast<uint32_t>(reinterpret_cast<uint64_t>(&code_ptr) >> 12);
+ Policy policy = Policy::kSchedOther;
+ uint32_t prio = 0;
+};
- uint32_t entropy[] = {static_cast<uint32_t>(boot_ns >> 32),
- static_cast<uint32_t>(boot_ns),
- static_cast<uint32_t>(epoch_ns >> 32),
- static_cast<uint32_t>(epoch_ns),
- code_ptr,
- stack_ptr};
- std::seed_seq entropy_seq(entropy, entropy + ArraySize(entropy));
+// Used to mock Linux scheduling policy and parameters API in tests.
+// In production code calls the Linux API, the class is stateless.
+class SchedOsHooks {
+ public:
+ struct SchedOsConfig {
+ int policy;
+ int rt_prio;
+ int nice;
+ };
- auto words = std::array<uint32_t, 4>();
- entropy_seq.generate(words.begin(), words.end());
- uint64_t msb = static_cast<uint64_t>(words[0]) << 32u | words[1];
- uint64_t lsb = static_cast<uint64_t>(words[2]) << 32u | words[3];
- return Uuid(static_cast<int64_t>(lsb), static_cast<int64_t>(msb));
-}
+ virtual ~SchedOsHooks() = default;
+ static SchedOsHooks* GetInstance();
+ // virtual for testing
+ virtual Status SetSchedConfig(const SchedOsConfig& arg);
+ // virtual for testing
+ virtual StatusOr<SchedOsConfig> GetCurrentSchedConfig() const;
+};
-Uuid::Uuid() {}
+// RAII helper to temporarily boost the scheduler priority of the current
+// thread. The priority is reverted to the original value when the object goes
+// out of scope.
+// It is supported only on Linux/Android, fails on other platforms.
+class ScopedSchedBoost {
+ public:
+ static StatusOr<ScopedSchedBoost> Boost(SchedPolicyAndPrio);
+ ScopedSchedBoost(ScopedSchedBoost&&) noexcept;
+ ScopedSchedBoost& operator=(ScopedSchedBoost&&) noexcept;
+ ~ScopedSchedBoost();
-Uuid::Uuid(const std::string& s) {
- PERFETTO_CHECK(s.size() == data_.size());
- memcpy(data_.data(), s.data(), s.size());
-}
+ // No copy constructors.
+ ScopedSchedBoost(const ScopedSchedBoost&) = delete;
+ ScopedSchedBoost& operator=(const ScopedSchedBoost&) = delete;
-Uuid::Uuid(int64_t lsb, int64_t msb) {
- set_lsb_msb(lsb, msb);
-}
+ static void ResetForTesting(SchedOsHooks*);
-std::string Uuid::ToString() const {
- return std::string(reinterpret_cast<const char*>(data_.data()), data_.size());
-}
+ private:
+ explicit ScopedSchedBoost(SchedPolicyAndPrio p) : policy_and_prio_(p) {}
-std::string Uuid::ToPrettyString() const {
- std::string s(data_.size() * 2 + 4, '-');
- // Format is 123e4567-e89b-12d3-a456-426655443322.
- size_t j = 0;
- for (size_t i = 0; i < data_.size(); ++i) {
- if (i == 4 || i == 6 || i == 8 || i == 10)
- j++;
- s[2 * i + j] = kHexmap[(data_[data_.size() - i - 1] & 0xf0) >> 4];
- s[2 * i + 1 + j] = kHexmap[(data_[data_.size() - i - 1] & 0x0f)];
- }
- return s;
-}
+ std::optional<SchedPolicyAndPrio> policy_and_prio_;
+ ThreadChecker thread_checker_;
+};
+} // namespace perfetto::base
-} // namespace base
-} // namespace perfetto
-// gen_amalgamated begin source: src/base/virtual_destructors.cc
+#endif // INCLUDE_PERFETTO_EXT_BASE_SCOPED_SCHED_BOOST_H_
+// gen_amalgamated begin header: include/perfetto/ext/base/status_macros.h
/*
- * Copyright (C) 2017 The Android Open Source Project
+ * 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.
@@ -10591,24 +10945,35 @@ std::string Uuid::ToPrettyString() const {
* limitations under the License.
*/
-// gen_amalgamated expanded: #include "perfetto/base/task_runner.h"
+#ifndef INCLUDE_PERFETTO_EXT_BASE_STATUS_MACROS_H_
+#define INCLUDE_PERFETTO_EXT_BASE_STATUS_MACROS_H_
-// This translation unit contains the definitions for the destructor of pure
-// virtual interfaces for the current build target. The alternative would be
-// introducing a one-liner .cc file for each pure virtual interface, which is
-// overkill. This is for compliance with -Wweak-vtables.
+// gen_amalgamated expanded: #include "perfetto/base/status.h"
-namespace perfetto {
-namespace base {
+// Evaluates |expr|, which should return a base::Status. If the status is an
+// error status, returns the status from the current function.
+#define RETURN_IF_ERROR(expr) \
+ do { \
+ ::perfetto::base::Status status_macro_internal_status = (expr); \
+ if (!status_macro_internal_status.ok()) \
+ return status_macro_internal_status; \
+ } while (0)
-TaskRunner::~TaskRunner() = default;
+#define PERFETTO_INTERNAL_CONCAT_IMPL(x, y) x##y
+#define PERFETTO_INTERNAL_MACRO_CONCAT(x, y) PERFETTO_INTERNAL_CONCAT_IMPL(x, y)
-} // namespace base
-} // namespace perfetto
-// gen_amalgamated begin source: src/base/waitable_event.cc
-// gen_amalgamated begin header: include/perfetto/ext/base/waitable_event.h
+// Evalues |rhs| which should return a base::StatusOr<T> and assigns this
+// to |lhs|. If the status is an error status, returns the status from the
+// current function.
+#define ASSIGN_OR_RETURN(lhs, rhs) \
+ PERFETTO_INTERNAL_MACRO_CONCAT(auto status_or, __LINE__) = rhs; \
+ RETURN_IF_ERROR( \
+ PERFETTO_INTERNAL_MACRO_CONCAT(status_or, __LINE__).status()); \
+ lhs = std::move(PERFETTO_INTERNAL_MACRO_CONCAT(status_or, __LINE__).value())
+
+#endif // INCLUDE_PERFETTO_EXT_BASE_STATUS_MACROS_H_
/*
- * Copyright (C) 2019 The Android Open Source Project
+ * 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.
@@ -10623,46 +10988,249 @@ TaskRunner::~TaskRunner() = default;
* limitations under the License.
*/
-#ifndef INCLUDE_PERFETTO_EXT_BASE_WAITABLE_EVENT_H_
-#define INCLUDE_PERFETTO_EXT_BASE_WAITABLE_EVENT_H_
+// gen_amalgamated expanded: #include "perfetto/ext/base/scoped_sched_boost.h"
-// gen_amalgamated expanded: #include "perfetto/base/thread_annotations.h"
+// gen_amalgamated expanded: #include "perfetto/ext/base/status_macros.h"
-#include <stdint.h>
+#if PERFETTO_BUILDFLAG(PERFETTO_OS_LINUX) || \
+ PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID)
+#include <sched.h> // for 'SCHED_' macros and 'sched_' functions
+#include <sys/resource.h> // for 'setpriority', 'getpriority', 'PRIO_PROCESS'
+#include <sys/types.h> // for 'pid_t'
-#include <condition_variable>
-#include <mutex>
+#include <algorithm>
+#include <vector>
-namespace perfetto {
-namespace base {
+#endif // PERFETTO_OS_LINUX || PERFETTO_OS_ANDROID
-// A waitable event for cross-thread synchronization.
-// All methods on this class can be called from any thread.
-class WaitableEvent {
+namespace perfetto::base {
+
+#if PERFETTO_BUILDFLAG(PERFETTO_OS_LINUX) || \
+ PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID)
+
+namespace {
+constexpr pid_t kCurrentPid = 0;
+
+class ThreadMgr {
public:
- WaitableEvent();
- ~WaitableEvent();
- WaitableEvent(const WaitableEvent&) = delete;
- WaitableEvent operator=(const WaitableEvent&) = delete;
+ // In this class we manage the boost state for the whole process.
+ // If we want to use it for each single thread, this needs to become
+ // 'GetInstanceForThread()'.
+ static ThreadMgr* GetInstance();
- // Synchronously block until the event is notified `notification` times.
- void Wait(uint64_t notifications = 1);
+ explicit ThreadMgr(SchedOsHooks*);
- // Signal the event, waking up blocked waiters.
- void Notify();
+ Status Add(SchedPolicyAndPrio);
+ void Remove(SchedPolicyAndPrio);
+ Status RecalcAndUpdatePrio();
+
+ ThreadMgr(const ThreadMgr&) = delete;
+ ThreadMgr& operator=(const ThreadMgr&) = delete;
+ ThreadMgr(ThreadMgr&&) = delete;
+ ThreadMgr& operator=(ThreadMgr&&) = delete;
+
+ void ResetForTesting(SchedOsHooks*);
private:
- std::mutex mutex_;
- std::condition_variable event_ PERFETTO_GUARDED_BY(mutex_);
- uint64_t notifications_ PERFETTO_GUARDED_BY(mutex_) = 0;
+ SchedOsHooks* os_hooks_;
+ SchedOsHooks::SchedOsConfig initial_config_{};
+ std::vector<SchedPolicyAndPrio> prios_;
};
-} // namespace base
-} // namespace perfetto
+ThreadMgr* ThreadMgr::GetInstance() {
+ static auto* instance = new ThreadMgr(SchedOsHooks::GetInstance());
+ return instance;
+}
+ThreadMgr::ThreadMgr(SchedOsHooks* os_hooks) : os_hooks_(os_hooks) {
+ auto res = os_hooks_->GetCurrentSchedConfig();
+ if (!res.ok()) {
+ // Should never fail: even without CAP_SYS_NICE we can always get our own
+ // policy and prio. If something goes very wrong, log an error and use
+ // SCHED_OTHER as initial config.
+ PERFETTO_DFATAL_OR_ELOG("Failed to get default sched config: %s",
+ res.status().c_message());
+ initial_config_ = SchedOsHooks::SchedOsConfig{SCHED_OTHER, 0, 0};
+ } else {
+ initial_config_ = res.value();
+ }
+}
-#endif // INCLUDE_PERFETTO_EXT_BASE_WAITABLE_EVENT_H_
+Status ThreadMgr::Add(SchedPolicyAndPrio spp) {
+ prios_.push_back(spp);
+ return RecalcAndUpdatePrio();
+}
+
+void ThreadMgr::Remove(SchedPolicyAndPrio spp) {
+ auto it = std::find(prios_.begin(), prios_.end(), spp);
+ if (it != prios_.end()) {
+ prios_.erase(it);
+ }
+ // It is possible that we previously added the wrongly configured policy,
+ // that wasn't the max policy. In that case the policy will be validated now,
+ // in 'RecalcAndUpdatePrio'.
+ // This for loop makes us ignore all wrongly configured policies and fallback
+ // to the first correct (or the initial one).
+ for (;;) {
+ if (auto res = RecalcAndUpdatePrio(); !res.ok()) {
+ PERFETTO_ELOG("%s", res.c_message());
+ } else {
+ break;
+ }
+ }
+}
+
+Status ThreadMgr::RecalcAndUpdatePrio() {
+ if (prios_.empty()) {
+ return os_hooks_->SetSchedConfig(initial_config_);
+ }
+ // TODO(ktimofeev): Check previously set prio to skip unnecessary syscall?
+ auto max_prio = std::max_element(prios_.begin(), prios_.end());
+ SchedOsHooks::SchedOsConfig os_config{};
+ switch (max_prio->policy) {
+ case SchedPolicyAndPrio::Policy::kSchedOther:
+ os_config = SchedOsHooks::SchedOsConfig{
+ SCHED_OTHER, 0, -1 * static_cast<int>(max_prio->prio)};
+ break;
+ case SchedPolicyAndPrio::Policy::kSchedFifo:
+ os_config = SchedOsHooks::SchedOsConfig{
+ SCHED_FIFO, static_cast<int>(max_prio->prio), 0};
+ break;
+ }
+ Status res = os_hooks_->SetSchedConfig(os_config);
+ if (!res.ok()) {
+ prios_.erase(max_prio);
+ return res;
+ }
+ return OkStatus();
+}
+
+void ThreadMgr::ResetForTesting(SchedOsHooks* os_hooks) {
+ os_hooks_ = os_hooks;
+ initial_config_ = os_hooks_->GetCurrentSchedConfig().value();
+ prios_.clear();
+}
+
+} // namespace
+
+SchedOsHooks* SchedOsHooks::GetInstance() {
+ static auto* instance = new SchedOsHooks();
+ return instance;
+}
+
+Status SchedOsHooks::SetSchedConfig(const SchedOsConfig& arg) {
+ sched_param param{};
+ param.sched_priority = arg.rt_prio;
+ int ret = sched_setscheduler(kCurrentPid, arg.policy, ¶m);
+ if (ret == -1) {
+ return ErrStatus("sched_setscheduler(%d, %d) failed (errno: %d, %s)",
+ arg.policy, arg.rt_prio, errno, strerror(errno));
+ }
+ // For the real-time policies the 'arg.rt_prio' value is >= 1.
+ // The userspace policies (SCHED_OTHER, SCHED_BATCH, SCHED_IDLE) use the nice
+ // value.
+ if (arg.rt_prio == 0) {
+ ret = setpriority(PRIO_PROCESS, kCurrentPid, arg.nice);
+ if (ret == -1) {
+ return ErrStatus("setpriority(%d) failed (errno: %d, %s)", arg.nice,
+ errno, strerror(errno));
+ }
+ }
+ return OkStatus();
+}
+
+StatusOr<SchedOsHooks::SchedOsConfig> SchedOsHooks::GetCurrentSchedConfig()
+ const {
+ int policy = sched_getscheduler(kCurrentPid);
+ if (policy == -1) {
+ return ErrStatus("sched_getscheduler failed (errno: %d, %s)", errno,
+ strerror(errno));
+ }
+ sched_param param{};
+ if (sched_getparam(kCurrentPid, ¶m) == -1) {
+ return ErrStatus("sched_getparam failed (errno: %d, %s)", errno,
+ strerror(errno));
+ }
+ int nice = 0;
+ // For the real-time policies the 'param.sched_priority' value is >= 1.
+ // The userspace policies (SCHED_OTHER, SCHED_BATCH, SCHED_IDLE) use the nice
+ // value.
+ if (param.sched_priority == 0) {
+ errno = 0;
+ nice = getpriority(PRIO_PROCESS, kCurrentPid);
+ if (nice == -1 && errno != 0) {
+ return ErrStatus("getpriority failed (errno: %d, %s)", errno,
+ strerror(errno));
+ }
+ }
+ return SchedOsConfig{policy, param.sched_priority, nice};
+}
+
+// static
+StatusOr<ScopedSchedBoost> ScopedSchedBoost::Boost(SchedPolicyAndPrio spp) {
+ auto res = ThreadMgr::GetInstance()->Add(spp);
+ RETURN_IF_ERROR(res);
+ return ScopedSchedBoost(spp);
+}
+
+ScopedSchedBoost::ScopedSchedBoost(ScopedSchedBoost&& other) noexcept {
+ this->policy_and_prio_ = other.policy_and_prio_;
+ other.policy_and_prio_ = std::nullopt;
+}
+
+ScopedSchedBoost& ScopedSchedBoost::operator=(
+ ScopedSchedBoost&& other) noexcept {
+ if (this != &other) {
+ this->~ScopedSchedBoost();
+ new (this) ScopedSchedBoost(std::move(other));
+ }
+ return *this;
+}
+
+ScopedSchedBoost::~ScopedSchedBoost() {
+ PERFETTO_DCHECK_THREAD(thread_checker_);
+ if (!policy_and_prio_.has_value())
+ return;
+ ThreadMgr::GetInstance()->Remove(*policy_and_prio_);
+ policy_and_prio_ = std::nullopt;
+}
+
+// static
+void ScopedSchedBoost::ResetForTesting(SchedOsHooks* os_manager) {
+ ThreadMgr::GetInstance()->ResetForTesting(os_manager);
+}
+
+#else
+
+// static
+SchedOsHooks* SchedOsHooks::GetInstance() {
+ return nullptr;
+}
+
+Status SchedOsHooks::SetSchedConfig(const SchedOsHooks::SchedOsConfig&) {
+ return ErrStatus("SchedOsHooks is supported only on Linux/Android");
+}
+
+StatusOr<SchedOsHooks::SchedOsConfig> SchedOsHooks::GetCurrentSchedConfig()
+ const {
+ return ErrStatus("SchedOsHooks is supported only on Linux/Android");
+}
+
+// static
+StatusOr<ScopedSchedBoost> ScopedSchedBoost::Boost(SchedPolicyAndPrio) {
+ return ErrStatus("ScopedSchedBoost is supported only on Linux/Android");
+}
+
+ScopedSchedBoost::ScopedSchedBoost(ScopedSchedBoost&&) noexcept = default;
+ScopedSchedBoost& ScopedSchedBoost::operator=(ScopedSchedBoost&&) noexcept =
+ default;
+ScopedSchedBoost::~ScopedSchedBoost() = default;
+
+#endif // PERFETTO_OS_LINUX || PERFETTO_OS_ANDROID
+
+} // namespace perfetto::base
+// gen_amalgamated begin source: src/base/status.cc
/*
- * Copyright (C) 2019 The Android Open Source Project
+ * 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.
@@ -10677,36 +11245,97 @@ class WaitableEvent {
* limitations under the License.
*/
-// gen_amalgamated expanded: #include "perfetto/ext/base/waitable_event.h"
+// gen_amalgamated expanded: #include "perfetto/base/status.h"
-namespace perfetto {
-namespace base {
+#include <algorithm>
+#include <cstdarg>
+#include <cstdio>
+#include <string>
+#include <utility>
-WaitableEvent::WaitableEvent() = default;
-WaitableEvent::~WaitableEvent() = default;
+namespace perfetto::base {
-void WaitableEvent::Wait(uint64_t notifications)
- PERFETTO_NO_THREAD_SAFETY_ANALYSIS {
- // 'std::unique_lock' lock doesn't work well with thread annotations
- // (see https://github.com/llvm/llvm-project/issues/63239),
- // so we suppress thread safety static analysis for this method.
- std::unique_lock<std::mutex> lock(mutex_);
- return event_.wait(lock, [&]() PERFETTO_EXCLUSIVE_LOCKS_REQUIRED(mutex_) {
- return notifications_ >= notifications;
- });
+Status ErrStatus(const char* format, ...) {
+ std::string buf;
+ buf.resize(1024);
+ for (;;) {
+ va_list ap;
+ va_start(ap, format);
+ int N = vsnprintf(buf.data(), buf.size() - 1, format, ap);
+ va_end(ap);
+
+ if (N <= 0) {
+ buf = "[printf format error]";
+ break;
+ }
+
+ auto sN = static_cast<size_t>(N);
+ if (sN > buf.size() - 1) {
+ // Indicates that the string was truncated and sN is the "number of
+ // non-null bytes which would be needed to fit the result". This is the
+ // C99 standard behaviour in the case of truncation. In that case, resize
+ // the buffer to match the returned value (with + 1 for the null
+ // terminator) and try again.
+ buf.resize(sN + 1);
+ continue;
+ }
+ if (sN == buf.size() - 1) {
+ // Indicates that the string was likely truncated and sN is just the
+ // number of bytes written into the string. This is the behaviour of
+ // non-standard compilers (MSVC) etc. In that case, just double the
+ // storage and try again.
+ buf.resize(sN * 2);
+ continue;
+ }
+
+ // Otherwise, indicates the string was written successfully: we need to
+ // resize to match the number of non-null bytes and return.
+ buf.resize(sN);
+ break;
+ }
+ return Status(std::move(buf));
}
-void WaitableEvent::Notify() {
- std::lock_guard<std::mutex> lock(mutex_);
- ++notifications_;
- event_.notify_all();
+std::optional<std::string_view> Status::GetPayload(
+ std::string_view type_url) const {
+ if (ok()) {
+ return std::nullopt;
+ }
+ for (const auto& kv : payloads_) {
+ if (kv.type_url == type_url) {
+ return kv.payload;
+ }
+ }
+ return std::nullopt;
}
-} // namespace base
-} // namespace perfetto
-// gen_amalgamated begin source: src/base/watchdog_posix.cc
-// gen_amalgamated begin header: include/perfetto/ext/base/watchdog.h
-// gen_amalgamated begin header: include/perfetto/ext/base/watchdog_noop.h
+void Status::SetPayload(std::string_view type_url, std::string value) {
+ if (ok()) {
+ return;
+ }
+ for (auto& kv : payloads_) {
+ if (kv.type_url == type_url) {
+ kv.payload = value;
+ return;
+ }
+ }
+ payloads_.push_back(Payload{std::string(type_url), std::move(value)});
+}
+
+bool Status::ErasePayload(std::string_view type_url) {
+ if (ok()) {
+ return false;
+ }
+ auto it = std::remove_if(
+ payloads_.begin(), payloads_.end(),
+ [type_url](const Payload& p) { return p.type_url == type_url; });
+ bool erased = it != payloads_.end();
+ payloads_.erase(it, payloads_.end());
+ return erased;
+}
+
+} // namespace perfetto::base
+// gen_amalgamated begin source: src/base/string_splitter.cc
/*
* Copyright (C) 2018 The Android Open Source Project
*
@@ -10723,149 +11352,83 @@ void WaitableEvent::Notify() {
* limitations under the License.
*/
-#ifndef INCLUDE_PERFETTO_EXT_BASE_WATCHDOG_NOOP_H_
-#define INCLUDE_PERFETTO_EXT_BASE_WATCHDOG_NOOP_H_
-
-#include <stdint.h>
-
-#include <functional>
-
-namespace perfetto {
-namespace base {
-
-class TaskRunner;
-
-enum class WatchdogCrashReason; // Defined in watchdog.h.
-struct WatchdogCrashInfo; // Defined in watchdog.h.
-
-class Watchdog {
- public:
- class Timer {
- public:
- // Define an empty dtor to avoid "unused variable" errors on the call site.
- Timer() {}
- Timer(const Timer&) {}
- ~Timer() {}
- };
- static Watchdog* GetInstance() {
- static Watchdog* watchdog = new Watchdog();
- return watchdog;
- }
- Timer CreateFatalTimer(uint32_t /*ms*/, WatchdogCrashReason) {
- return Timer();
- }
- void Start(TaskRunner* /*task_runner*/ = nullptr,
- std::function<void(WatchdogCrashInfo)> /*handler*/ = {}) {}
- void SetMemoryLimit(uint64_t /*bytes*/, uint32_t /*window_ms*/) {}
- void SetCpuLimit(uint32_t /*percentage*/, uint32_t /*window_ms*/) {}
-};
-
-} // namespace base
-} // namespace perfetto
-
-#endif // INCLUDE_PERFETTO_EXT_BASE_WATCHDOG_NOOP_H_
-/*
- * 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.
- */
-
-#ifndef INCLUDE_PERFETTO_EXT_BASE_WATCHDOG_H_
-#define INCLUDE_PERFETTO_EXT_BASE_WATCHDOG_H_
-
-#include <functional>
+// gen_amalgamated expanded: #include "perfetto/ext/base/string_splitter.h"
-// gen_amalgamated expanded: #include "perfetto/base/build_config.h"
+#include <utility>
-// The POSIX watchdog is only supported on Linux and Android in non-embedder
-// builds.
-#if PERFETTO_BUILDFLAG(PERFETTO_WATCHDOG)
-// gen_amalgamated expanded: #include "perfetto/ext/base/watchdog_posix.h"
-#else
-// gen_amalgamated expanded: #include "perfetto/ext/base/watchdog_noop.h"
-#endif
+// gen_amalgamated expanded: #include "perfetto/base/logging.h"
namespace perfetto {
namespace base {
-// Used only to add more details to crash reporting.
-enum class WatchdogCrashReason {
- kUnspecified = 0,
- kCpuGuardrail = 1,
- kMemGuardrail = 2,
- kTaskRunnerHung = 3,
- kTraceDidntStop = 4,
-};
-
-// Information about an imminent watchdog-triggered crash. Passed to the fatal
-// handler installed via Watchdog::Start() so embedders can record it (e.g. via
-// metatrace counters) before the process is force-killed.
-struct WatchdogCrashInfo {
- int thread_id = 0;
- WatchdogCrashReason reason = WatchdogCrashReason::kUnspecified;
-
- // The time in CLOCK_BOOTTIME when the watchdog triggered.
- int64_t alarm_time_ms = 0;
-
- // The initial timeout passed to CreateFatalTimer.
- int timeout_s = 0;
-
- // Elapsed seconds, since the offending fatal timer was created, sampled
- // from CLOCK_MONOTONIC, CLOCK_BOOTTIME and CLOCK_PROCESS_CPUTIME_ID
- // respectively. These mirror the wdog_actual_{mono,boot,cpu} crash keys.
- // They are 0 for cpu/memory guardrail crashes (no associated timer).
- int actual_mono_s = 0;
- int actual_boot_s = 0;
- int actual_cpu_s = 0;
-};
-
-// Make the limits more relaxed on desktop, where multi-GB traces are likely.
-// Multi-GB traces can take bursts of cpu time to write into disk at the end of
-// the trace.
-#if PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID)
-constexpr uint32_t kWatchdogDefaultCpuLimit = 75;
-constexpr uint32_t kWatchdogDefaultCpuWindow = 5 * 60 * 1000; // 5 minutes.
-#else
-constexpr uint32_t kWatchdogDefaultCpuLimit = 90;
-constexpr uint32_t kWatchdogDefaultCpuWindow = 10 * 60 * 1000; // 10 minutes.
-#endif
+StringSplitter::StringSplitter(std::string str,
+ char delimiter,
+ EmptyTokenMode empty_token_mode)
+ : str_(std::move(str)),
+ delimiter_(delimiter),
+ empty_token_mode_(empty_token_mode) {
+ // It's legal to access str[str.size()] in C++11 (it always returns \0),
+ // hence the +1 (which becomes just size() after the -1 in Initialize()).
+ Initialize(&str_[0], str_.size() + 1);
+}
-// The default memory margin we give to our processes. This is used as as a
-// constant to put on top of the trace buffers.
-// TODO(b/540573436): Retune the value once we have a proper solution.
-constexpr uint64_t kWatchdogDefaultMemorySlack = 64 * 1024 * 1024; // 64 MiB.
-constexpr uint32_t kWatchdogDefaultMemoryWindow = 30 * 1000; // 30 seconds.
+StringSplitter::StringSplitter(char* str,
+ size_t size,
+ char delimiter,
+ EmptyTokenMode empty_token_mode)
+ : delimiter_(delimiter), empty_token_mode_(empty_token_mode) {
+ Initialize(str, size);
+}
-inline void RunTaskWithWatchdogGuard(const std::function<void()>& task) {
- // The longest duration allowed for a single task within the TaskRunner.
- // Exceeding this limit will trigger program termination.
- constexpr int64_t kWatchdogMillis = 180000; // 180s
+StringSplitter::StringSplitter(StringSplitter* outer,
+ char delimiter,
+ EmptyTokenMode empty_token_mode)
+ : delimiter_(delimiter), empty_token_mode_(empty_token_mode) {
+ Initialize(outer->cur_token(), outer->cur_token_size() + 1);
+}
- Watchdog::Timer handle = base::Watchdog::GetInstance()->CreateFatalTimer(
- kWatchdogMillis, WatchdogCrashReason::kTaskRunnerHung);
- task();
+void StringSplitter::Initialize(char* str, size_t size) {
+ PERFETTO_DCHECK(!size || str);
+ next_ = str;
+ end_ = str + size;
+ cur_ = nullptr;
+ cur_size_ = 0;
+ if (size)
+ next_[size - 1] = '\0';
+}
- // Suppress unused variable warnings in the client library amalgamated build.
- (void)kWatchdogDefaultCpuLimit;
- (void)kWatchdogDefaultCpuWindow;
- (void)kWatchdogDefaultMemorySlack;
- (void)kWatchdogDefaultMemoryWindow;
+bool StringSplitter::Next() {
+ for (; next_ < end_; next_++) {
+ if (*next_ == delimiter_ &&
+ empty_token_mode_ == EmptyTokenMode::DISALLOW_EMPTY_TOKENS) {
+ // If empty tokens are disallowed, find fist non-delimiter character.
+ continue;
+ }
+ cur_ = next_;
+ for (;; next_++) {
+ if (*next_ == delimiter_) {
+ cur_size_ = static_cast<size_t>(next_ - cur_);
+ *(next_++) = '\0';
+ break;
+ }
+ if (*next_ == '\0') {
+ cur_size_ = static_cast<size_t>(next_ - cur_);
+ next_ = end_;
+ break;
+ }
+ }
+ if (*cur_ || empty_token_mode_ == EmptyTokenMode::ALLOW_EMPTY_TOKENS)
+ return true;
+ break;
+ }
+ cur_ = nullptr;
+ cur_size_ = 0;
+ return false;
}
} // namespace base
} // namespace perfetto
-
-#endif // INCLUDE_PERFETTO_EXT_BASE_WATCHDOG_H_
+// gen_amalgamated begin source: src/base/string_utils.cc
/*
* Copyright (C) 2018 The Android Open Source Project
*
@@ -10882,501 +11445,433 @@ inline void RunTaskWithWatchdogGuard(const std::function<void()>& task) {
* limitations under the License.
*/
-// gen_amalgamated expanded: #include "perfetto/ext/base/platform.h"
// gen_amalgamated expanded: #include "perfetto/ext/base/string_utils.h"
-// gen_amalgamated expanded: #include "perfetto/ext/base/watchdog.h"
-
-#if PERFETTO_BUILDFLAG(PERFETTO_WATCHDOG)
-#include <fcntl.h>
-#include <poll.h>
-#include <signal.h>
-#include <stdint.h>
-#include <stdlib.h>
-#include <sys/syscall.h>
-#include <sys/timerfd.h>
-#include <unistd.h>
+#include <locale.h>
+#include <stdarg.h>
+#include <string.h>
#include <algorithm>
+
+#if PERFETTO_BUILDFLAG(PERFETTO_OS_APPLE)
+#include <xlocale.h>
+#elif PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
+#include <windows.h>
+#endif
+
#include <cinttypes>
-#include <fstream>
-#include <thread>
+#include <string_view>
-// gen_amalgamated expanded: #include "perfetto/base/build_config.h"
+// gen_amalgamated expanded: #include "perfetto/base/compiler.h"
// gen_amalgamated expanded: #include "perfetto/base/logging.h"
-// gen_amalgamated expanded: #include "perfetto/base/task_runner.h"
-// gen_amalgamated expanded: #include "perfetto/base/thread_utils.h"
-// gen_amalgamated expanded: #include "perfetto/base/time.h"
-// gen_amalgamated expanded: #include "perfetto/ext/base/crash_keys.h"
-// gen_amalgamated expanded: #include "perfetto/ext/base/file_utils.h"
-// gen_amalgamated expanded: #include "perfetto/ext/base/scoped_file.h"
-// gen_amalgamated expanded: #include "perfetto/ext/base/utils.h"
namespace perfetto {
namespace base {
-namespace {
-
-constexpr uint32_t kDefaultPollingInterval = 30 * 1000;
-
-// Grace period given to a fatal handler (passed to Start()) to
-// crash the process on its own before the watchdog force-kills it.
-constexpr uint32_t kFatalHandlerGraceMs = 60 * 1000;
-
-base::CrashKey g_crash_key_reason("wdog_reason");
-base::CrashKey g_crash_key_timeout("wdog_timeout");
-base::CrashKey g_crash_key_actual_mono("wdog_actual_mono");
-base::CrashKey g_crash_key_actual_boot("wdog_actual_boot");
-base::CrashKey g_crash_key_actual_cpu("wdog_actual_cpu");
-
-bool IsMultipleOf(uint32_t number, uint32_t divisor) {
- return number >= divisor && number % divisor == 0;
+// Locale-independent as possible version of strtod.
+double StrToD(const char* nptr, char** endptr) {
+#if PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID) || \
+ PERFETTO_BUILDFLAG(PERFETTO_OS_LINUX_BUT_NOT_QNX) || \
+ PERFETTO_BUILDFLAG(PERFETTO_OS_APPLE)
+ static auto c_locale = newlocale(LC_ALL, "C", nullptr);
+ return strtod_l(nptr, endptr, c_locale);
+#else
+ return strtod(nptr, endptr);
+#endif
}
-double MeanForArray(const uint64_t array[], size_t size) {
- uint64_t total = 0;
- for (size_t i = 0; i < size; i++) {
- total += array[i];
- }
- return static_cast<double>(total / size);
+bool StartsWith(const std::string& str, const std::string& prefix) {
+ return str.compare(0, prefix.length(), prefix) == 0;
}
-} // namespace
-
-bool ReadProcStat(int fd, ProcStat* out) {
- char c[512];
- size_t c_pos = 0;
- while (c_pos < sizeof(c) - 1) {
- ssize_t rd = PERFETTO_EINTR(read(fd, c + c_pos, sizeof(c) - c_pos));
- if (rd < 0) {
- PERFETTO_ELOG("Failed to read stat file to enforce resource limits.");
- return false;
- }
- if (rd == 0)
- break;
- c_pos += static_cast<size_t>(rd);
- }
- PERFETTO_CHECK(c_pos < sizeof(c));
- c[c_pos] = '\0';
+bool StartsWithAny(const std::string& str,
+ const std::vector<std::string>& prefixes) {
+ return std::any_of(
+ prefixes.begin(), prefixes.end(),
+ [&str](const std::string& prefix) { return StartsWith(str, prefix); });
+}
- if (sscanf(c,
- "%*d %*s %*c %*d %*d %*d %*d %*d %*u %*u %*u %*u %*u %lu "
- "%lu %*d %*d %*d %*d %*d %*d %*u %*u %ld",
- &out->utime, &out->stime, &out->rss_pages) != 3) {
- PERFETTO_ELOG("Invalid stat format: %s", c);
+bool EndsWith(const std::string& str, const std::string& suffix) {
+ if (suffix.size() > str.size())
return false;
- }
- return true;
+ return str.compare(str.size() - suffix.size(), suffix.size(), suffix) == 0;
}
-Watchdog::Watchdog(uint32_t polling_interval_ms)
- : polling_interval_ms_(polling_interval_ms) {}
-
-Watchdog::~Watchdog() {
- if (!thread_.joinable()) {
- PERFETTO_DCHECK(!enabled_);
- return;
- }
- PERFETTO_DCHECK(enabled_);
- enabled_ = false;
- // Rearm the timer to 1ns from now. This will cause the watchdog thread to
- // wakeup from the poll() and see |enabled_| == false.
- // This code path is used only in tests. In production code the watchdog
- // is a singleton and is never destroyed.
- struct itimerspec ts{};
- ts.it_value.tv_sec = 0;
- ts.it_value.tv_nsec = 1;
- timerfd_settime(*timer_fd_, /*flags=*/0, &ts, nullptr);
-
- thread_.join();
+bool Contains(const std::string& haystack, const std::string& needle) {
+ return haystack.find(needle) != std::string::npos;
}
-Watchdog* Watchdog::GetInstance() {
- static Watchdog* watchdog = new Watchdog(kDefaultPollingInterval);
- return watchdog;
+bool Contains(const std::string& haystack, const char needle) {
+ return haystack.find(needle) != std::string::npos;
}
-// Can be called from any thread.
-Watchdog::Timer Watchdog::CreateFatalTimer(uint32_t ms,
- WatchdogCrashReason crash_reason) {
- if (!enabled_.load(std::memory_order_relaxed))
- return Watchdog::Timer(this, 0, crash_reason);
+bool Contains(const std::vector<std::string>& haystack,
+ const std::string& needle) {
+ return std::find(haystack.begin(), haystack.end(), needle) != haystack.end();
+}
- return Watchdog::Timer(this, ms, crash_reason);
+size_t Find(const StringView& needle, const StringView& haystack) {
+ if (needle.empty())
+ return 0;
+ if (needle.size() > haystack.size())
+ return std::string::npos;
+ for (size_t i = 0; i < haystack.size() - (needle.size() - 1); ++i) {
+ if (strncmp(haystack.data() + i, needle.data(), needle.size()) == 0)
+ return i;
+ }
+ return std::string::npos;
}
-// Can be called from any thread.
-void Watchdog::AddFatalTimer(TimerData timer) {
- std::lock_guard<std::mutex> guard(mutex_);
- timers_.emplace_back(std::move(timer));
- RearmTimerFd_Locked();
+bool CaseInsensitiveEqual(std::string_view first, std::string_view second) {
+ return first.size() == second.size() &&
+ std::equal(
+ first.begin(), first.end(), second.begin(),
+ [](char a, char b) { return Lowercase(a) == Lowercase(b); });
}
-// Can be called from any thread.
-void Watchdog::RemoveFatalTimer(TimerData timer) {
- std::lock_guard<std::mutex> guard(mutex_);
- for (auto it = timers_.begin(); it != timers_.end(); it++) {
- if (*it == timer) {
- timers_.erase(it);
- break; // Remove only one. Doesn't matter which one.
+std::string Join(const std::vector<std::string>& parts,
+ const std::string& delim) {
+ std::string acc;
+ for (size_t i = 0; i < parts.size(); ++i) {
+ acc += parts[i];
+ if (i + 1 != parts.size()) {
+ acc += delim;
}
}
- RearmTimerFd_Locked();
+ return acc;
}
-void Watchdog::RearmTimerFd_Locked() {
- if (!enabled_)
- return;
- auto it = std::min_element(timers_.begin(), timers_.end());
+std::vector<std::string> SplitString(const std::string& text,
+ const std::string& delimiter) {
+ PERFETTO_CHECK(!delimiter.empty());
- // We use one timerfd to handle all the outstanding |timers_|. Keep it armed
- // to the task expiring soonest.
- struct itimerspec ts{};
- if (it != timers_.end()) {
- ts.it_value = ToPosixTimespec(it->deadline);
+ std::vector<std::string> output;
+ size_t start = 0;
+ size_t next;
+ for (;;) {
+ next = std::min(text.find(delimiter, start), text.size());
+ if (next > start)
+ output.emplace_back(&text[start], next - start);
+ start = next + delimiter.size();
+ if (start >= text.size())
+ break;
}
- // If |timers_| is empty (it == end()) |ts.it_value| will remain
- // zero-initialized and that will disarm the timer in the call below.
- int res = timerfd_settime(*timer_fd_, TFD_TIMER_ABSTIME, &ts, nullptr);
- PERFETTO_DCHECK(res == 0);
+ return output;
}
-void Watchdog::Start(TaskRunner* task_runner,
- std::function<void(WatchdogCrashInfo)> fatal_handler) {
- std::lock_guard<std::mutex> guard(mutex_);
- if (thread_.joinable()) {
- PERFETTO_DCHECK(enabled_);
- } else {
- PERFETTO_DCHECK(!enabled_);
+std::string_view TrimWhitespace(std::string_view str) {
+ static constexpr char kWhitespaces[] = "\t\n ";
+ size_t front_idx = str.find_first_not_of(kWhitespaces);
+ if (front_idx == std::string_view::npos)
+ return {};
+ std::string_view front_trimmed = str.substr(front_idx);
+ size_t end_idx = front_trimmed.find_last_not_of(kWhitespaces);
+ PERFETTO_DCHECK(end_idx != std::string_view::npos);
+ return front_trimmed.substr(0, end_idx + 1);
+}
- // |fatal_handler_*| are written here, before the watchdog thread is
- // created. The watchdog thread is the only reader, so no locking is
- // needed when accessing them from ThreadMain().
- fatal_handler_task_runner_ = task_runner;
- fatal_handler_ = std::move(fatal_handler);
+std::string TrimWhitespace(const std::string& str) {
+ return std::string(TrimWhitespace(std::string_view(str)));
+}
-#if PERFETTO_BUILDFLAG(PERFETTO_OS_LINUX) || \
- PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID)
- // Kick the thread to start running but only on Android or Linux.
- timer_fd_.reset(
- timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC | TFD_NONBLOCK));
- if (!timer_fd_) {
- PERFETTO_PLOG(
- "timerfd_create failed, the Perfetto watchdog is not available");
- return;
- }
- enabled_ = true;
- RearmTimerFd_Locked(); // Deal with timers created before Start().
- thread_ = std::thread(&Watchdog::ThreadMain, this);
-#endif
- }
+std::string_view TrimWhitespace(const char* str) {
+ return TrimWhitespace(std::string_view(str));
}
-void Watchdog::SetMemoryLimit(uint64_t bytes, uint32_t window_ms) {
- // Update the fields under the lock.
- std::lock_guard<std::mutex> guard(mutex_);
+std::string StripPrefix(const std::string& str, const std::string& prefix) {
+ return StartsWith(str, prefix) ? str.substr(prefix.size()) : str;
+}
- PERFETTO_CHECK(IsMultipleOf(window_ms, polling_interval_ms_) || bytes == 0);
+std::string StripSuffix(const std::string& str, const std::string& suffix) {
+ return EndsWith(str, suffix) ? str.substr(0, str.size() - suffix.size())
+ : str;
+}
- size_t size = bytes == 0 ? 0 : window_ms / polling_interval_ms_ + 1;
- memory_window_bytes_.Reset(size);
- memory_limit_bytes_ = bytes;
+std::string ToUpper(const std::string& str) {
+ // Don't use toupper(), it depends on the locale.
+ std::string res(str);
+ auto end = res.end();
+ for (auto c = res.begin(); c != end; ++c)
+ *c = Uppercase(*c);
+ return res;
}
-void Watchdog::SetCpuLimit(uint32_t percentage, uint32_t window_ms) {
- std::lock_guard<std::mutex> guard(mutex_);
+std::string ToLower(const std::string& str) {
+ // Don't use tolower(), it depends on the locale.
+ std::string res(str);
+ auto end = res.end();
+ for (auto c = res.begin(); c != end; ++c)
+ *c = Lowercase(*c);
+ return res;
+}
- PERFETTO_CHECK(percentage <= 100);
- PERFETTO_CHECK(IsMultipleOf(window_ms, polling_interval_ms_) ||
- percentage == 0);
+std::string ToHex(const char* data, size_t size) {
+ std::string hex(2 * size + 1, 'x');
+ for (size_t i = 0; i < size; ++i) {
+ // snprintf prints 3 characters, the two hex digits and a null byte. As we
+ // write left to right, we keep overwriting the nullbytes, except for the
+ // last call to snprintf.
+ snprintf(&(hex[2 * i]), 3, "%02hhx", data[i]);
+ }
+ // Remove the trailing nullbyte produced by the last snprintf.
+ hex.resize(2 * size);
+ return hex;
+}
- size_t size = percentage == 0 ? 0 : window_ms / polling_interval_ms_ + 1;
- cpu_window_time_ticks_.Reset(size);
- cpu_limit_percentage_ = percentage;
+std::string IntToHexString(uint32_t number) {
+ size_t max_size = 11; // Max uint32 is 0xFFFFFFFF + 1 for null byte.
+ std::string buf;
+ buf.resize(max_size);
+ size_t final_len = SprintfTrunc(&buf[0], max_size, "0x%02x", number);
+ buf.resize(static_cast<size_t>(final_len)); // Cuts off the final null byte.
+ return buf;
}
-void Watchdog::ThreadMain() {
- // Register crash keys explicitly to avoid running out of slots at crash time.
- g_crash_key_reason.Register();
- g_crash_key_timeout.Register();
- g_crash_key_actual_boot.Register();
- g_crash_key_actual_mono.Register();
- g_crash_key_actual_cpu.Register();
+std::string Uint64ToHexString(uint64_t number) {
+ return "0x" + Uint64ToHexStringNoPrefix(number);
+}
- base::ScopedFile stat_fd(base::OpenFile("/proc/self/stat", O_RDONLY));
- if (!stat_fd) {
- PERFETTO_ELOG("Failed to open stat file to enforce resource limits.");
- return;
- }
+std::string Uint64ToHexStringNoPrefix(uint64_t number) {
+ size_t max_size = 17; // Max uint64 is FFFFFFFFFFFFFFFF + 1 for null byte.
+ std::string buf;
+ buf.resize(max_size);
+ size_t final_len = SprintfTrunc(&buf[0], max_size, "%" PRIx64 "", number);
+ buf.resize(static_cast<size_t>(final_len)); // Cuts off the final null byte.
+ return buf;
+}
- PERFETTO_DCHECK(timer_fd_);
+std::string StripChars(const std::string& str,
+ const std::string& chars,
+ char replacement) {
+ std::string res(str);
+ const char* start = res.c_str();
+ const char* remove = chars.c_str();
+ for (const char* c = strpbrk(start, remove); c; c = strpbrk(c + 1, remove))
+ res[static_cast<uintptr_t>(c - start)] = replacement;
+ return res;
+}
- constexpr uint8_t kFdCount = 1;
- struct pollfd fds[kFdCount]{};
- fds[0].fd = *timer_fd_;
- fds[0].events = POLLIN;
+std::string ReplaceAll(std::string str,
+ const std::string& to_replace,
+ const std::string& replacement) {
+ PERFETTO_CHECK(!to_replace.empty());
+ size_t pos = 0;
+ while ((pos = str.find(to_replace, pos)) != std::string::npos) {
+ str.replace(pos, to_replace.length(), replacement);
+ pos += replacement.length();
+ }
+ return str;
+}
- for (;;) {
- // We use the poll() timeout to drive the periodic ticks for the cpu/memory
- // checks. The only other case when the poll() unblocks is when we crash
- // (or have to quit via enabled_ == false, but that happens only in tests).
- platform::BeforeMaybeBlockingSyscall();
- auto ret = poll(fds, kFdCount, static_cast<int>(polling_interval_ms_));
- platform::AfterMaybeBlockingSyscall();
- if (!enabled_)
- return;
- if (ret < 0) {
- if (errno == ENOMEM || errno == EINTR) {
- // Should happen extremely rarely.
- std::this_thread::sleep_for(std::chrono::milliseconds(100));
- continue;
- }
- PERFETTO_FATAL("watchdog poll() failed");
- }
+bool CheckAsciiAndRemoveInvalidUTF8(base::StringView str, std::string& output) {
+ bool is_ascii = std::all_of(str.begin(), str.end(), [](char c) {
+ return (static_cast<unsigned char>(c) & 0b10000000) == 0b00000000;
+ });
+ if (is_ascii) {
+ return true;
+ }
- // If we get here either:
- // 1. poll() timed out, in which case we should process cpu/mem guardrails.
- // 2. A timer expired, in which case we shall crash.
+ // https://www.rfc-editor.org/rfc/rfc3629.txt
+ output.clear();
+ output.reserve(str.size());
+ for (size_t i = 0; i < str.size();) {
+ unsigned char c = static_cast<unsigned char>(str.data()[i]);
+ size_t num_bytes = 0;
+ bool valid_sequence = true;
- uint64_t expired = 0; // Must be exactly 8 bytes.
- auto res = PERFETTO_EINTR(read(*timer_fd_, &expired, sizeof(expired)));
- PERFETTO_DCHECK((res < 0 && (errno == EAGAIN)) ||
- (res == sizeof(expired) && expired > 0));
- const TimeMillis now_mono_ms = GetWallTimeMs();
+ if ((c & 0b10000000) == 0b00000000) {
+ num_bytes = 1;
+ } else if ((c & 0b11100000) == 0b11000000) {
+ num_bytes = 2;
+ } else if ((c & 0b11110000) == 0b11100000) {
+ num_bytes = 3;
+ } else if ((c & 0b11111000) == 0b11110000) {
+ num_bytes = 4;
+ } else {
+ valid_sequence = false;
+ // Skip this byte
+ num_bytes = 1;
+ }
- // Check if any of the timers expired.
- WatchdogCrashInfo info{};
- {
- std::lock_guard<std::mutex> guard(mutex_);
- for (const auto& timer : timers_) {
- if (now_mono_ms >= timer.deadline) {
- info.thread_id = timer.thread_id;
- info.reason = timer.crash_reason;
- const TimeMillis now_boot_ms = GetBootTimeMs();
- info.alarm_time_ms = now_boot_ms.count();
- info.timeout_s =
- static_cast<int>(std::chrono::duration_cast<TimeSeconds>(
- timer.deadline - timer.ctime_mono)
- .count());
- info.actual_mono_s =
- static_cast<int>(std::chrono::duration_cast<TimeSeconds>(
- now_mono_ms - timer.ctime_mono)
- .count());
- info.actual_boot_s =
- static_cast<int>(std::chrono::duration_cast<TimeSeconds>(
- now_boot_ms - timer.ctime_boot)
- .count());
- info.actual_cpu_s =
- static_cast<int>(std::chrono::duration_cast<TimeSeconds>(
- GetProcessCPUTimeNs() - timer.ctime_cpu)
- .count());
- break;
+ if (valid_sequence) {
+ // Check if enough bytes are available in the string
+ if (i + num_bytes > str.size()) {
+ valid_sequence = false;
+ num_bytes = 1; // Treat as a single invalid byte for advancement
+ } else {
+ // Check for overlong encodings, surrogates, and out-of-range
+ if (num_bytes == 2 && c < 0b11000010) { // 0xC2
+ valid_sequence = false; // Overlong
+ } else if (num_bytes == 3) {
+ unsigned char byte2 = static_cast<unsigned char>(str.data()[i + 1]);
+ if ((c == 0b11100000 && byte2 < 0b10100000) || // Overlong E0
+ (c == 0b11101101 && byte2 >= 0b10100000)) { // Surrogate ED
+ valid_sequence = false;
+ }
+ } else if (num_bytes == 4) {
+ unsigned char byte2 = static_cast<unsigned char>(str.data()[i + 1]);
+ if ((c == 0b11110000 && byte2 < 0b10010000) || // Overlong F0
+ (c == 0b11110100 && byte2 > 0b10001111)) { // Out of range F4
+ valid_sequence = false;
+ }
}
- }
- }
- if (info.thread_id) {
- SerializeLogsAndKillThread(info.thread_id, info);
+ if (valid_sequence && num_bytes > 1) {
+ for (size_t j = 1; j < num_bytes; ++j) {
+ unsigned char continuation_byte =
+ static_cast<unsigned char>(str.data()[i + j]);
+ if ((continuation_byte & 0b11000000) != 0b10000000) {
+ valid_sequence = false;
+ break;
+ }
+ }
+ }
+ }
}
- // Check CPU and memory guardrails (if enabled).
- lseek(stat_fd.get(), 0, SEEK_SET);
- ProcStat stat;
- if (!ReadProcStat(stat_fd.get(), &stat))
- continue;
- uint64_t cpu_time = stat.utime + stat.stime;
- uint64_t rss_bytes =
- static_cast<uint64_t>(stat.rss_pages) * base::GetSysPageSize();
-
- bool threshold_exceeded = false;
- WatchdogCrashReason crash_reason{};
- {
- std::lock_guard<std::mutex> guard(mutex_);
- if (CheckMemory_Locked(rss_bytes) && !IsSyncMemoryTaggingEnabled()) {
- threshold_exceeded = true;
- crash_reason = WatchdogCrashReason::kMemGuardrail;
- } else if (CheckCpu_Locked(cpu_time)) {
- threshold_exceeded = true;
- crash_reason = WatchdogCrashReason::kCpuGuardrail;
+ if (valid_sequence) {
+ for (size_t j = 0; j < num_bytes; ++j) {
+ output.push_back(str.data()[i + j]);
}
}
- if (threshold_exceeded) {
- info.reason = crash_reason;
- // No associated timer: info.actual_*_s remain 0.
- SerializeLogsAndKillThread(getpid(), info);
- }
+ i += num_bytes;
}
+ return false;
}
-void Watchdog::SerializeLogsAndKillThread(int tid,
- const WatchdogCrashInfo& info) {
- g_crash_key_timeout.Set(info.timeout_s);
- g_crash_key_actual_mono.Set(info.actual_mono_s);
- g_crash_key_actual_boot.Set(info.actual_boot_s);
- g_crash_key_actual_cpu.Set(info.actual_cpu_s);
- g_crash_key_reason.Set(static_cast<int>(info.reason));
-
- // If the embedder installed a fatal handler, give it a chance to run (e.g.
- // to flush in-flight state) before we force-kill the process. The handler
- // is expected to crash the process on its own (e.g. via PERFETTO_FATAL once
- // it's done). If it doesn't crash within |kFatalHandlerGraceMs|, we proceed
- // and force-kill from here.
- // |fatal_handler_*| are set in Start() before the watchdog thread is
- // created, so no locking is needed. Clearing them after invocation prevents
- // re-posting if the same expired condition is observed again.
- if (fatal_handler_ && fatal_handler_task_runner_) {
- fatal_handler_task_runner_->PostTask(
- [h = std::move(fatal_handler_), info] { h(info); });
- fatal_handler_ = nullptr;
- fatal_handler_task_runner_ = nullptr;
- if (!disable_kill_failsafe_for_testing_) {
- std::this_thread::sleep_for(
- std::chrono::milliseconds(kFatalHandlerGraceMs));
- }
+#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
+bool WideToUTF8(const std::wstring& source, std::string& output) {
+ if (source.empty() ||
+ source.size() > static_cast<size_t>(std::numeric_limits<int>::max())) {
+ return false;
}
-
- // We are about to die. Serialize the logs into the crash buffer so the
- // debuggerd crash handler picks them up and attaches to the bugreport.
- // In the case of a PERFETTO_CHECK/PERFETTO_FATAL this is done in logging.h.
- // But in the watchdog case, we don't hit that codepath and must do ourselves.
- MaybeSerializeLastLogsForCrashReporting();
-
- // Send a SIGABRT to the thread that armed the timer. This is to see the
- // callstack of the thread that is stuck in a long task rather than the
- // watchdog thread.
- if (syscall(__NR_tgkill, getpid(), tid, SIGABRT) < 0) {
- // At this point the process must die. If for any reason the tgkill doesn't
- // work (e.g. the thread has disappeared), force a crash from here.
- abort();
+ int size = ::WideCharToMultiByte(CP_UTF8, 0, &source[0],
+ static_cast<int>(source.size()), nullptr, 0,
+ nullptr, nullptr);
+ output.assign(static_cast<size_t>(size), '\0');
+ if (::WideCharToMultiByte(CP_UTF8, 0, &source[0],
+ static_cast<int>(source.size()), &output[0], size,
+ nullptr, nullptr) != size) {
+ return false;
}
-
- if (disable_kill_failsafe_for_testing_)
- return;
-
- // The tgkill() above will take some milliseconds to cause a crash, as it
- // involves the kernel to queue the SIGABRT on the target thread (often the
- // main thread, which is != watchdog thread) and do a scheduling round.
- // If something goes wrong though (the target thread has signals masked or
- // is stuck in an uninterruptible+wakekill syscall) force quit from this
- // thread.
- std::this_thread::sleep_for(std::chrono::seconds(10));
- abort();
+ return true;
}
+#endif // PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
-bool Watchdog::CheckMemory_Locked(uint64_t rss_bytes) {
- if (memory_limit_bytes_ == 0)
+#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
+bool UTF8ToWide(const std::string& source, std::wstring& output) {
+ if (source.empty() ||
+ source.size() > static_cast<size_t>(std::numeric_limits<int>::max())) {
return false;
-
- // Add the current stat value to the ring buffer and check that the mean
- // remains under our threshold.
- if (memory_window_bytes_.Push(rss_bytes)) {
- if (memory_window_bytes_.Mean() >
- static_cast<double>(memory_limit_bytes_)) {
- PERFETTO_ELOG(
- "Memory watchdog trigger. Memory window of %f bytes is above the "
- "%" PRIu64 " bytes limit.",
- memory_window_bytes_.Mean(), memory_limit_bytes_);
- return true;
- }
}
- return false;
-}
-
-bool Watchdog::CheckCpu_Locked(uint64_t cpu_time) {
- if (cpu_limit_percentage_ == 0)
+ int size = ::MultiByteToWideChar(CP_UTF8, 0, &source[0],
+ static_cast<int>(source.size()), nullptr, 0);
+ output.assign(static_cast<size_t>(size), L'\0');
+ if (::MultiByteToWideChar(CP_UTF8, 0, &source[0],
+ static_cast<int>(source.size()), &output[0],
+ size) != size) {
return false;
-
- // Add the cpu time to the ring buffer.
- if (cpu_window_time_ticks_.Push(cpu_time)) {
- // Compute the percentage over the whole window and check that it remains
- // under the threshold.
- uint64_t difference_ticks = cpu_window_time_ticks_.NewestWhenFull() -
- cpu_window_time_ticks_.OldestWhenFull();
- double window_interval_ticks =
- (static_cast<double>(WindowTimeForRingBuffer(cpu_window_time_ticks_)) /
- 1000.0) *
- static_cast<double>(sysconf(_SC_CLK_TCK));
- double percentage = static_cast<double>(difference_ticks) /
- static_cast<double>(window_interval_ticks) * 100;
- if (percentage > cpu_limit_percentage_) {
- PERFETTO_ELOG("CPU watchdog trigger. %f%% CPU use is above the %" PRIu32
- "%% CPU limit.",
- percentage, cpu_limit_percentage_);
- return true;
- }
}
- return false;
+ return true;
}
+#endif // PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
-uint32_t Watchdog::WindowTimeForRingBuffer(const WindowedInterval& window) {
- return static_cast<uint32_t>(window.size() - 1) * polling_interval_ms_;
-}
+size_t SprintfTrunc(char* dst, size_t dst_size, const char* fmt, ...) {
+ if (PERFETTO_UNLIKELY(dst_size == 0))
+ return 0;
-bool Watchdog::WindowedInterval::Push(uint64_t sample) {
- // Add the sample to the current position in the ring buffer.
- buffer_[position_] = sample;
+ va_list args;
+ va_start(args, fmt);
+ int src_size = vsnprintf(dst, dst_size, fmt, args);
+ va_end(args);
- // Update the position with next one circularily.
- position_ = (position_ + 1) % size_;
+ if (PERFETTO_UNLIKELY(src_size <= 0)) {
+ dst[0] = '\0';
+ return 0;
+ }
- // Set the filled flag the first time we wrap.
- filled_ = filled_ || position_ == 0;
- return filled_;
-}
+ size_t res;
+ if (PERFETTO_LIKELY(src_size < static_cast<int>(dst_size))) {
+ // Most common case.
+ res = static_cast<size_t>(src_size);
+ } else {
+ // Truncation case.
+ res = dst_size - 1;
+ }
-double Watchdog::WindowedInterval::Mean() const {
- return MeanForArray(buffer_.get(), size_);
+ PERFETTO_DCHECK(res < dst_size);
+ PERFETTO_DCHECK(dst[res] == '\0');
+ return res;
}
-void Watchdog::WindowedInterval::Clear() {
- position_ = 0;
- buffer_.reset(new uint64_t[size_]());
+std::optional<LineWithOffset> FindLineWithOffset(base::StringView str,
+ uint32_t offset) {
+ static constexpr char kNewLine = '\n';
+ uint32_t line_offset = 0;
+ uint32_t line_count = 1;
+ for (uint32_t i = 0; i < str.size(); ++i) {
+ if (str.at(i) == kNewLine) {
+ line_offset = i + 1;
+ line_count++;
+ continue;
+ }
+ if (i == offset) {
+ size_t end_offset = str.find(kNewLine, i);
+ if (end_offset == std::string::npos) {
+ end_offset = str.size();
+ }
+ base::StringView line = str.substr(line_offset, end_offset - line_offset);
+ return LineWithOffset{line, offset - line_offset, line_count};
+ }
+ }
+ return std::nullopt;
}
-void Watchdog::WindowedInterval::Reset(size_t new_size) {
- position_ = 0;
- size_ = new_size;
- buffer_.reset(new_size == 0 ? nullptr : new uint64_t[new_size]());
-}
+} // namespace base
+} // namespace perfetto
+// gen_amalgamated begin source: src/base/string_view.cc
+/*
+ * 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.
+ */
-Watchdog::Timer::Timer(Watchdog* watchdog,
- uint32_t ms,
- WatchdogCrashReason crash_reason)
- : watchdog_(watchdog) {
- if (!ms)
- return; // No-op timer created when the watchdog is disabled.
+// gen_amalgamated expanded: #include "perfetto/ext/base/string_view.h"
- TimeMillis now_mono = GetWallTimeMs();
- timer_data_.deadline = now_mono + std::chrono::milliseconds(ms);
- timer_data_.ctime_mono = now_mono;
- timer_data_.ctime_boot = GetBootTimeMs();
- timer_data_.ctime_cpu =
- std::chrono::duration_cast<TimeMillis>(GetProcessCPUTimeNs());
- timer_data_.thread_id = GetThreadId();
- timer_data_.crash_reason = crash_reason;
- PERFETTO_DCHECK(watchdog_);
- watchdog_->AddFatalTimer(timer_data_);
-}
+namespace perfetto {
+namespace base {
-Watchdog::Timer::~Timer() {
- if (timer_data_.deadline.count())
- watchdog_->RemoveFatalTimer(timer_data_);
-}
+// Without ignoring this warning we get the message:
+// error: out-of-line definition of constexpr static data member is redundant
+// in C++17 and is deprecated
+// when using clang-cl in Windows.
+#if defined(__GNUC__) // GCC & clang
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wdeprecated"
+#endif // __GNUC__
-Watchdog::Timer::Timer(Timer&& other) noexcept {
- watchdog_ = std::move(other.watchdog_);
- other.watchdog_ = nullptr;
- timer_data_ = std::move(other.timer_data_);
- other.timer_data_ = TimerData();
-}
+// static
+constexpr size_t StringView::npos;
+
+#if defined(__GNUC__)
+#pragma GCC diagnostic pop
+#endif
} // namespace base
} // namespace perfetto
-
-#endif // PERFETTO_BUILDFLAG(PERFETTO_WATCHDOG)
-// gen_amalgamated begin source: src/base/weak_runner.cc
-// gen_amalgamated begin header: include/perfetto/ext/base/weak_runner.h
+// gen_amalgamated begin source: src/base/string_view_splitter.cc
+// gen_amalgamated begin header: include/perfetto/ext/base/string_view_splitter.h
/*
* Copyright (C) 2024 The Android Open Source Project
*
@@ -11393,52 +11888,75 @@ Watchdog::Timer::Timer(Timer&& other) noexcept {
* limitations under the License.
*/
-#ifndef INCLUDE_PERFETTO_EXT_BASE_WEAK_RUNNER_H_
-#define INCLUDE_PERFETTO_EXT_BASE_WEAK_RUNNER_H_
+#ifndef INCLUDE_PERFETTO_EXT_BASE_STRING_VIEW_SPLITTER_H_
+#define INCLUDE_PERFETTO_EXT_BASE_STRING_VIEW_SPLITTER_H_
-#include <stdint.h>
+// gen_amalgamated expanded: #include "perfetto/ext/base/string_view.h"
-#include <functional>
-#include <memory>
+namespace perfetto {
+namespace base {
-namespace perfetto::base {
+// C++ version of strtok(). Splits a StringView without making copies or any
+// heap allocations. Supports the special case of using \0 as a delimiter.
+// The token returned in output are valid as long as the input string is valid.
+class StringViewSplitter {
+ public:
+ // Whether an empty string (two delimiters side-to-side) is a valid token.
+ enum class EmptyTokenMode {
+ DISALLOW_EMPTY_TOKENS,
+ ALLOW_EMPTY_TOKENS,
-class TaskRunner;
+ DEFAULT = DISALLOW_EMPTY_TOKENS,
+ };
-// This is a wrapper around a `base::TaskRunner*`. It is intended to be used by
-// classes that want to post tasks on themselves. When the object is destroyed,
-// all posted tasks become noops.
-//
-// A class that embeds a WeakRunner can safely capture `this` on the posted
-// tasks.
-class WeakRunner {
- public:
- explicit WeakRunner(base::TaskRunner* task_runner);
- ~WeakRunner();
- base::TaskRunner* task_runner() const { return task_runner_; }
+ // Can take ownership of the string if passed via std::move(), e.g.:
+ // StringViewSplitter(std::move(str), '\n');
+ StringViewSplitter(base::StringView,
+ char delimiter,
+ EmptyTokenMode empty_token_mode = EmptyTokenMode::DEFAULT);
- // Schedules `f` for immediate execution. `f` will not be executed is `*this`
- // is destroyed.
- //
- // Can be called from any thread, but the caller needs to make sure that
- // `*this` is alive while `PostTask` is running: this is not obvious when
- // multiple threads are involved.
- void PostTask(std::function<void()> f) const;
+ // Splits the current token from an outer StringViewSplitter instance. This is
+ // to chain splitters as follows: for (base::StringViewSplitter lines(x,
+ // '\n'); ss.Next();)
+ // for (base::StringViewSplitter words(&lines, ' '); words.Next();)
+ StringViewSplitter(StringViewSplitter*,
+ char delimiter,
+ EmptyTokenMode empty_token_mode = EmptyTokenMode::DEFAULT);
- // Schedules `f` for execution after |delay_ms|.
- // Can be called from any thread, but the caller needs to make sure that
- // `*this` is alive while `PostDelayedTask` is running: this is not obvious
- // when multiple threads are involved.
- void PostDelayedTask(std::function<void()> f, uint32_t delay_ms) const;
+ // Returns true if a token is found (in which case it will be stored in
+ // cur_token()), false if no more tokens are found.
+ bool Next();
+
+ // Returns the next token if, found (in which case it will be stored in
+ // cur_token()), and the empty string if no more tokens are found.
+ base::StringView NextToken() { return Next() ? cur_token() : ""; }
+
+ // Returns the current token iff last call to Next() returned true.
+ // In all other cases (before the 1st call to Next() and after Next() returns
+ // false) returns the empty string.
+ base::StringView cur_token() { return cur_; }
+
+ // Returns the remainder of the current input string that has not yet been
+ // tokenized.
+ base::StringView remainder() { return next_; }
private:
- base::TaskRunner* const task_runner_;
- std::shared_ptr<bool> destroyed_;
+ StringViewSplitter(const StringViewSplitter&) = delete;
+ StringViewSplitter& operator=(const StringViewSplitter&) = delete;
+ void Initialize(base::StringView);
+
+ base::StringView str_;
+ base::StringView cur_;
+ base::StringView next_;
+ bool end_of_input_;
+ const char delimiter_;
+ const EmptyTokenMode empty_token_mode_;
};
-} // namespace perfetto::base
+} // namespace base
+} // namespace perfetto
-#endif // INCLUDE_PERFETTO_EXT_BASE_WEAK_RUNNER_H_
+#endif // INCLUDE_PERFETTO_EXT_BASE_STRING_VIEW_SPLITTER_H_
/*
* Copyright (C) 2024 The Android Open Source Project
*
@@ -11455,46 +11973,92 @@ class WeakRunner {
* limitations under the License.
*/
-// gen_amalgamated expanded: #include "perfetto/ext/base/weak_runner.h"
+// gen_amalgamated expanded: #include "perfetto/ext/base/string_view_splitter.h"
-// gen_amalgamated expanded: #include "perfetto/base/task_runner.h"
+#include <utility>
-namespace perfetto::base {
+// gen_amalgamated expanded: #include "perfetto/base/logging.h"
-WeakRunner::WeakRunner(base::TaskRunner* task_runner)
- : task_runner_(task_runner), destroyed_(std::make_shared<bool>(false)) {}
+namespace perfetto {
+namespace base {
-WeakRunner::~WeakRunner() {
- *destroyed_ = true;
+StringViewSplitter::StringViewSplitter(base::StringView str,
+ char delimiter,
+ EmptyTokenMode empty_token_mode)
+ : str_(std::move(str)),
+ delimiter_(delimiter),
+ empty_token_mode_(empty_token_mode) {
+ Initialize(str);
}
-void WeakRunner::PostTask(std::function<void()> f) const {
- task_runner_->PostTask([destroyed = destroyed_, f = std::move(f)]() {
- if (*destroyed) {
- return;
- }
- f();
- });
+StringViewSplitter::StringViewSplitter(StringViewSplitter* outer,
+ char delimiter,
+ EmptyTokenMode empty_token_mode)
+ : delimiter_(delimiter), empty_token_mode_(empty_token_mode) {
+ Initialize(outer->cur_token());
}
-void WeakRunner::PostDelayedTask(std::function<void()> f,
- uint32_t delay_ms) const {
- task_runner_->PostDelayedTask(
- [destroyed = destroyed_, f = std::move(f)]() {
- if (*destroyed) {
- return;
- }
- f();
- },
- delay_ms);
+void StringViewSplitter::Initialize(base::StringView str) {
+ next_ = str;
+ cur_ = "";
+ end_of_input_ = false;
}
-} // namespace perfetto::base
-// gen_amalgamated begin source: src/base/lock_free_task_runner.cc
-// gen_amalgamated begin header: include/perfetto/ext/base/lock_free_task_runner.h
-// gen_amalgamated begin header: include/perfetto/ext/base/flags.h
+bool StringViewSplitter::Next() {
+ if (end_of_input_) {
+ cur_ = next_ = "";
+ return false;
+ }
+
+ size_t substr_start = 0;
+ if (empty_token_mode_ == EmptyTokenMode::DISALLOW_EMPTY_TOKENS) {
+ while (substr_start < next_.size() &&
+ next_.at(substr_start) == delimiter_) {
+ substr_start++;
+ }
+ }
+
+ if (substr_start >= next_.size()) {
+ end_of_input_ = true;
+ cur_ = next_ = "";
+ return !cur_.empty() ||
+ empty_token_mode_ == EmptyTokenMode::ALLOW_EMPTY_TOKENS;
+ }
+
+ size_t delimiter_start = next_.find(delimiter_, substr_start);
+ if (delimiter_start == base::StringView::npos) {
+ cur_ = next_.substr(substr_start);
+ next_ = "";
+ end_of_input_ = true;
+ return !cur_.empty() ||
+ empty_token_mode_ == EmptyTokenMode::ALLOW_EMPTY_TOKENS;
+ }
+
+ size_t delimiter_end = delimiter_start + 1;
+
+ if (empty_token_mode_ == EmptyTokenMode::DISALLOW_EMPTY_TOKENS) {
+ while (delimiter_end < next_.size() &&
+ next_.at(delimiter_end) == delimiter_) {
+ delimiter_end++;
+ }
+ if (delimiter_end >= next_.size()) {
+ end_of_input_ = true;
+ }
+ }
+
+ cur_ = next_.substr(substr_start, delimiter_start - substr_start);
+ next_ = next_.substr(delimiter_end);
+
+ return !cur_.empty() ||
+ empty_token_mode_ == EmptyTokenMode::ALLOW_EMPTY_TOKENS;
+}
+
+} // namespace base
+} // namespace perfetto
+// gen_amalgamated begin source: src/base/temp_file.cc
+// gen_amalgamated begin header: include/perfetto/ext/base/temp_file.h
/*
- * Copyright (C) 2025 The Android Open Source Project
+ * 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.
@@ -11509,36 +12073,80 @@ void WeakRunner::PostDelayedTask(std::function<void()> f,
* limitations under the License.
*/
-#ifndef INCLUDE_PERFETTO_EXT_BASE_FLAGS_H_
-#define INCLUDE_PERFETTO_EXT_BASE_FLAGS_H_
+#ifndef INCLUDE_PERFETTO_EXT_BASE_TEMP_FILE_H_
+#define INCLUDE_PERFETTO_EXT_BASE_TEMP_FILE_H_
-// gen_amalgamated expanded: #include "perfetto/base/build_config.h"
+#include <string>
-#if PERFETTO_BUILDFLAG(PERFETTO_ANDROID_BUILD) && \
- PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID)
-// Android: aconfig generates PERFETTO_FLAGS_* macros in perfetto_flags.h
-#include <perfetto_flags.h>
-#else
-// Non-Android: Define fallback PERFETTO_FLAGS_* macros
-// These match the pattern from Android's aconfig codegen
-#define PERFETTO_FLAGS(FLAG) PERFETTO_FLAGS_##FLAG
+// gen_amalgamated expanded: #include "perfetto/ext/base/scoped_file.h"
+// gen_amalgamated expanded: #include "perfetto/ext/base/status_or.h"
-#define PERFETTO_FLAGS_TEST_READ_ONLY_FLAG false
-#define PERFETTO_FLAGS_USE_LOCKFREE_TASKRUNNER \
- PERFETTO_BUILDFLAG(PERFETTO_ENABLE_LOCKFREE_TASKRUNNER)
-#define PERFETTO_FLAGS_BUFFER_CLONE_PRESERVE_READ_ITER true
-#define PERFETTO_FLAGS_USE_UNIX_SOCKET_INOTIFY \
- PERFETTO_BUILDFLAG(PERFETTO_ENABLE_SOCK_INOTIFY)
-#define PERFETTO_FLAGS_TRIGGER_PERFETTO_ON_TRACED_PROBES_DISCONNECT false
-#define PERFETTO_FLAGS_USE_PCRE2 PERFETTO_BUILDFLAG(PERFETTO_PCRE2)
-#define PERFETTO_FLAGS_SYS_STATS_LARGE_READ true
+namespace perfetto {
+namespace base {
-#endif // PERFETTO_BUILDFLAG(PERFETTO_ANDROID_BUILD) && ...
+std::string GetSysTempDir();
-#endif // INCLUDE_PERFETTO_EXT_BASE_FLAGS_H_
-// gen_amalgamated begin header: include/perfetto/ext/base/unix_task_runner.h
+class TempFile {
+ public:
+ enum class LinkMode { kLinked, kUnlinked };
+
+ // Creates a temporary file.
+ // If |mode| is kUnlinked, unlinks the file before returning, keeping fd()
+ // open and leaving path() empty.
+ // Returns an error status if creation or unlinking fails.
+ static StatusOr<TempFile> Create(LinkMode mode = LinkMode::kLinked);
+
+ TempFile(TempFile&&) noexcept;
+ TempFile& operator=(TempFile&&);
+ ~TempFile();
+
+ const std::string& path() const { return path_; }
+ int fd() const { return *fd_; }
+ int operator*() const { return *fd_; }
+
+ // Unlinks the file and clears path(), keeping fd() open.
+ // Returns true on success, or if the file is already unlinked.
+ // On failure, returns false and leaves path() unchanged.
+ bool Unlink();
+
+ // Unlinks the file if needed and transfers ownership of its descriptor to
+ // the caller.
+ // Aborts if unlinking fails.
+ ScopedFile ReleaseFD();
+
+ private:
+ TempFile(ScopedFile fd, std::string path);
+ TempFile(const TempFile&) = delete;
+ TempFile& operator=(const TempFile&) = delete;
+
+ ScopedFile fd_;
+ std::string path_;
+};
+
+class TempDir {
+ public:
+ static TempDir Create();
+
+ TempDir(TempDir&&) noexcept;
+ TempDir& operator=(TempDir&&);
+ ~TempDir();
+
+ const std::string& path() const { return path_; }
+
+ private:
+ TempDir();
+ TempDir(const TempDir&) = delete;
+ TempDir& operator=(const TempDir&) = delete;
+
+ std::string path_;
+};
+
+} // namespace base
+} // namespace perfetto
+
+#endif // INCLUDE_PERFETTO_EXT_BASE_TEMP_FILE_H_
/*
- * Copyright (C) 2017 The Android Open Source Project
+ * 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.
@@ -11553,131 +12161,177 @@ void WeakRunner::PostDelayedTask(std::function<void()> f,
* limitations under the License.
*/
-#ifndef INCLUDE_PERFETTO_EXT_BASE_UNIX_TASK_RUNNER_H_
-#define INCLUDE_PERFETTO_EXT_BASE_UNIX_TASK_RUNNER_H_
+// gen_amalgamated expanded: #include "perfetto/ext/base/temp_file.h"
// gen_amalgamated expanded: #include "perfetto/base/build_config.h"
-// gen_amalgamated expanded: #include "perfetto/base/task_runner.h"
-// gen_amalgamated expanded: #include "perfetto/base/thread_annotations.h"
-// gen_amalgamated expanded: #include "perfetto/base/thread_utils.h"
-// gen_amalgamated expanded: #include "perfetto/base/time.h"
-// gen_amalgamated expanded: #include "perfetto/ext/base/event_fd.h"
-// gen_amalgamated expanded: #include "perfetto/ext/base/rt_mutex.h"
-// gen_amalgamated expanded: #include "perfetto/ext/base/scoped_file.h"
-// gen_amalgamated expanded: #include "perfetto/ext/base/thread_checker.h"
-#include <chrono>
-#include <deque>
-#include <map>
-#include <mutex>
-#include <vector>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
-#if !PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
-#include <poll.h>
+#include <utility>
+
+#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
+#include <windows.h>
+
+#include <direct.h>
+#include <fileapi.h>
+#include <io.h>
+#else
+#include <unistd.h>
#endif
+// gen_amalgamated expanded: #include "perfetto/base/logging.h"
+// gen_amalgamated expanded: #include "perfetto/ext/base/file_utils.h"
+// gen_amalgamated expanded: #include "perfetto/ext/base/status_macros.h"
+// gen_amalgamated expanded: #include "perfetto/ext/base/string_utils.h"
+
namespace perfetto {
namespace base {
-// Runs a task runner on the current thread.
-//
-// Implementation note: we currently assume (and enforce in debug builds) that
-// Run() is called from the thread that constructed the UnixTaskRunner. This is
-// not strictly necessary, and we could instead track the thread that invokes
-// Run(). However, a related property that *might* be important to enforce is
-// that the destructor runs on the task-running thread. Otherwise, if there are
-// still-pending tasks at the time of destruction, we would destroy those
-// outside of the task thread (which might be unexpected to the caller). On the
-// other hand, the std::function task interface discourages use of any
-// resource-owning tasks (as the callable needs to be copyable), so this might
-// not be important in practice.
-//
-// TODO(rsavitski): consider adding a thread-check in the destructor, after
-// auditing existing usages.
-// TODO(primiano): rename this to TaskRunnerImpl. The "Unix" part is misleading
-// now as it supports also Windows.
-class UnixTaskRunner : public TaskRunner {
- public:
- UnixTaskRunner();
- ~UnixTaskRunner() override;
-
- // Start executing tasks. Doesn't return until Quit() is called. Run() may be
- // called multiple times on the same task runner.
- void Run();
- void Quit();
-
- // Checks whether there are any pending immediate tasks to run. Note that
- // delayed tasks don't count even if they are due to run.
- bool IsIdleForTesting();
+namespace {
- // Pretends (for the purposes of running delayed tasks) that time advanced by
- // `ms`.
- void AdvanceTimeForTesting(uint32_t ms);
+#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
+StatusOr<std::string> GetTempFilePathWin() {
+ std::string path = GetSysTempDir() + "\\perfetto-XXXXXX";
+ int error = _mktemp_s(path.data(), path.size() + 1);
+ if (error != 0)
+ return ErrStatus("_mktemp_s() failed: %s", strerror(error));
+ return path;
+}
+#endif
- // TaskRunner implementation:
- void PostTask(std::function<void()>) override;
- void PostDelayedTask(std::function<void()>, uint32_t delay_ms) override;
- void AddFileDescriptorWatch(PlatformHandle, std::function<void()>) override;
- void RemoveFileDescriptorWatch(PlatformHandle) override;
- bool RunsTasksOnCurrentThread() const override;
+Status UnlinkTempFile(const std::string& path) {
+#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
+ // If the file is still open, deletion completes when its last handle closes.
+ if (!DeleteFileA(path.c_str())) {
+ return ErrStatus("DeleteFileA(%s) failed: %lu", path.c_str(),
+ GetLastError());
+ }
+#else
+ if (unlink(path.c_str()) != 0)
+ return ErrStatus("unlink(%s) failed: %s", path.c_str(), strerror(errno));
+#endif
+ return OkStatus();
+}
- // Returns true if the task runner is quitting, or has quit and hasn't been
- // restarted since. Exposed primarily for ThreadTaskRunner, not necessary for
- // normal use of this class.
- bool QuitCalled();
+} // namespace
- private:
- void WakeUp();
- void UpdateWatchTasksLocked() PERFETTO_EXCLUSIVE_LOCKS_REQUIRED(lock_);
- int GetDelayMsToNextTaskLocked() const
- PERFETTO_EXCLUSIVE_LOCKS_REQUIRED(lock_);
- void RunImmediateAndDelayedTask();
- void PostFileDescriptorWatches(uint64_t windows_wait_result);
- void RunFileDescriptorWatch(PlatformHandle);
+std::string GetSysTempDir() {
+ const char* tmpdir = nullptr;
+#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
+ if ((tmpdir = getenv("TMP")))
+ return tmpdir;
+ if ((tmpdir = getenv("TEMP")))
+ return tmpdir;
+ return "C:\\TEMP";
+#else
+ if ((tmpdir = getenv("TMPDIR")))
+ return base::StripSuffix(tmpdir, "/");
+#if PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID)
+ return "/data/local/tmp";
+#else
+ return "/tmp";
+#endif // !OS_ANDROID
+#endif // !OS_WIN
+}
- ThreadChecker thread_checker_;
- std::atomic<PlatformThreadId> created_thread_id_ = GetThreadId();
+// static
+StatusOr<TempFile> TempFile::Create(LinkMode mode) {
+#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
+ ASSIGN_OR_RETURN(std::string path, GetTempFilePathWin());
- EventFd event_;
+ // TempFile exposes both a descriptor and a path. Match POSIX by allowing the
+ // path to be reopened while the descriptor remains open. These sharing flags
+ // are not settable through _open(), hence the CreateFileA +
+ // _open_osfhandle dance.
+ ScopedPlatformHandle h(
+ ::CreateFileA(path.c_str(), GENERIC_READ | GENERIC_WRITE,
+ FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,
+ nullptr, CREATE_ALWAYS, FILE_ATTRIBUTE_TEMPORARY, nullptr));
+ if (!h) {
+ return ErrStatus("CreateFileA(%s) failed: %lu", path.c_str(),
+ GetLastError());
+ }
-// The array of fds/handles passed to poll(2) / WaitForMultipleObjects().
-#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
- std::vector<PlatformHandle> poll_fds_;
+ // According to MSDN, when using _open_osfhandle the caller must not call
+ // CloseHandle(). Ownership is moved to the file descriptor, which then needs
+ // to be closed with just with _close().
+ ScopedFile fd(_open_osfhandle(reinterpret_cast<intptr_t>(h.get()), 0));
+ if (!fd) {
+ auto status = ErrStatus("_open_osfhandle() failed: %s", strerror(errno));
+ UnlinkTempFile(path); // Best effort.
+ return status;
+ }
+ h.release();
#else
- std::vector<struct pollfd> poll_fds_;
+ std::string path = GetSysTempDir() + "/perfetto-XXXXXXXX";
+ ScopedFile fd(mkstemp(path.data()));
+ if (!fd)
+ return ErrStatus("mkstemp(%s) failed: %s", path.c_str(), strerror(errno));
#endif
- base::MaybeRtMutex lock_;
+ // Transfer ownership to TempFile only once all fallible operations succeed,
+ // because ~TempFile() aborts if unlinking fails.
+ if (mode == LinkMode::kUnlinked) {
+ RETURN_IF_ERROR(UnlinkTempFile(path));
+ return TempFile(std::move(fd), std::string());
+ }
+ return TempFile(std::move(fd), std::move(path));
+}
- std::deque<std::function<void()>> immediate_tasks_ PERFETTO_GUARDED_BY(lock_);
- std::multimap<TimeMillis, std::function<void()>> delayed_tasks_
- PERFETTO_GUARDED_BY(lock_);
- bool quit_ PERFETTO_GUARDED_BY(lock_) = false;
- TimeMillis advanced_time_for_testing_ PERFETTO_GUARDED_BY(lock_) =
- TimeMillis(0);
+TempFile::TempFile(ScopedFile fd, std::string path)
+ : fd_(std::move(fd)), path_(std::move(path)) {}
- struct WatchTask {
- std::function<void()> callback;
+TempFile::~TempFile() {
+ PERFETTO_CHECK(Unlink());
+}
+
+ScopedFile TempFile::ReleaseFD() {
+ PERFETTO_CHECK(Unlink());
+ return std::move(fd_);
+}
+
+bool TempFile::Unlink() {
+ if (path_.empty())
+ return true;
+ if (!UnlinkTempFile(path_).ok())
+ return false;
+ path_.clear();
+ return true;
+}
+
+TempFile::TempFile(TempFile&&) noexcept = default;
+TempFile& TempFile::operator=(TempFile&&) = default;
+
+// static
+TempDir TempDir::Create() {
+ TempDir temp_dir;
#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
- // On UNIX systems we make the FD number negative in |poll_fds_| to avoid
- // polling it again until the queued task runs. On Windows we can't do that.
- // Instead we keep track of its state here.
- bool pending = false;
+ temp_dir.path_ = GetTempFilePathWin().ValueOrDie();
+ PERFETTO_CHECK(_mkdir(temp_dir.path_.c_str()) == 0);
#else
- size_t poll_fd_index; // Index into |poll_fds_|.
+ temp_dir.path_ = GetSysTempDir() + "/perfetto-XXXXXXXX";
+ PERFETTO_CHECK(mkdtemp(&temp_dir.path_[0]));
#endif
- };
+ return temp_dir;
+}
- std::map<PlatformHandle, WatchTask> watch_tasks_ PERFETTO_GUARDED_BY(lock_);
- bool watch_tasks_changed_ PERFETTO_GUARDED_BY(lock_) = false;
-};
+TempDir::TempDir() = default;
+TempDir::TempDir(TempDir&&) noexcept = default;
+TempDir& TempDir::operator=(TempDir&&) = default;
+
+TempDir::~TempDir() {
+ if (path_.empty())
+ return; // For objects that get std::move()d.
+ PERFETTO_CHECK(Rmdir(path_));
+}
} // namespace base
} // namespace perfetto
-
-#endif // INCLUDE_PERFETTO_EXT_BASE_UNIX_TASK_RUNNER_H_
+// gen_amalgamated begin source: src/base/thread_checker.cc
/*
- * Copyright (C) 2025 The Android Open Source Project
+ * 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.
@@ -11692,272 +12346,151 @@ class UnixTaskRunner : public TaskRunner {
* limitations under the License.
*/
-#ifndef INCLUDE_PERFETTO_EXT_BASE_LOCK_FREE_TASK_RUNNER_H_
-#define INCLUDE_PERFETTO_EXT_BASE_LOCK_FREE_TASK_RUNNER_H_
-
-// gen_amalgamated expanded: #include "perfetto/base/flat_set.h"
-// gen_amalgamated expanded: #include "perfetto/base/task_runner.h"
-// gen_amalgamated expanded: #include "perfetto/base/thread_annotations.h"
-// gen_amalgamated expanded: #include "perfetto/base/time.h"
-// gen_amalgamated expanded: #include "perfetto/ext/base/event_fd.h"
-// gen_amalgamated expanded: #include "perfetto/ext/base/flags.h"
-// gen_amalgamated expanded: #include "perfetto/ext/base/scoped_file.h"
-// gen_amalgamated expanded: #include "perfetto/ext/base/unix_task_runner.h"
+// gen_amalgamated expanded: #include "perfetto/ext/base/thread_checker.h"
-#if !PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
-#include <poll.h>
+#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
+#include <windows.h>
#endif
-#include <array>
-#include <atomic>
-#include <thread>
-#include <unordered_map>
-
namespace perfetto {
namespace base {
-namespace task_runner_internal {
-class ScopedRefcount;
-struct Slab;
+namespace {
+constexpr ThreadID kDetached{};
-// Exposed for testing
-constexpr uint32_t kNumRefcountBuckets = 32;
-constexpr size_t kSlabSize = 512;
+ThreadID CurrentThreadId() {
+#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
+ return ::GetCurrentThreadId();
+#else
+ return pthread_self();
+#endif
+}
+} // namespace
-} // namespace task_runner_internal
+ThreadChecker::ThreadChecker() {
+ thread_id_.store(CurrentThreadId());
+}
-template <typename T>
-class TaskRunnerTest;
+ThreadChecker::~ThreadChecker() = default;
-// This class implements a lock-less multi-producer single-consumer task runner.
-// This is achieved by using a linked list of "slabs". Each slab is a fixed-size
-// array of tasks.
-// See /docs/design-docs/lock-free-task-runner.md for more details
-class PERFETTO_EXPORT_COMPONENT LockFreeTaskRunner : public TaskRunner {
- public:
- LockFreeTaskRunner();
- ~LockFreeTaskRunner() override;
+ThreadChecker::ThreadChecker(const ThreadChecker& other)
+ : thread_id_(other.thread_id_.load()) {}
- void Run();
- void Quit();
+ThreadChecker& ThreadChecker::operator=(const ThreadChecker& other) {
+ thread_id_ = other.thread_id_.load();
+ return *this;
+}
- // Checks whether there are any pending immediate tasks to run. Note that
- // delayed tasks don't count even if they are due to run.
- bool IsIdleForTesting();
+bool ThreadChecker::CalledOnValidThread() const {
+ auto self = CurrentThreadId();
- // TaskRunner implementation:
- void PostTask(std::function<void()>) override;
- void PostDelayedTask(std::function<void()>, uint32_t delay_ms) override;
- void AddFileDescriptorWatch(PlatformHandle, std::function<void()>) override;
- void RemoveFileDescriptorWatch(PlatformHandle) override;
- bool RunsTasksOnCurrentThread() const override;
+ // Will re-attach if previously detached using DetachFromThread().
+ auto prev_value = kDetached;
+ if (thread_id_.compare_exchange_strong(prev_value, self))
+ return true;
+ return prev_value == self;
+}
- // Pretends (for the purposes of running delayed tasks) that time advanced by
- // `ms`.
- void AdvanceTimeForTesting(uint32_t ms);
+void ThreadChecker::DetachFromThread() {
+ thread_id_.store(kDetached);
+}
- // Stats for testing.
- size_t slabs_allocated() const {
- return slabs_allocated_.load(std::memory_order_relaxed);
- }
- size_t slabs_freed() const {
- return slabs_freed_.load(std::memory_order_relaxed);
- }
+} // namespace base
+} // namespace perfetto
+// gen_amalgamated begin source: src/base/thread_utils.cc
+// gen_amalgamated begin header: include/perfetto/ext/base/thread_utils.h
+/*
+ * 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.
+ */
- private:
- using Slab = task_runner_internal::Slab;
- using ScopedRefcount = task_runner_internal::ScopedRefcount;
- friend class task_runner_internal::ScopedRefcount;
+#ifndef INCLUDE_PERFETTO_EXT_BASE_THREAD_UTILS_H_
+#define INCLUDE_PERFETTO_EXT_BASE_THREAD_UTILS_H_
- struct DelayedTask {
- TimeMillis time;
- uint64_t seq;
- std::function<void()> task;
+#include <string>
- // Note that the < operator keeps the DelayedTasks sorted in reverse order
- // (the latest one is first, the earliest one is last). This is so we can
- // have a FIFO queue using a vector by just doing an O(1) pop_back().
- bool operator<(const DelayedTask& other) const {
- if (time != other.time)
- return time > other.time;
- return seq > other.seq;
- }
- bool operator==(const DelayedTask& other) const {
- return time == other.time && seq == other.seq;
- }
- };
+// gen_amalgamated expanded: #include "perfetto/base/build_config.h"
+// gen_amalgamated expanded: #include "perfetto/base/export.h"
+// gen_amalgamated expanded: #include "perfetto/ext/base/string_utils.h"
- PERFETTO_ALWAYS_INLINE std::function<void()> PopNextImmediateTask();
- std::function<void()> PopTaskRecursive(Slab*, Slab* next_slab);
- std::function<void()> PopNextExpiredDelayedTask();
- int GetDelayMsToNextTask() const;
- void WakeUp() { wakeup_event_.Notify(); }
- Slab* AllocNewSlab();
- void DeleteSlab(Slab*);
- void PostFileDescriptorWatches(uint64_t windows_wait_result);
- void RunFileDescriptorWatch(PlatformHandle);
- void UpdateWatchTasks();
+#if PERFETTO_BUILDFLAG(PERFETTO_OS_LINUX) || \
+ PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID) || \
+ PERFETTO_BUILDFLAG(PERFETTO_OS_APPLE)
+#include <pthread.h>
+#include <string.h>
+#include <algorithm>
+#endif
- // These two are semantically a unique_ptr, but are accessed from different
- // threads.
- std::atomic<Slab*> tail_{}; // This is never null.
- std::atomic<Slab*> free_slab_{};
+#if PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID)
+#include <sys/prctl.h>
+#endif
- EventFd wakeup_event_;
- bool quit_ = false;
- std::thread::id run_task_thread_id_;
+// Internal implementation utils that aren't as widely useful/supported as
+// base/thread_utils.h.
- // Delayed tasks, accessed only by the main thread. Items are stored in
- // reverse temporal order, see comment in the operator<.
- FlatSet<DelayedTask> delayed_tasks_;
- uint64_t next_delayed_task_seq_ = 0;
- std::atomic<uint32_t> advanced_time_for_testing_{};
+namespace perfetto {
+namespace base {
- // The array of fds/handles passed to poll(2) / WaitForMultipleObjects().
-#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
- std::vector<PlatformHandle> poll_fds_;
+#if PERFETTO_BUILDFLAG(PERFETTO_OS_LINUX) || \
+ PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID) || \
+ PERFETTO_BUILDFLAG(PERFETTO_OS_APPLE)
+// Sets the "comm" of the calling thread to the first 15 chars of the given
+// string.
+inline bool MaybeSetThreadName(const std::string& name) {
+ char buf[16] = {};
+ StringCopy(buf, name.c_str(), sizeof(buf));
+
+#if PERFETTO_BUILDFLAG(PERFETTO_OS_APPLE)
+ return pthread_setname_np(buf) == 0;
#else
- std::vector<struct pollfd> poll_fds_;
+ return pthread_setname_np(pthread_self(), buf) == 0;
#endif
+}
- struct WatchTask {
- std::function<void()> callback;
-#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
- // On UNIX systems we make the FD number negative in |poll_fds_| to avoid
- // polling it again until the queued task runs. On Windows we can't do that.
- // Instead we keep track of its state here.
- bool pending = false;
+inline bool GetThreadName(std::string& out_result) {
+ char buf[16] = {};
+#if PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID)
+ if (prctl(PR_GET_NAME, buf) != 0)
+ return false;
#else
- size_t poll_fd_index; // Index into |poll_fds_|.
+ if (pthread_getname_np(pthread_self(), buf, sizeof(buf)) != 0)
+ return false;
#endif
- };
-
- // Accessed only from the main thread.
- std::unordered_map<PlatformHandle, WatchTask> watch_tasks_;
- bool watch_tasks_changed_ = false;
-
- // An array of 32 refcount buckets. Every Slab* maps to a bucket via a hash
- // function. Every PostTask() thread increases the refcount before accessing
- // a slab, and decreases it when done.
- // This allows the Run() main thread to tell if any thread has possibly been
- // able to observe the Slab through the tail_ before deleting it.
- std::array<std::atomic<int32_t>, task_runner_internal::kNumRefcountBuckets>
- refcounts_{};
-
- // Stats for testing.
- std::atomic<size_t> slabs_allocated_{};
- std::atomic<size_t> slabs_freed_{};
-};
-
-namespace task_runner_internal {
-
-// Returns the index of the refcount_ bucket for the passed Slab pointer.
-static uint32_t HashSlabPtr(Slab* slab) {
- // This is a SplitMix64 hash, which is very fast and effective with pointers
- // (See the test LockFreeTaskRunnerTest.HashSpreading).
- uint64_t u = reinterpret_cast<uintptr_t>(slab);
- u &= 0x00FFFFFFFFFFFFFFull; // Clear asan/MTE top byte for tagged pointers.
- u += 0x9E3779B97F4A7C15ull;
- u = (u ^ (u >> 30)) * 0xBF58476D1CE4E5B9ull;
- u = (u ^ (u >> 27)) * 0x94D049BB133111EBull;
- return static_cast<uint32_t>((u ^ (u >> 31)) % kNumRefcountBuckets);
+ out_result = std::string(buf);
+ return true;
}
-// A slab is a fixed-size array of tasks. The lifecycle of a task slot
-// within a slab goes through three phases:
-//
-// 1. Reservation: A writer thread atomically increments `next_task_slot` to
-// reserve a slot in the `tasks` array. This reservation establishes the
-// implicit order in which the consumer will attempt to read tasks (but
-// only if they are published in the bitmap, see below).
-//
-// 2. Publishing: After writing the task into its reserved slot, the writer
-// thread atomically sets the corresponding bit in the `tasks_written`
-// bitmask. This acts as a memory barrier and makes the task visible to
-// the consumer (main) thread.
-//
-// 3. Consumption: The main thread acquire-reads the `tasks_written` bitmask.
-// For each bit that is set, it processes the task and then sets the
-// corresponding bit in its private `tasks_read` bitmask to prevent
-// reading the same task again.
-struct Slab {
- Slab();
- ~Slab();
-
- std::atomic<size_t> next_task_slot{0};
-
- // `tasks` and `next_task_slot` are accessed by writer threads only.
- // The main thread can access `tasks[i]` but only after ensuring that the
- // corresponding bit in `tasks_written` is set.
- std::array<std::function<void()>, kSlabSize> tasks{};
-
- // A bitmask indicating which tasks in the `tasks` array have been written
- // and are ready to be read by the main thread.
- // This is atomically updated by writer threads and read by the main thread.
- using BitWord = size_t;
- static constexpr size_t kBitsPerWord = sizeof(BitWord) * 8;
- static constexpr size_t kNumWords = kSlabSize / kBitsPerWord;
- std::array<std::atomic<BitWord>, kNumWords> tasks_written{};
-
- // A bitmask indicating which tasks have been read by the main thread.
- // This is accessed only by the main thread, so no atomicity is required.
- std::array<BitWord, kNumWords> tasks_read{};
-
- // The link to the previous slab.
- // This is written by writer threads when they create a new slab and link it
- // to the previous tail. But they do so when nobody else can see the Slab,
- // so there is no need for an atomic ptr. After the initial creation,
- // this is accessed only by the main thread when:
- // 1. draining tasks (to walk back to the oldest slab)
- // 2. deleting slabs, setting it to nullptr, when they are fully consumed.
- Slab* prev = nullptr;
-};
-
-class ScopedRefcount {
- public:
- ScopedRefcount(LockFreeTaskRunner* tr, LockFreeTaskRunner::Slab* slab) {
- bucket_ = &tr->refcounts_[HashSlabPtr(slab)];
- auto prev_value = bucket_->fetch_add(1);
- PERFETTO_DCHECK(prev_value >= 0);
- }
-
- ~ScopedRefcount() {
- if (bucket_) {
- auto prev_value = bucket_->fetch_sub(1);
- PERFETTO_DCHECK(prev_value > 0);
- }
- }
-
- ScopedRefcount(ScopedRefcount&& other) noexcept {
- bucket_ = other.bucket_;
- other.bucket_ = nullptr;
- }
-
- ScopedRefcount& operator=(ScopedRefcount&& other) noexcept {
- this->~ScopedRefcount();
- new (this) ScopedRefcount(std::move(other));
- return *this;
- }
-
- ScopedRefcount(const ScopedRefcount&) = delete;
- ScopedRefcount& operator=(const ScopedRefcount&) = delete;
+#elif PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
- std::atomic<int32_t>* bucket_{};
-};
-} // namespace task_runner_internal
+PERFETTO_EXPORT_COMPONENT bool MaybeSetThreadName(const std::string& name);
+PERFETTO_EXPORT_COMPONENT bool GetThreadName(std::string& out_result);
-using MaybeLockFreeTaskRunner =
- std::conditional_t<PERFETTO_FLAGS(USE_LOCKFREE_TASKRUNNER),
- LockFreeTaskRunner,
- UnixTaskRunner>;
+#else
+inline bool MaybeSetThreadName(const std::string&) {
+ return false;
+}
+inline bool GetThreadName(std::string&) {
+ return false;
+}
+#endif
} // namespace base
} // namespace perfetto
-#endif // INCLUDE_PERFETTO_EXT_BASE_LOCK_FREE_TASK_RUNNER_H_
-// gen_amalgamated begin header: include/perfetto/ext/base/bits.h
+#endif // INCLUDE_PERFETTO_EXT_BASE_THREAD_UTILS_H_
/*
- * Copyright (C) 2025 The Android Open Source Project
+ * 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.
@@ -11972,93 +12505,89 @@ using MaybeLockFreeTaskRunner =
* limitations under the License.
*/
-#ifndef INCLUDE_PERFETTO_EXT_BASE_BITS_H_
-#define INCLUDE_PERFETTO_EXT_BASE_BITS_H_
-
-#include <cstddef>
-#include <cstdint>
+// gen_amalgamated expanded: #include "perfetto/base/thread_utils.h"
+// gen_amalgamated expanded: #include "perfetto/ext/base/thread_utils.h"
// gen_amalgamated expanded: #include "perfetto/base/build_config.h"
-// gen_amalgamated expanded: #include "perfetto/base/compiler.h"
-#if PERFETTO_BUILDFLAG(PERFETTO_X64_CPU_OPT)
-#include <immintrin.h>
+#if PERFETTO_BUILDFLAG(PERFETTO_OS_FUCHSIA)
+#include <zircon/process.h>
+#include <zircon/syscalls.h>
+#include <zircon/types.h>
+#elif PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
+#include <windows.h>
#endif
namespace perfetto {
namespace base {
-inline PERFETTO_ALWAYS_INLINE uint32_t CountLeadZeros32(uint32_t value) {
-#if PERFETTO_BUILDFLAG(PERFETTO_X64_CPU_OPT)
- return static_cast<uint32_t>(_lzcnt_u32(value));
-#elif defined(__GNUC__) || defined(__clang__)
- return value ? static_cast<uint32_t>(__builtin_clz(value)) : 32u;
-#else
- unsigned long out;
- return _BitScanReverse(&out, value) ? 31 - out : 32u;
-#endif
+#if PERFETTO_BUILDFLAG(PERFETTO_OS_FUCHSIA)
+static PlatformThreadId ResolveThreadId() {
+ zx_info_handle_basic_t basic;
+ return (zx_object_get_info(zx_thread_self(), ZX_INFO_HANDLE_BASIC, &basic,
+ sizeof(basic), nullptr, nullptr) == ZX_OK)
+ ? basic.koid
+ : ZX_KOID_INVALID;
}
-
-inline PERFETTO_ALWAYS_INLINE uint32_t CountLeadZeros64(uint64_t value) {
-#if PERFETTO_BUILDFLAG(PERFETTO_X64_CPU_OPT)
- return static_cast<uint32_t>(_lzcnt_u64(value));
-#elif defined(__GNUC__) || defined(__clang__)
- return value ? static_cast<uint32_t>(__builtin_clzll(value)) : 64u;
-#else
- unsigned long out;
- return _BitScanReverse64(&out, value) ? 63 - out : 64u;
-#endif
+PlatformThreadId GetThreadId() {
+ thread_local static PlatformThreadId thread_id = ResolveThreadId();
+ return thread_id;
}
-template <typename T>
-uint32_t CountLeadZeros(T value) {
- if constexpr (sizeof(T) == 8)
- return CountLeadZeros64(static_cast<uint64_t>(value));
- return CountLeadZeros32(static_cast<uint32_t>(value));
-}
+#elif PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
-inline PERFETTO_ALWAYS_INLINE uint32_t CountTrailZeros64(uint64_t value) {
-#if PERFETTO_BUILDFLAG(PERFETTO_X64_CPU_OPT)
- return static_cast<uint32_t>(_tzcnt_u64(value));
-#elif defined(__GNUC__) || defined(__clang__)
- return value ? static_cast<uint32_t>(__builtin_ctzll(value)) : 64u;
-#else
- unsigned long out;
- return _BitScanForward64(&out, value) ? static_cast<uint32_t>(out) : 64u;
-#endif
-}
+// The SetThreadDescription API was brought in version 1607 of Windows 10.
+typedef HRESULT(WINAPI* SetThreadDescription)(HANDLE hThread,
+ PCWSTR lpThreadDescription);
-inline PERFETTO_ALWAYS_INLINE uint32_t CountTrailZeros32(uint32_t value) {
-#if PERFETTO_BUILDFLAG(PERFETTO_X64_CPU_OPT)
- return _tzcnt_u32(value);
-#elif defined(__GNUC__) || defined(__clang__)
- return value ? static_cast<uint32_t>(__builtin_ctz(value)) : 32u;
-#else
- unsigned long out;
- return _BitScanForward(&out, value) ? out : 32u;
-#endif
-}
+// The SetThreadDescription API was brought in version 1607 of Windows 10.
+typedef HRESULT(WINAPI* GetThreadDescription)(HANDLE hThread,
+ PWSTR* ppszThreadDescription);
-template <typename T>
-inline PERFETTO_ALWAYS_INLINE uint32_t CountTrailZeros(T value) {
- if (sizeof(T) == 8) {
- return CountTrailZeros64(static_cast<uint64_t>(value));
+bool MaybeSetThreadName(const std::string& name) {
+ // The SetThreadDescription API works even if no debugger is attached.
+ static auto set_thread_description_func =
+ reinterpret_cast<SetThreadDescription>(
+ reinterpret_cast<void*>(::GetProcAddress(
+ ::GetModuleHandleA("Kernel32.dll"), "SetThreadDescription")));
+ if (!set_thread_description_func) {
+ return false;
}
- return CountTrailZeros32(static_cast<uint32_t>(value));
+ std::wstring wide_thread_name;
+ if (!UTF8ToWide(name, wide_thread_name)) {
+ return false;
+ }
+ HRESULT result = set_thread_description_func(::GetCurrentThread(),
+ wide_thread_name.c_str());
+ return !FAILED(result);
}
-template <typename T>
-constexpr bool AllBitsSet(T v) {
- return v == static_cast<T>(-1);
+bool GetThreadName(std::string& out_result) {
+ static auto get_thread_description_func =
+ reinterpret_cast<GetThreadDescription>(
+ reinterpret_cast<void*>(::GetProcAddress(
+ ::GetModuleHandleA("Kernel32.dll"), "GetThreadDescription")));
+ if (!get_thread_description_func) {
+ return false;
+ }
+ wchar_t* wide_thread_name;
+ HRESULT result =
+ get_thread_description_func(::GetCurrentThread(), &wide_thread_name);
+ if (SUCCEEDED(result)) {
+ bool success = WideToUTF8(std::wstring(wide_thread_name), out_result);
+ LocalFree(wide_thread_name);
+ return success;
+ }
+ return false;
}
+#endif // PERFETTO_BUILDFLAG(PERFETTO_OS_FUCHSIA)
+
} // namespace base
} // namespace perfetto
-
-#endif // INCLUDE_PERFETTO_EXT_BASE_BITS_H_
-
+// gen_amalgamated begin source: src/base/time.cc
/*
- * Copyright (C) 2025 The Android Open Source Project
+ * 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.
@@ -12066,546 +12595,216 @@ constexpr bool AllBitsSet(T v) {
*
* http://www.apache.org/licenses/LICENSE-2.0
*
- * Unless required by applicable law of an "AS IS" BASIS,
+ * 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.
*/
-// gen_amalgamated expanded: #include "perfetto/ext/base/lock_free_task_runner.h"
+#include <atomic>
+
+// gen_amalgamated expanded: #include "perfetto/base/time.h"
// gen_amalgamated expanded: #include "perfetto/base/build_config.h"
+// gen_amalgamated expanded: #include "perfetto/base/logging.h"
+// gen_amalgamated expanded: #include "perfetto/ext/base/string_utils.h"
#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
#include <windows.h>
-
-// Keep the \n before to prevent clang-format reordering.
-#include <synchapi.h>
#else
-#include <poll.h>
#include <unistd.h>
#endif
-#include <thread>
-
-// gen_amalgamated expanded: #include "perfetto/base/logging.h"
-// gen_amalgamated expanded: #include "perfetto/base/time.h"
-// gen_amalgamated expanded: #include "perfetto/ext/base/bits.h"
-// gen_amalgamated expanded: #include "perfetto/ext/base/platform.h"
-// gen_amalgamated expanded: #include "perfetto/ext/base/utils.h"
-// gen_amalgamated expanded: #include "perfetto/ext/base/watchdog.h"
-
namespace perfetto {
namespace base {
-namespace task_runner_internal {
-Slab::Slab() = default;
-Slab::~Slab() {
- PERFETTO_DCHECK(!prev); // We should never delete linked slabs.
-}
-} // namespace task_runner_internal
-
+#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
+#if !PERFETTO_BUILDFLAG(PERFETTO_ARCH_CPU_ARM64)
namespace {
-static constexpr auto kSlabSize = task_runner_internal::kSlabSize;
-}
-LockFreeTaskRunner::LockFreeTaskRunner()
- : run_task_thread_id_(std::this_thread::get_id()) {
- static_assert((kSlabSize & (kSlabSize - 1)) == 0, "kSlabSize must be a pow2");
- static_assert(kSlabSize >= Slab::kBitsPerWord);
+// Returns the current value of the performance counter.
+int64_t QPCNowRaw() {
+ LARGE_INTEGER perf_counter_now = {};
+ // According to the MSDN documentation for QueryPerformanceCounter(), this
+ // will never fail on systems that run XP or later.
+ // https://msdn.microsoft.com/library/windows/desktop/ms644904.aspx
+ ::QueryPerformanceCounter(&perf_counter_now);
+ return perf_counter_now.QuadPart;
+}
- // Populate both the tail and the freelist, to minimize the chance of
- // allocations at runtime.
- tail_.store(AllocNewSlab());
- free_slab_.store(AllocNewSlab());
+double TSCTicksPerSecond() {
+ // The value returned by QueryPerformanceFrequency() cannot be used as the TSC
+ // frequency, because there is no guarantee that the TSC frequency is equal to
+ // the performance counter frequency.
+ // The TSC frequency is cached in a static variable because it takes some time
+ // to compute it.
+ static std::atomic<double> tsc_ticks_per_second = 0;
+ double value = tsc_ticks_per_second.load(std::memory_order_relaxed);
+ if (value != 0)
+ return value;
- AddFileDescriptorWatch(wakeup_event_.fd(), [] {
- // Not reached -- see PostFileDescriptorWatches().
- PERFETTO_DFATAL("Should be unreachable.");
- });
-}
+ // Increase the thread priority to reduces the chances of having a context
+ // switch during a reading of the TSC and the performance counter.
+ const int previous_priority = ::GetThreadPriority(::GetCurrentThread());
+ ::SetThreadPriority(::GetCurrentThread(), THREAD_PRIORITY_HIGHEST);
-LockFreeTaskRunner::~LockFreeTaskRunner() {
- PERFETTO_DCHECK(RunsTasksOnCurrentThread());
+ // The first time that this function is called, make an initial reading of the
+ // TSC and the performance counter. Initialization of static variable is
+ // thread-safe. Threads can race initializing tsc_initial vs
+ // perf_counter_initial, although they should be storing very similar values.
- for (Slab* slab = tail_.exchange(nullptr); slab;) {
- Slab* prev = slab->prev;
- slab->prev = nullptr;
- delete slab;
- slab = prev;
- }
- delete free_slab_.exchange(nullptr);
-}
+ static const uint64_t tsc_initial = __rdtsc();
+ static const int64_t perf_counter_initial = QPCNowRaw();
-void LockFreeTaskRunner::PostTask(std::function<void()> closure) {
- // We use nullity of std::function in PopTaskRecursive() to determine exit
- // criteria. Posting a null task would break that logic. Also a null task
- // would cause an abort when trying to run it later on.
- PERFETTO_CHECK(PERFETTO_LIKELY(closure));
- using BitWord = Slab::BitWord;
- for (;;) {
- Slab* slab = tail_.load();
- PERFETTO_DCHECK(slab); // The tail_ must be always valid.
- ScopedRefcount scoped_refcount(this, slab);
- // After incrementing the refcount, re-verify that `slab` is still the
- // current tail. If it isn't, the slab might have been deleted between
- // our tail_.load() above and the refcount inc (the reader's check on
- // refcount==0 may have happened before our inc). Retry with the new tail.
- // If the second tail.load() returns the same slab, in seq_cst order
- // any subsequent CAS that replaces tail_ comes after this load, hence
- // any reader's later refcount check is also after our inc and will
- // observe refcount > 0.
- if (PERFETTO_UNLIKELY(tail_.load() != slab)) {
- continue;
- }
+ // Make a another reading of the TSC and the performance counter every time
+ // that this function is called.
+ const uint64_t tsc_now = __rdtsc();
+ const int64_t perf_counter_now = QPCNowRaw();
- // Now that we have a slab, try appending a task to it (if there is space).
- // We have 3 cases:
- // 1. slot < kSlabSize: the nominal case. Append the task and return.
- // 2. slot == kSlabSize: the common overflow case: The slab was full and we
- // tried to allocate the N+1 th element. We have to allocate a new Slab.
- // 3. slot > kSlabSize: like 2, but but two (or more) threads raced on it.
- // One thread will win the race and alloc a new slab, the other one will
- // repeat.
- size_t slot = slab->next_task_slot.fetch_add(1, std::memory_order_relaxed);
+ // Reset the thread priority.
+ ::SetThreadPriority(::GetCurrentThread(), previous_priority);
- if (slot >= kSlabSize) { // Cases 2,3
- Slab* new_slab = AllocNewSlab();
- new_slab->prev = slab;
- new_slab->next_task_slot.store(1, std::memory_order_relaxed);
- slot = 0;
- if (PERFETTO_UNLIKELY(!tail_.compare_exchange_strong(slab, new_slab))) {
- // If the cmpxcgh fails, another thread tried to allocate a new tail
- // slab and won the race. Do another round, we'll observe the new slab.
- // We have to release the prev pointer as at this point we found out
- // another thread also has it.
- new_slab->prev = nullptr;
- DeleteSlab(new_slab);
- continue;
- }
+ // Make sure that at least 50 ms elapsed between the 2 readings. The first
+ // time that this function is called, we don't expect this to be the case.
+ // Note: The longer the elapsed time between the 2 readings is, the more
+ // accurate the computed TSC frequency will be. The 50 ms value was
+ // chosen because local benchmarks show that it allows us to get a
+ // stddev of less than 1 tick/us between multiple runs.
+ // Note: According to the MSDN documentation for QueryPerformanceFrequency(),
+ // this will never fail on systems that run XP or later.
+ // https://msdn.microsoft.com/library/windows/desktop/ms644905.aspx
+ LARGE_INTEGER perf_counter_frequency = {};
+ ::QueryPerformanceFrequency(&perf_counter_frequency);
+ PERFETTO_CHECK(perf_counter_now >= perf_counter_initial);
+ const int64_t perf_counter_ticks = perf_counter_now - perf_counter_initial;
+ const double elapsed_time_seconds =
+ static_cast<double>(perf_counter_ticks) /
+ static_cast<double>(perf_counter_frequency.QuadPart);
- slab = new_slab;
- scoped_refcount = ScopedRefcount(this, new_slab);
- }
+ constexpr double kMinimumEvaluationPeriodSeconds = 0.05;
+ if (elapsed_time_seconds < kMinimumEvaluationPeriodSeconds)
+ return 0;
- // Nominal case: publish the task and return.
- PERFETTO_DCHECK(!slab->tasks[slot]);
- slab->tasks[slot] = std::move(closure);
- size_t s_word = slot / Slab::kBitsPerWord;
- size_t s_bit = slot % Slab::kBitsPerWord;
- BitWord s_mask = BitWord(1) << s_bit;
- PERFETTO_DCHECK(
- (slab->tasks_written[s_word].load(std::memory_order_relaxed) &
- s_mask) == 0);
- slab->tasks_written[s_word].fetch_or(s_mask, std::memory_order_release);
+ // Compute the frequency of the TSC.
+ PERFETTO_CHECK(tsc_now >= tsc_initial);
+ const uint64_t tsc_ticks = tsc_now - tsc_initial;
+ // Racing with another thread to write |tsc_ticks_per_second| is benign
+ // because both threads will write a valid result.
+ tsc_ticks_per_second.store(
+ static_cast<double>(tsc_ticks) / elapsed_time_seconds,
+ std::memory_order_relaxed);
- if (!RunsTasksOnCurrentThread()) {
- // We don't need any clever logic to avoid spurious wake ups from other
- // threads. Most PostTask()s in our codebase are done by the main thread.
- // In the rare cases of a PostTask() coming from another thread, the odds
- // of the main thread being woken up at the same time are tiny.
- WakeUp();
- }
- return;
- }
+ return tsc_ticks_per_second.load(std::memory_order_relaxed);
}
-void LockFreeTaskRunner::Run() {
- PERFETTO_CHECK(run_task_thread_id_ == std::this_thread::get_id());
- quit_ = false;
+} // namespace
+#endif // !PERFETTO_BUILDFLAG(PERFETTO_ARCH_CPU_ARM64)
- while (!quit_) {
- // Pop one immediate and one delayed task, for fairness.
- std::function<void()> immediate_task = PopNextImmediateTask();
- std::function<void()> delayed_task = PopNextExpiredDelayedTask();
- bool has_task = immediate_task || delayed_task;
- int poll_timeout_ms = has_task ? 0 : GetDelayMsToNextTask();
+TimeNanos GetWallTimeNs() {
+ LARGE_INTEGER freq;
+ ::QueryPerformanceFrequency(&freq);
+ LARGE_INTEGER counter;
+ ::QueryPerformanceCounter(&counter);
+ double elapsed_nanoseconds = (1e9 * static_cast<double>(counter.QuadPart)) /
+ static_cast<double>(freq.QuadPart);
+ return TimeNanos(static_cast<uint64_t>(elapsed_nanoseconds));
+}
- // run the poll(). We need it for two different reasons:
- // 1. Blocks until the next event on the horizon, which:
- // - If we pulled a task, poll in non-blocking mode (0 delay). There
- // might be other tasks ready and we want to run them soon after.
- // - If there is a delayed task, compute the time remaining for it.
- // - Otherwise polls indefinitely, waiting for a PostTask() or a Quit()
- // call from another thread.
- // 2. Regardless of timing, we need to read the FD watches.
- // We want to do this even if we know already that we have an immediate
- // task (when poll_timeout_ms = 0) to ensure fairness.
-
- // TODO(primiano): we could optimize this and avoid a syscall for each
- // task when we have bursts of tasks (with some saturation, e.g. do still
- // a poll() every 10 tasks). Unfortunately, however, some users of
- // TestTaskRunner.RunUntilIdle() rely on the fact that FD watches are
- // polled before the current task is ran, so that the task can tell if
- // there are more tasks upcoming or it has reached quiescence.
- // TL;DR RunUntilIdle() was a mistake as it has ill-defined semantics but
- // now tests rely on those subtle semantics.
-
- // Recompute the list of FDs to watch.
- UpdateWatchTasks();
-
- uint64_t windows_wait_res = 0;
-#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
- // Unlike poll(2), WaitForMultipleObjects() returns only *one* handle in the
- // set, even when >1 is signalled. In order to avoid starvation,
- // PostFileDescriptorWatches() will WaitForSingleObject() each other handle
- // to ensure fairness. |windows_wait_res| is passed just to avoid an extra
- // WaitForSingleObject() for the one handle that WaitForMultipleObject()
- // returned.
- DWORD timeout =
- poll_timeout_ms >= 0 ? static_cast<DWORD>(poll_timeout_ms) : INFINITE;
- windows_wait_res =
- WaitForMultipleObjects(static_cast<DWORD>(poll_fds_.size()),
- &poll_fds_[0], /*bWaitAll=*/false, timeout);
-#else
- platform::BeforeMaybeBlockingSyscall();
- int ret = PERFETTO_EINTR(poll(
- &poll_fds_[0], static_cast<nfds_t>(poll_fds_.size()), poll_timeout_ms));
- platform::AfterMaybeBlockingSyscall();
- PERFETTO_CHECK(ret >= 0);
-#endif
- PostFileDescriptorWatches(windows_wait_res);
-
- if (immediate_task) {
- errno = 0;
- RunTaskWithWatchdogGuard(std::move(immediate_task));
- }
-
- if (delayed_task) {
- errno = 0;
- RunTaskWithWatchdogGuard(std::move(delayed_task));
- }
- }
-
- // Wait for all other threads to have finished the Quit's PostTask().
- // This is to prevent the following race in tests:
- // - Thread1 (!= main thread) invokes Quit, which in turn becomes a PostTask.
- // - This function sees quit_=true and returns from Run().
- // - The owner of the LFTR at that point is entitled to destroy LFTR.
- // - Thread1 is still executing the epilogue of the PostTask, decrementing the
- // refcount, and ends up operating on invalid memory.
- while (
- std::any_of(refcounts_.begin(), refcounts_.end(),
- [](std::atomic<int32_t>& bucket) { return bucket.load(); })) {
- std::this_thread::yield();
- }
-}
-
-std::function<void()> LockFreeTaskRunner::PopNextImmediateTask() {
- return PopTaskRecursive(tail_.load(), nullptr);
-}
-
-std::function<void()> LockFreeTaskRunner::PopTaskRecursive(Slab* slab,
- Slab* next_slab) {
- PERFETTO_DCHECK(RunsTasksOnCurrentThread());
- Slab* prev = slab->prev;
- if (PERFETTO_UNLIKELY(prev)) {
- // In practice it's extemely unlikely that a slab has >1 predecessors.
- // In nominal conditions it is going to have 0 predecessors most of the
- // times and 1 predecessors 1 every kSlabSize times.
- auto task = PopTaskRecursive(prev, slab);
- if (task)
- return task;
- }
-
- size_t words_fully_consumed = 0;
- for (size_t w = 0; w < Slab::kNumWords; ++w) {
- using BitWord = Slab::BitWord;
- BitWord wr_word = slab->tasks_written[w].load(std::memory_order_acquire);
- BitWord rd_word = slab->tasks_read[w];
- words_fully_consumed += base::AllBitsSet(rd_word) ? 1 : 0;
- BitWord unread_word = wr_word & ~rd_word;
-
- if (unread_word == 0)
- continue;
-
- // Find the first unread task in the word.
- uint32_t bit = base::CountTrailZeros(unread_word);
- BitWord bit_mask = BitWord(1) << bit;
- size_t slot = w * Slab::kBitsPerWord + bit;
- std::function<void()> task = std::move(slab->tasks[slot]);
- slab->tasks[slot] = nullptr;
- slab->tasks_read[w] |= bit_mask;
- return task;
- } // for(word in tasks_written)
-
- // There are no unconsumed tasks in this Slab. Reached this point, this
- // invocation will return null. However, before doing so, if the slab is fully
- // written (are no slots left) and fully consumed delete it.
- // We never delete the latest slab (the one pointed to by tail_) because
- // we want the tail_ to always point to a valid slab.
- // In principle, we only delete non-tail slabs, and PostTask() threads only
- // access the tail, never walk back on the list, which sounds safe. However
- // there is a potential race we have to guard against:
- // A PostTask() thread could observe Slab 1 (e.g., the only slab), then
- // another PostTask thread() could append (and replace tail_ with) a new
- // Slab 2 (because Slab 1 was full).
- // If Run() comes along and sees the Slab 1 full it will delete it, without
- // realizing that the first thread is still accessing it, thinking it was the
- // tail.
- // Essentially, it is safe to delete non-tail slabs as long as we can
- // guarrantee that no other thread observed that slab through the `tail_` at
- // some point in the recent past. In order to do so, we use a refcount
- // mechanism. If the refcount is 0 we know that no other PostTask thread
- // has loaded the tail, and hence we can safely delete any non-tail slab.
- // If a PostTask thread comes immediately after our check they will observe
- // the new tail (we never delete the tail slab, only the predecessors).
-
- bool slab_fully_consumed = words_fully_consumed == Slab::kNumWords;
-
- const uint32_t bucket = HashSlabPtr(slab);
- if (slab_fully_consumed && next_slab && refcounts_[bucket].load() == 0) {
- // NOTE: only the main thread follows the `prev` linked list, writers never
- // look at `prev`. The only contention entrypoint is the `tail_` pointer,
- // which can be modified both by us and by writers.
- PERFETTO_DCHECK(next_slab->prev == slab);
- next_slab->prev = slab->prev;
- slab->prev = nullptr;
- DeleteSlab(slab);
- }
-
- return nullptr;
-}
-
-void LockFreeTaskRunner::Quit() {
- // We have to post the writing of the quit if we are not on the right thread.
- // The alternative would be writing quit_ + WakeUp(), but that is racy:
- // - We write quit_=true from another thread
- // - The main thread sees it immediately (it just happens to be iterating)
- // and destroys itself.
- // - We try to call WakeUp() while the main thread is being destroyed.
- if (!RunsTasksOnCurrentThread()) {
- PostTask([this] { this->Quit(); });
- return;
- }
- quit_ = true;
-}
-
-bool LockFreeTaskRunner::IsIdleForTesting() {
- PERFETTO_DCHECK(RunsTasksOnCurrentThread());
- for (Slab* slab = tail_; slab; slab = slab->prev) {
- for (size_t i = 0; i < Slab::kNumWords; ++i) {
- if (slab->tasks_written[i] & ~slab->tasks_read[i]) {
- return false;
- }
- }
- }
- return true;
-}
-
-std::function<void()> LockFreeTaskRunner::PopNextExpiredDelayedTask() {
- PERFETTO_DCHECK(RunsTasksOnCurrentThread());
- TimeMillis now =
- GetWallTimeMs() +
- TimeMillis(advanced_time_for_testing_.load(std::memory_order_relaxed));
- if (!delayed_tasks_.empty() && delayed_tasks_.back().time <= now) {
- auto task = std::move(delayed_tasks_.back().task);
- delayed_tasks_.pop_back();
- return task;
- }
- return nullptr;
-}
-
-int LockFreeTaskRunner::GetDelayMsToNextTask() const {
- PERFETTO_DCHECK(RunsTasksOnCurrentThread());
- if (delayed_tasks_.empty()) {
- return -1; // Forever.
- }
- TimeMillis now =
- GetWallTimeMs() +
- TimeMillis(advanced_time_for_testing_.load(std::memory_order_relaxed));
- TimeMillis deadline = delayed_tasks_.back().time;
- if (deadline <= now) {
- return 0;
- }
- return static_cast<int>((deadline - now).count());
-}
-
-LockFreeTaskRunner::Slab* LockFreeTaskRunner::AllocNewSlab() {
- Slab* free_slab = free_slab_.exchange(nullptr);
- if (free_slab) {
- free_slab->~Slab();
- new (free_slab) Slab();
- return free_slab;
- }
- slabs_allocated_.fetch_add(1, std::memory_order_relaxed);
- return new Slab();
-}
+TimeNanos GetThreadCPUTimeNs() {
+#if PERFETTO_BUILDFLAG(PERFETTO_ARCH_CPU_ARM64)
+ // QueryThreadCycleTime versus TSCTicksPerSecond doesn't have much relation to
+ // actual elapsed time on Windows on Arm, because QueryThreadCycleTime is
+ // backed by the actual number of CPU cycles executed, rather than a
+ // constant-rate timer like Intel. To work around this, use GetThreadTimes
+ // (which isn't as accurate but is meaningful as a measure of elapsed
+ // per-thread time).
+ FILETIME dummy, kernel_ftime, user_ftime;
+ ::GetThreadTimes(GetCurrentThread(), &dummy, &dummy, &kernel_ftime,
+ &user_ftime);
+ uint64_t kernel_time =
+ kernel_ftime.dwHighDateTime * 0x100000000 + kernel_ftime.dwLowDateTime;
+ uint64_t user_time =
+ user_ftime.dwHighDateTime * 0x100000000 + user_ftime.dwLowDateTime;
-void LockFreeTaskRunner::DeleteSlab(Slab* slab) {
- PERFETTO_DCHECK(!slab->prev); // We should never delete a linked slab.
- Slab* null_slab = nullptr;
- if (!free_slab_.compare_exchange_strong(null_slab, slab)) {
- slabs_freed_.fetch_add(1, std::memory_order_relaxed);
- delete slab;
- }
-}
+ return TimeNanos((kernel_time + user_time) * 100);
+#else // !PERFETTO_BUILDFLAG(PERFETTO_ARCH_CPU_ARM64)
+ // Get the number of TSC ticks used by the current thread.
+ ULONG64 thread_cycle_time = 0;
+ ::QueryThreadCycleTime(GetCurrentThread(), &thread_cycle_time);
-void LockFreeTaskRunner::PostDelayedTask(std::function<void()> task,
- uint32_t delay_ms) {
- if (!RunsTasksOnCurrentThread()) {
- PostTask([this, task = std::move(task), delay_ms] {
- this->PostDelayedTask(std::move(task), delay_ms);
- });
- return;
- }
+ // Get the frequency of the TSC.
+ const double tsc_ticks_per_second = TSCTicksPerSecond();
+ if (tsc_ticks_per_second == 0)
+ return TimeNanos();
- TimeMillis runtime =
- GetWallTimeMs() + TimeMillis(delay_ms) +
- TimeMillis(advanced_time_for_testing_.load(std::memory_order_relaxed));
- delayed_tasks_.insert(
- DelayedTask{runtime, next_delayed_task_seq_++, std::move(task)});
+ // Return the CPU time of the current thread.
+ const double thread_time_seconds =
+ static_cast<double>(thread_cycle_time) / tsc_ticks_per_second;
+ constexpr int64_t kNanosecondsPerSecond = 1000 * 1000 * 1000;
+ return TimeNanos(
+ static_cast<int64_t>(thread_time_seconds * kNanosecondsPerSecond));
+#endif // !PERFETTO_BUILDFLAG(PERFETTO_ARCH_CPU_ARM64)
}
-void LockFreeTaskRunner::AdvanceTimeForTesting(uint32_t ms) {
- advanced_time_for_testing_.fetch_add(ms);
- WakeUp();
+void SleepMicroseconds(unsigned interval_us) {
+ // The Windows Sleep function takes a millisecond count. Round up so that
+ // short sleeps don't turn into a busy wait. Note that the sleep granularity
+ // on Windows can dynamically vary from 1 ms to ~16 ms, so don't count on this
+ // being a short sleep.
+ ::Sleep(static_cast<DWORD>((interval_us + 999) / 1000));
}
-void LockFreeTaskRunner::PostFileDescriptorWatches(
- uint64_t windows_wait_result) {
- PERFETTO_DCHECK(RunsTasksOnCurrentThread());
- for (size_t i = 0; i < poll_fds_.size(); i++) {
-#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
- const PlatformHandle handle = poll_fds_[i];
- // |windows_wait_result| is the result of WaitForMultipleObjects() call. If
- // one of the objects was signalled, it will have a value between
- // [0, poll_fds_.size()].
- if (i != windows_wait_result &&
- WaitForSingleObject(handle, 0) != WAIT_OBJECT_0) {
- continue;
- }
-#else
- base::ignore_result(windows_wait_result);
- const PlatformHandle handle = poll_fds_[i].fd;
- if (!(poll_fds_[i].revents & (POLLIN | POLLHUP)))
- continue;
- poll_fds_[i].revents = 0;
-#endif
-
- // The wake-up event is handled inline to avoid an infinite recursion of
- // posted tasks.
- if (handle == wakeup_event_.fd()) {
- wakeup_event_.Clear();
- continue;
- }
-
- // Binding to |this| is safe since we are the only object executing the
- // task.
- PostTask([this, handle] { this->RunFileDescriptorWatch(handle); });
-
- // Flag the task as pending.
-#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
- // On Windows this is done by marking the WatchTask entry as pending. This
- // is more expensive than Linux as requires rebuilding the |poll_fds_|
- // vector on each call. There doesn't seem to be a good alternative though.
- auto it = watch_tasks_.find(handle);
- PERFETTO_CHECK(it != watch_tasks_.end());
- PERFETTO_DCHECK(!it->second.pending);
- it->second.pending = true;
-#else
- // On UNIX systems instead, we just make the fd negative while its task is
- // pending. This makes poll(2) ignore the fd.
- PERFETTO_DCHECK(poll_fds_[i].fd >= 0);
- poll_fds_[i].fd = -poll_fds_[i].fd;
-#endif
- }
+void InitializeTime() {
+#if !PERFETTO_BUILDFLAG(PERFETTO_ARCH_CPU_ARM64)
+ // Make an early first call to TSCTicksPerSecond() to start 50 ms elapsed time
+ // (see comment in TSCTicksPerSecond()).
+ TSCTicksPerSecond();
+#endif // !PERFETTO_BUILDFLAG(PERFETTO_ARCH_CPU_ARM64)
}
-void LockFreeTaskRunner::RunFileDescriptorWatch(PlatformHandle fd) {
- PERFETTO_DCHECK(RunsTasksOnCurrentThread());
-
- std::function<void()> task;
- auto it = watch_tasks_.find(fd);
- if (it == watch_tasks_.end())
- return;
- WatchTask& watch_task = it->second;
-
- // Make poll(2) pay attention to the fd again. Since another thread may have
- // updated this watch we need to refresh the set first.
- UpdateWatchTasks();
-
-#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
- // On Windows we manually track the presence of outstanding tasks for the
- // watch. The UpdateWatchTasksLocked() in the Run() loop will re-add the
- // task to the |poll_fds_| vector.
- PERFETTO_DCHECK(watch_task.pending);
- watch_task.pending = false;
-#else
- size_t fd_index = watch_task.poll_fd_index;
- PERFETTO_DCHECK(fd_index < poll_fds_.size());
- PERFETTO_DCHECK(::abs(poll_fds_[fd_index].fd) == fd);
- poll_fds_[fd_index].fd = fd;
-#endif
- task = watch_task.callback;
- errno = 0;
- RunTaskWithWatchdogGuard(task);
-}
+#else // PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
-void LockFreeTaskRunner::UpdateWatchTasks() {
- PERFETTO_DCHECK(RunsTasksOnCurrentThread());
-#if !PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
- if (!watch_tasks_changed_)
- return;
- watch_tasks_changed_ = false;
-#endif
- poll_fds_.clear();
- for (auto& it : watch_tasks_) {
- PlatformHandle handle = it.first;
- WatchTask& watch_task = it.second;
-#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
- if (!watch_task.pending)
- poll_fds_.push_back(handle);
-#else
- watch_task.poll_fd_index = poll_fds_.size();
- poll_fds_.push_back({handle, POLLIN | POLLHUP, 0});
-#endif
- }
+void SleepMicroseconds(unsigned interval_us) {
+ ::usleep(static_cast<useconds_t>(interval_us));
}
-void LockFreeTaskRunner::AddFileDescriptorWatch(PlatformHandle fd,
- std::function<void()> task) {
- PERFETTO_DCHECK(PlatformHandleChecker::IsValid(fd));
+void InitializeTime() {}
- if (!RunsTasksOnCurrentThread()) {
- PostTask([this, task = std::move(task), fd] {
- this->AddFileDescriptorWatch(fd, std::move(task));
- });
- return;
- }
+#endif // PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
- PERFETTO_DCHECK(!watch_tasks_.count(fd));
- WatchTask& watch_task = watch_tasks_[fd];
- watch_task.callback = std::move(task);
+std::string GetTimeFmt(const std::string& fmt) {
+ time_t raw_time;
+ time(&raw_time);
+ struct tm local_tm;
#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
- watch_task.pending = false;
+ PERFETTO_CHECK(localtime_s(&local_tm, &raw_time) == 0);
#else
- watch_task.poll_fd_index = SIZE_MAX;
+ tzset();
+ PERFETTO_CHECK(localtime_r(&raw_time, &local_tm) != nullptr);
#endif
- watch_tasks_changed_ = true;
-}
-
-void LockFreeTaskRunner::RemoveFileDescriptorWatch(PlatformHandle fd) {
- if (!RunsTasksOnCurrentThread()) {
- PostTask([this, fd] { this->RemoveFileDescriptorWatch(fd); });
- return;
- }
-
- PERFETTO_DCHECK(watch_tasks_.count(fd));
- watch_tasks_.erase(fd);
- watch_tasks_changed_ = true;
+ char buf[128];
+ PERFETTO_CHECK(strftime(buf, 80, fmt.c_str(), &local_tm) > 0);
+ return buf;
}
-bool LockFreeTaskRunner::RunsTasksOnCurrentThread() const {
- return run_task_thread_id_ == std::this_thread::get_id();
+std::optional<int32_t> GetTimezoneOffsetMins() {
+ std::string tz = GetTimeFmt("%z");
+ if (tz.size() != 5 || (tz[0] != '+' && tz[0] != '-'))
+ return std::nullopt;
+ char sign = '\0';
+ int32_t hh = 0;
+ int32_t mm = 0;
+ if (sscanf(tz.c_str(), "%c%2d%2d", &sign, &hh, &mm) != 3)
+ return std::nullopt;
+ return (hh * 60 + mm) * (sign == '-' ? -1 : 1);
}
} // namespace base
} // namespace perfetto
-// gen_amalgamated begin source: src/base/thread_task_runner.cc
-// gen_amalgamated begin header: include/perfetto/ext/base/thread_task_runner.h
+// gen_amalgamated begin source: src/base/utils.cc
/*
- * Copyright (C) 2019 The Android Open Source Project
+ * 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.
@@ -12620,227 +12819,353 @@ bool LockFreeTaskRunner::RunsTasksOnCurrentThread() const {
* limitations under the License.
*/
-#ifndef INCLUDE_PERFETTO_EXT_BASE_THREAD_TASK_RUNNER_H_
-#define INCLUDE_PERFETTO_EXT_BASE_THREAD_TASK_RUNNER_H_
+// gen_amalgamated expanded: #include "perfetto/ext/base/utils.h"
-#include <functional>
-#include <thread>
+#include <string>
-// gen_amalgamated expanded: #include "perfetto/ext/base/lock_free_task_runner.h"
+// gen_amalgamated expanded: #include "perfetto/base/build_config.h"
+// gen_amalgamated expanded: #include "perfetto/base/logging.h"
+// gen_amalgamated expanded: #include "perfetto/ext/base/file_utils.h"
+// gen_amalgamated expanded: #include "perfetto/ext/base/pipe.h"
+// gen_amalgamated expanded: #include "perfetto/ext/base/string_utils.h"
-namespace perfetto {
-namespace base {
+#if PERFETTO_BUILDFLAG(PERFETTO_OS_LINUX) || \
+ PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID) || \
+ PERFETTO_BUILDFLAG(PERFETTO_OS_APPLE) || \
+ PERFETTO_BUILDFLAG(PERFETTO_OS_FREEBSD) || \
+ PERFETTO_BUILDFLAG(PERFETTO_OS_FUCHSIA)
+#include <limits.h>
+#include <stdlib.h> // For _exit()
+#endif
-// A MaybeLockFreeTaskRunner backed by a dedicated task thread. Shuts down the
-// runner and joins the thread upon destruction. Can be moved to transfer
-// ownership.
-//
-// Guarantees that:
-// * the MaybeLockFreeTaskRunner will be constructed and destructed on the task
-// thread.
-// * the task thread will live for the lifetime of the MaybeLockFreeTaskRunner.
-//
-class PERFETTO_EXPORT_COMPONENT ThreadTaskRunner : public TaskRunner {
- public:
- static ThreadTaskRunner CreateAndStart(const std::string& name = "") {
- return ThreadTaskRunner(name);
- }
+#if !PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
+// For isatty(), getpagesize(), geteuid(), fork() & sysconf().
+#include <unistd.h>
+#endif
- ThreadTaskRunner(const ThreadTaskRunner&) = delete;
- ThreadTaskRunner& operator=(const ThreadTaskRunner&) = delete;
+#if PERFETTO_BUILDFLAG(PERFETTO_OS_APPLE)
+#include <mach-o/dyld.h>
+#include <mach/vm_page_size.h>
+#endif
- ThreadTaskRunner(ThreadTaskRunner&&) noexcept;
- ThreadTaskRunner& operator=(ThreadTaskRunner&&);
- ~ThreadTaskRunner() override;
+#if PERFETTO_BUILDFLAG(PERFETTO_OS_FREEBSD)
+#include <sys/sysctl.h>
+#endif
- // Executes the given function on the task runner thread and blocks the caller
- // thread until the function has run.
- void PostTaskAndWaitForTesting(std::function<void()>);
+#if PERFETTO_BUILDFLAG(PERFETTO_OS_LINUX_BUT_NOT_QNX) || \
+ PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID)
+#include <sys/prctl.h>
- // Can be called from another thread to get the CPU time of the thread the
- // task-runner is executing on.
- uint64_t GetThreadCPUTimeNsForTesting();
+#ifndef PR_GET_TAGGED_ADDR_CTRL
+#define PR_GET_TAGGED_ADDR_CTRL 56
+#endif
- PlatformThreadId GetThreadIdForTesting();
+#ifndef PR_TAGGED_ADDR_ENABLE
+#define PR_TAGGED_ADDR_ENABLE (1UL << 0)
+#endif
- // Returns a pointer to the MaybeLockFreeTaskRunner, which is valid for the
- // lifetime of this ThreadTaskRunner object (unless this object is moved-from,
- // in which case the pointer remains valid for the lifetime of the new owning
- // ThreadTaskRunner).
- //
- // Warning: do not call Quit() on the returned runner pointer, the termination
- // should be handled exclusively by this class' destructor.
- MaybeLockFreeTaskRunner* get() const { return task_runner_; }
+#ifndef PR_MTE_TCF_SYNC
+#define PR_MTE_TCF_SYNC (1UL << 1)
+#endif
- // TaskRunner implementation.
- // These methods just proxy to the underlying task_runner_.
- void PostTask(std::function<void()>) override;
- void PostDelayedTask(std::function<void()>, uint32_t delay_ms) override;
- void AddFileDescriptorWatch(PlatformHandle, std::function<void()>) override;
- void RemoveFileDescriptorWatch(PlatformHandle) override;
- bool RunsTasksOnCurrentThread() const override;
+#endif // OS_LINUX | OS_ANDROID
- private:
- explicit ThreadTaskRunner(const std::string& name);
- void RunTaskThread(std::function<void(MaybeLockFreeTaskRunner*)> initializer);
+#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
+#include <windows.h>
- std::thread thread_;
- std::string name_;
- MaybeLockFreeTaskRunner* task_runner_ = nullptr;
-};
+#include <io.h>
+#include <malloc.h> // For _aligned_malloc().
+#endif
-} // namespace base
-} // namespace perfetto
+#if PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID)
+#include <dlfcn.h>
+#include <malloc.h>
-#endif // INCLUDE_PERFETTO_EXT_BASE_THREAD_TASK_RUNNER_H_
-/*
- * 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.
- */
+#ifdef M_PURGE
+#define PERFETTO_M_PURGE M_PURGE
+#else
+// Only available in in-tree builds and on newer SDKs.
+#define PERFETTO_M_PURGE -101
+#endif // M_PURGE
-// gen_amalgamated expanded: #include "perfetto/base/build_config.h"
+#ifdef M_PURGE_ALL
+#define PERFETTO_M_PURGE_ALL M_PURGE_ALL
+#else
+// Only available in in-tree builds and on newer SDKs.
+#define PERFETTO_M_PURGE_ALL -104
+#endif // M_PURGE
-// gen_amalgamated expanded: #include "perfetto/ext/base/thread_task_runner.h"
+namespace {
+extern "C" {
+using MalloptType = int (*)(int, int);
+}
+} // namespace
+#endif // OS_ANDROID
-#include <condition_variable>
-#include <functional>
-#include <mutex>
-#include <thread>
+namespace perfetto {
+namespace base {
-// gen_amalgamated expanded: #include "perfetto/base/logging.h"
-// gen_amalgamated expanded: #include "perfetto/ext/base/lock_free_task_runner.h"
-// gen_amalgamated expanded: #include "perfetto/ext/base/thread_utils.h"
+namespace internal {
-#if PERFETTO_BUILDFLAG(PERFETTO_OS_LINUX_BUT_NOT_QNX) || \
+std::atomic<uint32_t> g_cached_page_size{0};
+
+uint32_t GetSysPageSizeSlowpath() {
+ uint32_t page_size = 0;
+#if PERFETTO_BUILDFLAG(PERFETTO_OS_LINUX) || \
PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID)
-#include <sys/prctl.h>
+ const int page_size_int = getpagesize();
+ // If sysconf() fails for obscure reasons (e.g. SELinux denial) assume the
+ // page size is 4KB. This is to avoid regressing subtle SDK usages, as old
+ // versions of this code had a static constant baked in.
+ page_size = static_cast<uint32_t>(page_size_int > 0 ? page_size_int : 4096);
+#elif PERFETTO_BUILDFLAG(PERFETTO_OS_APPLE)
+ page_size = static_cast<uint32_t>(vm_page_size);
+#elif PERFETTO_BUILDFLAG(PERFETTO_OS_FREEBSD)
+ page_size = static_cast<uint32_t>(sysconf(_SC_PAGESIZE));
+#else
+ page_size = 4096;
#endif
-namespace perfetto {
-namespace base {
-
-ThreadTaskRunner::ThreadTaskRunner(ThreadTaskRunner&& other) noexcept
- : thread_(std::move(other.thread_)), task_runner_(other.task_runner_) {
- other.task_runner_ = nullptr;
-}
+ PERFETTO_CHECK(page_size > 0 && page_size % 4096 == 0);
-ThreadTaskRunner& ThreadTaskRunner::operator=(ThreadTaskRunner&& other) {
- this->~ThreadTaskRunner();
- new (this) ThreadTaskRunner(std::move(other));
- return *this;
+ // Races here are fine because any thread will write the same value.
+ g_cached_page_size.store(page_size, std::memory_order_relaxed);
+ return page_size;
}
-ThreadTaskRunner::~ThreadTaskRunner() {
- if (task_runner_) {
- task_runner_->Quit();
+} // namespace internal
- PERFETTO_DCHECK(thread_.joinable());
+void MaybeReleaseAllocatorMemToOS() {
+#if PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID)
+ // mallopt() on Android requires SDK level 26. Many targets and embedders
+ // still depend on a lower SDK level. Given mallopt() is a quite simple API,
+ // use reflection to do this rather than bumping the SDK level for all
+ // embedders. This keeps the behavior of standalone builds aligned with
+ // in-tree builds.
+ static MalloptType mallopt_fn =
+ reinterpret_cast<MalloptType>(dlsym(RTLD_DEFAULT, "mallopt"));
+ if (!mallopt_fn)
+ return;
+ if (mallopt_fn(PERFETTO_M_PURGE_ALL, 0) == 0) {
+ mallopt_fn(PERFETTO_M_PURGE, 0);
}
- if (thread_.joinable())
- thread_.join();
+#endif
}
-ThreadTaskRunner::ThreadTaskRunner(const std::string& name) : name_(name) {
- std::mutex init_lock;
- std::condition_variable init_cv;
-
- std::function<void(MaybeLockFreeTaskRunner*)> initializer =
- [this, &init_lock, &init_cv](MaybeLockFreeTaskRunner* task_runner) {
- std::lock_guard<std::mutex> lock(init_lock);
- task_runner_ = task_runner;
- // Notify while still holding the lock, as init_cv ceases to exist as
- // soon as the main thread observes a non-null task_runner_, and it can
- // wake up spuriously (i.e. before the notify if we had unlocked before
- // notifying).
- init_cv.notify_one();
- };
-
- thread_ = std::thread(&ThreadTaskRunner::RunTaskThread, this,
- std::move(initializer));
+uid_t GetCurrentUserId() {
+#if PERFETTO_BUILDFLAG(PERFETTO_OS_LINUX) || \
+ PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID) || \
+ PERFETTO_BUILDFLAG(PERFETTO_OS_FREEBSD) || \
+ PERFETTO_BUILDFLAG(PERFETTO_OS_APPLE)
+ return geteuid();
+#else
+ // TODO(primiano): On Windows we could hash the current user SID and derive a
+ // numeric user id [1]. It is not clear whether we need that. Right now that
+ // would not bring any benefit. Returning 0 unil we can prove we need it.
+ // [1]:https://android-review.googlesource.com/c/platform/external/perfetto/+/1513879/25/src/base/utils.cc
+ return 0;
+#endif
+}
- std::unique_lock<std::mutex> lock(init_lock);
- init_cv.wait(lock, [this] { return !!task_runner_; });
+void SetEnv(const std::string& key, const std::string& value) {
+#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
+ PERFETTO_CHECK(::_putenv_s(key.c_str(), value.c_str()) == 0);
+#else
+ PERFETTO_CHECK(::setenv(key.c_str(), value.c_str(), /*overwrite=*/true) == 0);
+#endif
}
-void ThreadTaskRunner::RunTaskThread(
- std::function<void(MaybeLockFreeTaskRunner*)> initializer) {
- if (!name_.empty()) {
- base::MaybeSetThreadName(name_);
- }
+void UnsetEnv(const std::string& key) {
+#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
+ PERFETTO_CHECK(::_putenv_s(key.c_str(), "") == 0);
+#else
+ PERFETTO_CHECK(::unsetenv(key.c_str()) == 0);
+#endif
+}
- MaybeLockFreeTaskRunner task_runner;
- task_runner.PostTask(std::bind(std::move(initializer), &task_runner));
- task_runner.Run();
+bool IsTty(int fd) {
+#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
+ return ::_isatty(fd) != 0;
+#else
+ return ::isatty(fd) != 0;
+#endif
}
-void ThreadTaskRunner::PostTaskAndWaitForTesting(std::function<void()> fn) {
- std::mutex mutex;
- std::condition_variable cv;
+bool IsTty(FILE* stream) {
+#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
+ return IsTty(::_fileno(stream));
+#else
+ return IsTty(::fileno(stream));
+#endif
+}
- std::unique_lock<std::mutex> lock(mutex);
- bool done = false;
- task_runner_->PostTask([&mutex, &cv, &done, &fn] {
- fn();
+void Daemonize(std::function<int(pid_t)> parent_cb) {
+#if PERFETTO_BUILDFLAG(PERFETTO_OS_LINUX) || \
+ PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID) || \
+ PERFETTO_BUILDFLAG(PERFETTO_OS_FREEBSD) || \
+ (PERFETTO_BUILDFLAG(PERFETTO_OS_APPLE) && \
+ !PERFETTO_BUILDFLAG(PERFETTO_OS_APPLE_TVOS))
+ Pipe pipe = Pipe::Create(Pipe::kBothBlock);
+ pid_t pid;
+ switch (pid = fork()) {
+ case -1:
+ PERFETTO_FATAL("fork");
+ case 0: {
+ PERFETTO_CHECK(setsid() != -1);
+ base::ignore_result(chdir("/"));
+ base::ScopedFile null = base::OpenFile("/dev/null", O_RDONLY);
+ PERFETTO_CHECK(null);
+ PERFETTO_CHECK(dup2(*null, STDIN_FILENO) != -1);
+ PERFETTO_CHECK(dup2(*null, STDOUT_FILENO) != -1);
+ PERFETTO_CHECK(dup2(*null, STDERR_FILENO) != -1);
+ // Do not accidentally close stdin/stdout/stderr.
+ if (*null <= 2)
+ null.release();
+ WriteAll(*pipe.wr, "1", 1);
+ break;
+ }
+ default: {
+ // Wait for the child process to have reached the setsid() call. This is
+ // to avoid that 'adb shell perfetto -D' destroys the terminal (hence
+ // sending a SIGHUP to the child) before the child has detached from the
+ // terminal (see b/238644870).
- std::lock_guard<std::mutex> inner_lock(mutex);
- done = true;
- cv.notify_one();
- });
- cv.wait(lock, [&done] { return done; });
+ // This is to unblock the read() below (with EOF, which will fail the
+ // CHECK) in the unlikely case of the child crashing before WriteAll("1").
+ pipe.wr.reset();
+ char one = '\0';
+ PERFETTO_CHECK(Read(*pipe.rd, &one, sizeof(one)) == 1 && one == '1');
+ int err = parent_cb(pid);
+ exit(err);
+ }
+ }
+#else
+ // Avoid -Wunreachable warnings.
+ if (reinterpret_cast<intptr_t>(&Daemonize) != 16)
+ PERFETTO_FATAL("--background is only supported on Linux/Android/Mac");
+ ignore_result(parent_cb);
+#endif // OS_WIN
}
-uint64_t ThreadTaskRunner::GetThreadCPUTimeNsForTesting() {
- uint64_t thread_time_ns = 0;
- PostTaskAndWaitForTesting([&thread_time_ns] {
- thread_time_ns = static_cast<uint64_t>(base::GetThreadCPUTimeNs().count());
- });
- return thread_time_ns;
-}
-PlatformThreadId ThreadTaskRunner::GetThreadIdForTesting() {
- PlatformThreadId thread_id = static_cast<PlatformThreadId>(-1);
- PostTaskAndWaitForTesting([&thread_id] { thread_id = GetThreadId(); });
- return thread_id;
+std::string GetCurExecutablePath() {
+ std::string self_path;
+#if PERFETTO_BUILDFLAG(PERFETTO_OS_LINUX) || \
+ PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID) || \
+ PERFETTO_BUILDFLAG(PERFETTO_OS_FUCHSIA)
+ char buf[PATH_MAX];
+ ssize_t size = readlink("/proc/self/exe", buf, sizeof(buf));
+ PERFETTO_CHECK(size != -1);
+ // readlink does not null terminate.
+ self_path = std::string(buf, static_cast<size_t>(size));
+#elif PERFETTO_BUILDFLAG(PERFETTO_OS_APPLE)
+ uint32_t size = 0;
+ PERFETTO_CHECK(_NSGetExecutablePath(nullptr, &size));
+ self_path.resize(size);
+ PERFETTO_CHECK(_NSGetExecutablePath(&self_path[0], &size) == 0);
+#elif PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
+ char buf[MAX_PATH];
+ auto len = ::GetModuleFileNameA(nullptr /*current*/, buf, sizeof(buf));
+ self_path = std::string(buf, len);
+#elif PERFETTO_BUILDFLAG(PERFETTO_OS_FREEBSD)
+ char buf[PATH_MAX];
+ int mib[4], ret;
+ size_t len = sizeof(buf);
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_PROC;
+ mib[2] = KERN_PROC_PATHNAME;
+ mib[3] = -1;
+ ret = sysctl(mib, 4, buf, &len, NULL, 0);
+ PERFETTO_CHECK(ret == 0);
+ // This returns the full path; need to trim the executable
+ self_path = std::string(buf);
+#else
+ PERFETTO_FATAL(
+ "GetCurExecutableDir() not implemented on the current platform");
+#endif
+ return self_path;
}
-void ThreadTaskRunner::PostTask(std::function<void()> task) {
- task_runner_->PostTask(std::move(task));
+std::string GetCurExecutableDir() {
+ auto path = GetCurExecutablePath();
+#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
+ // Paths in Windows can have both kinds of slashes (mingw vs msvc).
+ path = path.substr(0, path.find_last_of('\\'));
+#endif
+ path = path.substr(0, path.find_last_of('/'));
+ return path;
}
-void ThreadTaskRunner::PostDelayedTask(std::function<void()> task,
- uint32_t delay_ms) {
- task_runner_->PostDelayedTask(std::move(task), delay_ms);
+void* AlignedAlloc(size_t alignment, size_t size) {
+ void* res = nullptr;
+ alignment = AlignUp<sizeof(void*)>(alignment); // At least pointer size.
+#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
+ // Window's _aligned_malloc() has a nearly identically signature to Unix's
+ // aligned_alloc() but its arguments are obviously swapped.
+ res = _aligned_malloc(size, alignment);
+#else
+ // aligned_alloc() has been introduced in Android only in API 28.
+ // Also NaCl and Fuchsia seems to have only posix_memalign().
+ ignore_result(posix_memalign(&res, alignment, size));
+#endif
+ PERFETTO_CHECK(res);
+ return res;
}
-void ThreadTaskRunner::AddFileDescriptorWatch(
- PlatformHandle handle,
- std::function<void()> watch_task) {
- task_runner_->AddFileDescriptorWatch(handle, std::move(watch_task));
+void AlignedFree(void* ptr) {
+#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
+ _aligned_free(ptr); // MSDN says it is fine to pass nullptr.
+#else
+ free(ptr);
+#endif
}
-void ThreadTaskRunner::RemoveFileDescriptorWatch(PlatformHandle handle) {
- task_runner_->RemoveFileDescriptorWatch(handle);
+bool IsSyncMemoryTaggingEnabled() {
+#if PERFETTO_BUILDFLAG(PERFETTO_OS_LINUX_BUT_NOT_QNX) || \
+ PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID)
+ // Compute only once per lifetime of the process.
+ static bool cached_value = [] {
+ const int res = prctl(PR_GET_TAGGED_ADDR_CTRL, 0, 0, 0, 0);
+ if (res < 0)
+ return false;
+ const uint32_t actl = static_cast<uint32_t>(res);
+ return (actl & PR_TAGGED_ADDR_ENABLE) && (actl & PR_MTE_TCF_SYNC);
+ }();
+ return cached_value;
+#else
+ return false;
+#endif
}
-bool ThreadTaskRunner::RunsTasksOnCurrentThread() const {
- return task_runner_->RunsTasksOnCurrentThread();
+std::string HexDump(const void* data_void, size_t len, size_t bytes_per_line) {
+ const char* data = reinterpret_cast<const char*>(data_void);
+ std::string res;
+ static const size_t kPadding = bytes_per_line * 3 + 12;
+ std::unique_ptr<char[]> line(new char[bytes_per_line * 4 + 128]);
+ for (size_t i = 0; i < len; i += bytes_per_line) {
+ char* wptr = line.get();
+ wptr += base::SprintfTrunc(wptr, 19, "%08zX: ", i);
+ for (size_t j = i; j < i + bytes_per_line && j < len; j++) {
+ wptr += base::SprintfTrunc(wptr, 4, "%02X ",
+ static_cast<unsigned>(data[j]) & 0xFF);
+ }
+ for (size_t j = static_cast<size_t>(wptr - line.get()); j < kPadding; ++j)
+ *(wptr++) = ' ';
+ for (size_t j = i; j < i + bytes_per_line && j < len; j++) {
+ char c = data[j];
+ *(wptr++) = (c >= 32 && c < 127) ? c : '.';
+ }
+ *(wptr++) = '\n';
+ *(wptr++) = '\0';
+ res.append(line.get());
+ }
+ return res;
}
} // namespace base
} // namespace perfetto
-// gen_amalgamated begin source: src/base/unix_task_runner.cc
+// gen_amalgamated begin source: src/base/uuid.cc
/*
- * Copyright (C) 2017 The Android Open Source Project
+ * 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.
@@ -12855,311 +13180,128 @@ bool ThreadTaskRunner::RunsTasksOnCurrentThread() const {
* limitations under the License.
*/
-// gen_amalgamated expanded: #include "perfetto/base/build_config.h"
-
-// gen_amalgamated expanded: #include "perfetto/ext/base/platform.h"
-// gen_amalgamated expanded: #include "perfetto/ext/base/unix_task_runner.h"
-
-#include <errno.h>
-#include <stdlib.h>
-
-#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
-#include <windows.h>
-
-#include <synchapi.h>
-#else
-#include <unistd.h>
-#endif
+// gen_amalgamated expanded: #include "perfetto/ext/base/uuid.h"
-#include <algorithm>
-#include <limits>
+#include <random>
-// gen_amalgamated expanded: #include "perfetto/ext/base/watchdog.h"
+// gen_amalgamated expanded: #include "perfetto/base/time.h"
+// gen_amalgamated expanded: #include "perfetto/ext/base/utils.h"
namespace perfetto {
namespace base {
+namespace {
-UnixTaskRunner::UnixTaskRunner() {
- AddFileDescriptorWatch(event_.fd(), [] {
- // Not reached -- see PostFileDescriptorWatches().
- PERFETTO_DFATAL("Should be unreachable.");
- });
-}
+constexpr char kHexmap[] = {'0', '1', '2', '3', '4', '5', '6', '7',
+ '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
-UnixTaskRunner::~UnixTaskRunner() = default;
+} // namespace
-void UnixTaskRunner::WakeUp() {
- event_.Notify();
-}
+// A globally unique 128-bit number.
+// In the early days of perfetto we were (sorta) respecting rfc4122. Later we
+// started replacing the LSB of the UUID with the statsd subscription ID in
+// other parts of the codebase (see perfetto_cmd.cc) for the convenience of
+// trace lookups, so rfc4122 made no sense as it just reduced entropy.
+Uuid Uuidv4() {
+ // Mix different sources of entropy to reduce the chances of collisions.
+ // Only using boot time is not enough. Under the assumption that most traces
+ // are started around the same time at boot, within a 1s window, the birthday
+ // paradox gives a chance of 90% collisions with 70k traces over a 1e9 space
+ // (Number of ns in a 1s window).
+ // We deliberately don't use /dev/urandom as that might block for
+ // unpredictable time if the system is idle (and is not portable).
+ // The UUID does NOT need to be cryptographically secure, but random enough
+ // to avoid collisions across a large number of devices.
+ uint64_t boot_ns = static_cast<uint64_t>(GetBootTimeNs().count());
+ uint64_t epoch_ns = static_cast<uint64_t>(GetWallTimeNs().count());
-void UnixTaskRunner::Run() {
- PERFETTO_DCHECK_THREAD(thread_checker_);
- created_thread_id_.store(GetThreadId(), std::memory_order_relaxed);
- {
- std::lock_guard<base::MaybeRtMutex> lock(lock_);
- quit_ = false;
- }
- for (;;) {
- int poll_timeout_ms;
- {
- std::lock_guard<base::MaybeRtMutex> lock(lock_);
- if (quit_)
- return;
- poll_timeout_ms = GetDelayMsToNextTaskLocked();
- UpdateWatchTasksLocked();
- }
+ // Use code ASLR as entropy source.
+ uint32_t code_ptr =
+ static_cast<uint32_t>(reinterpret_cast<uint64_t>(&Uuidv4) >> 12);
-#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
- DWORD timeout =
- poll_timeout_ms >= 0 ? static_cast<DWORD>(poll_timeout_ms) : INFINITE;
- DWORD ret =
- WaitForMultipleObjects(static_cast<DWORD>(poll_fds_.size()),
- &poll_fds_[0], /*bWaitAll=*/false, timeout);
- // Unlike poll(2), WaitForMultipleObjects() returns only *one* handle in the
- // set, even when >1 is signalled. In order to avoid starvation,
- // PostFileDescriptorWatches() will WaitForSingleObject() each other handle
- // to ensure fairness. |ret| here is passed just to avoid an extra
- // WaitForSingleObject() for the one handle that WaitForMultipleObject()
- // returned.
- PostFileDescriptorWatches(ret);
-#else
- platform::BeforeMaybeBlockingSyscall();
- int ret = PERFETTO_EINTR(poll(
- &poll_fds_[0], static_cast<nfds_t>(poll_fds_.size()), poll_timeout_ms));
- platform::AfterMaybeBlockingSyscall();
- PERFETTO_CHECK(ret >= 0);
- PostFileDescriptorWatches(0 /*ignored*/);
-#endif
+ // Use stack ASLR as a further entropy source.
+ uint32_t stack_ptr =
+ static_cast<uint32_t>(reinterpret_cast<uint64_t>(&code_ptr) >> 12);
- // To avoid starvation we always interleave all types of tasks -- immediate,
- // delayed and file descriptor watches.
- RunImmediateAndDelayedTask();
- }
-}
+ uint32_t entropy[] = {static_cast<uint32_t>(boot_ns >> 32),
+ static_cast<uint32_t>(boot_ns),
+ static_cast<uint32_t>(epoch_ns >> 32),
+ static_cast<uint32_t>(epoch_ns),
+ code_ptr,
+ stack_ptr};
+ std::seed_seq entropy_seq(entropy, entropy + ArraySize(entropy));
-void UnixTaskRunner::Quit() {
- std::lock_guard<base::MaybeRtMutex> lock(lock_);
- quit_ = true;
- WakeUp();
+ auto words = std::array<uint32_t, 4>();
+ entropy_seq.generate(words.begin(), words.end());
+ uint64_t msb = static_cast<uint64_t>(words[0]) << 32u | words[1];
+ uint64_t lsb = static_cast<uint64_t>(words[2]) << 32u | words[3];
+ return Uuid(static_cast<int64_t>(lsb), static_cast<int64_t>(msb));
}
-bool UnixTaskRunner::QuitCalled() {
- std::lock_guard<base::MaybeRtMutex> lock(lock_);
- return quit_;
+Uuid::Uuid() {}
+
+Uuid::Uuid(const std::string& s) {
+ PERFETTO_CHECK(s.size() == data_.size());
+ memcpy(data_.data(), s.data(), s.size());
}
-bool UnixTaskRunner::IsIdleForTesting() {
- std::lock_guard<base::MaybeRtMutex> lock(lock_);
- return immediate_tasks_.empty();
+Uuid::Uuid(int64_t lsb, int64_t msb) {
+ set_lsb_msb(lsb, msb);
}
-void UnixTaskRunner::AdvanceTimeForTesting(uint32_t ms) {
- std::lock_guard<base::MaybeRtMutex> lock(lock_);
- advanced_time_for_testing_ += TimeMillis(ms);
+std::string Uuid::ToString() const {
+ return std::string(reinterpret_cast<const char*>(data_.data()), data_.size());
}
-void UnixTaskRunner::UpdateWatchTasksLocked() {
- PERFETTO_DCHECK_THREAD(thread_checker_);
-#if !PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
- if (!watch_tasks_changed_)
- return;
- watch_tasks_changed_ = false;
-#endif
- poll_fds_.clear();
- for (auto& it : watch_tasks_) {
- PlatformHandle handle = it.first;
- WatchTask& watch_task = it.second;
-#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
- if (!watch_task.pending)
- poll_fds_.push_back(handle);
-#else
- watch_task.poll_fd_index = poll_fds_.size();
- poll_fds_.push_back({handle, POLLIN | POLLHUP, 0});
-#endif
- }
-}
-
-void UnixTaskRunner::RunImmediateAndDelayedTask() {
- // If locking overhead becomes an issue, add a separate work queue.
- std::function<void()> immediate_task;
- std::function<void()> delayed_task;
- TimeMillis now = GetWallTimeMs();
- {
- std::lock_guard<base::MaybeRtMutex> lock(lock_);
- if (!immediate_tasks_.empty()) {
- immediate_task = std::move(immediate_tasks_.front());
- immediate_tasks_.pop_front();
- }
- if (!delayed_tasks_.empty()) {
- auto it = delayed_tasks_.begin();
- if (now + advanced_time_for_testing_ >= it->first) {
- delayed_task = std::move(it->second);
- delayed_tasks_.erase(it);
- }
- }
- }
-
- errno = 0;
- if (immediate_task)
- RunTaskWithWatchdogGuard(immediate_task);
- errno = 0;
- if (delayed_task)
- RunTaskWithWatchdogGuard(delayed_task);
-}
-
-void UnixTaskRunner::PostFileDescriptorWatches(uint64_t windows_wait_result) {
- PERFETTO_DCHECK_THREAD(thread_checker_);
- for (size_t i = 0; i < poll_fds_.size(); i++) {
-#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
- const PlatformHandle handle = poll_fds_[i];
- // |windows_wait_result| is the result of WaitForMultipleObjects() call. If
- // one of the objects was signalled, it will have a value between
- // [0, poll_fds_.size()].
- if (i != windows_wait_result &&
- WaitForSingleObject(handle, 0) != WAIT_OBJECT_0) {
- continue;
- }
-#else
- base::ignore_result(windows_wait_result);
- const PlatformHandle handle = poll_fds_[i].fd;
- if (!(poll_fds_[i].revents & (POLLIN | POLLHUP)))
- continue;
- poll_fds_[i].revents = 0;
-#endif
-
- // The wake-up event is handled inline to avoid an infinite recursion of
- // posted tasks.
- if (handle == event_.fd()) {
- event_.Clear();
- continue;
- }
-
- // Binding to |this| is safe since we are the only object executing the
- // task.
- PostTask(std::bind(&UnixTaskRunner::RunFileDescriptorWatch, this, handle));
-
- // Flag the task as pending.
-#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
- // On Windows this is done by marking the WatchTask entry as pending. This
- // is more expensive than Linux as requires rebuilding the |poll_fds_|
- // vector on each call. There doesn't seem to be a good alternative though.
- auto it = watch_tasks_.find(handle);
- PERFETTO_CHECK(it != watch_tasks_.end());
- PERFETTO_DCHECK(!it->second.pending);
- it->second.pending = true;
-#else
- // On UNIX systems instead, we just make the fd negative while its task is
- // pending. This makes poll(2) ignore the fd.
- PERFETTO_DCHECK(poll_fds_[i].fd >= 0);
- poll_fds_[i].fd = -poll_fds_[i].fd;
-#endif
- }
-}
-
-void UnixTaskRunner::RunFileDescriptorWatch(PlatformHandle fd) {
- std::function<void()> task;
- {
- std::lock_guard<base::MaybeRtMutex> lock(lock_);
- auto it = watch_tasks_.find(fd);
- if (it == watch_tasks_.end())
- return;
- WatchTask& watch_task = it->second;
-
- // Make poll(2) pay attention to the fd again. Since another thread may have
- // updated this watch we need to refresh the set first.
- UpdateWatchTasksLocked();
-
-#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
- // On Windows we manually track the presence of outstanding tasks for the
- // watch. The UpdateWatchTasksLocked() in the Run() loop will re-add the
- // task to the |poll_fds_| vector.
- PERFETTO_DCHECK(watch_task.pending);
- watch_task.pending = false;
-#else
- size_t fd_index = watch_task.poll_fd_index;
- PERFETTO_DCHECK(fd_index < poll_fds_.size());
- PERFETTO_DCHECK(::abs(poll_fds_[fd_index].fd) == fd);
- poll_fds_[fd_index].fd = fd;
-#endif
- task = watch_task.callback;
- }
- errno = 0;
- RunTaskWithWatchdogGuard(task);
-}
-
-int UnixTaskRunner::GetDelayMsToNextTaskLocked() const {
- PERFETTO_DCHECK_THREAD(thread_checker_);
- if (!immediate_tasks_.empty())
- return 0;
- if (!delayed_tasks_.empty()) {
- TimeMillis diff = delayed_tasks_.begin()->first - GetWallTimeMs() -
- advanced_time_for_testing_;
- return std::max(0, static_cast<int>(diff.count()));
+std::string Uuid::ToPrettyString() const {
+ std::string s(data_.size() * 2 + 4, '-');
+ // Format is 123e4567-e89b-12d3-a456-426655443322.
+ size_t j = 0;
+ for (size_t i = 0; i < data_.size(); ++i) {
+ if (i == 4 || i == 6 || i == 8 || i == 10)
+ j++;
+ s[2 * i + j] = kHexmap[(data_[data_.size() - i - 1] & 0xf0) >> 4];
+ s[2 * i + 1 + j] = kHexmap[(data_[data_.size() - i - 1] & 0x0f)];
}
- return -1;
+ return s;
}
-void UnixTaskRunner::PostTask(std::function<void()> task) {
- bool was_empty;
- {
- std::lock_guard<base::MaybeRtMutex> lock(lock_);
- was_empty = immediate_tasks_.empty();
- immediate_tasks_.push_back(std::move(task));
- }
- if (was_empty)
- WakeUp();
-}
+} // namespace base
+} // namespace perfetto
+// gen_amalgamated begin source: src/base/virtual_destructors.cc
+/*
+ * 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.
+ */
-void UnixTaskRunner::PostDelayedTask(std::function<void()> task,
- uint32_t delay_ms) {
- TimeMillis runtime = GetWallTimeMs() + TimeMillis(delay_ms);
- {
- std::lock_guard<base::MaybeRtMutex> lock(lock_);
- delayed_tasks_.insert(
- std::make_pair(runtime + advanced_time_for_testing_, std::move(task)));
- }
- WakeUp();
-}
+// gen_amalgamated expanded: #include "perfetto/base/task_runner.h"
-void UnixTaskRunner::AddFileDescriptorWatch(PlatformHandle fd,
- std::function<void()> task) {
- PERFETTO_DCHECK(PlatformHandleChecker::IsValid(fd));
- {
- std::lock_guard<base::MaybeRtMutex> lock(lock_);
- PERFETTO_DCHECK(!watch_tasks_.count(fd));
- WatchTask& watch_task = watch_tasks_[fd];
- watch_task.callback = std::move(task);
-#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
- watch_task.pending = false;
-#else
- watch_task.poll_fd_index = SIZE_MAX;
-#endif
- watch_tasks_changed_ = true;
- }
- WakeUp();
-}
+// This translation unit contains the definitions for the destructor of pure
+// virtual interfaces for the current build target. The alternative would be
+// introducing a one-liner .cc file for each pure virtual interface, which is
+// overkill. This is for compliance with -Wweak-vtables.
-void UnixTaskRunner::RemoveFileDescriptorWatch(PlatformHandle fd) {
- PERFETTO_DCHECK(PlatformHandleChecker::IsValid(fd));
- {
- std::lock_guard<base::MaybeRtMutex> lock(lock_);
- PERFETTO_DCHECK(watch_tasks_.count(fd));
- watch_tasks_.erase(fd);
- watch_tasks_changed_ = true;
- }
- // No need to schedule a wake-up for this.
-}
+namespace perfetto {
+namespace base {
-bool UnixTaskRunner::RunsTasksOnCurrentThread() const {
- return GetThreadId() == created_thread_id_.load(std::memory_order_relaxed);
-}
+TaskRunner::~TaskRunner() = default;
} // namespace base
} // namespace perfetto
-// gen_amalgamated begin source: src/base/subprocess.cc
-// gen_amalgamated begin header: include/perfetto/ext/base/subprocess.h
+// gen_amalgamated begin source: src/base/waitable_event.cc
+// gen_amalgamated begin header: include/perfetto/ext/base/waitable_event.h
/*
- * Copyright (C) 2020 The Android Open Source Project
+ * 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.
@@ -13174,278 +13316,46 @@ bool UnixTaskRunner::RunsTasksOnCurrentThread() const {
* limitations under the License.
*/
-#ifndef INCLUDE_PERFETTO_EXT_BASE_SUBPROCESS_H_
-#define INCLUDE_PERFETTO_EXT_BASE_SUBPROCESS_H_
+#ifndef INCLUDE_PERFETTO_EXT_BASE_WAITABLE_EVENT_H_
+#define INCLUDE_PERFETTO_EXT_BASE_WAITABLE_EVENT_H_
+
+// gen_amalgamated expanded: #include "perfetto/base/thread_annotations.h"
+
+#include <stdint.h>
#include <condition_variable>
-#include <functional>
-#include <initializer_list>
-#include <memory>
#include <mutex>
-#include <optional>
-#include <string>
-#include <thread>
-#include <vector>
-
-// gen_amalgamated expanded: #include "perfetto/base/build_config.h"
-// gen_amalgamated expanded: #include "perfetto/base/logging.h"
-// gen_amalgamated expanded: #include "perfetto/base/platform_handle.h"
-// gen_amalgamated expanded: #include "perfetto/base/proc_utils.h"
-// gen_amalgamated expanded: #include "perfetto/ext/base/event_fd.h"
-// gen_amalgamated expanded: #include "perfetto/ext/base/pipe.h"
-// gen_amalgamated expanded: #include "perfetto/ext/base/scoped_file.h"
namespace perfetto {
namespace base {
-// Handles creation and lifecycle management of subprocesses, taking care of
-// all subtleties involved in handling processes on UNIX.
-// This class allows to deal with macro two use-cases:
-// 1) fork() + exec() equivalent: for spawning a brand new process image.
-// This happens when |args.exec_cmd| is not empty.
-// This is safe to use even in a multi-threaded environment.
-// 2) fork(): for spawning a process and running a function.
-// This happens when |args.posix_entrypoint_for_testing| is not empty.
-// This is intended only for tests as it is extremely subtle.
-// This mode must be used with extreme care. Before the entrypoint is
-// invoked all file descriptors other than stdin/out/err and the ones
-// specified in |args.preserve_fds| will be closed, to avoid each process
-// retaining a dupe of other subprocesses pipes. This however means that
-// any non trivial calls (including logging) must be avoided as they might
-// refer to FDs that are now closed. The entrypoint should really be used
-// just to signal a pipe or similar for synchronizing sequencing in tests.
-
-//
-// This class allows to control stdin/out/err pipe redirection and takes care
-// of keeping all the pipes pumped (stdin) / drained (stdout/err), in a similar
-// fashion of python's subprocess.Communicate()
-// stdin: is always piped and closed once the |args.input| buffer is written.
-// stdout/err can be either:
-// - dup()ed onto the parent process stdout/err.
-// - redirected onto /dev/null.
-// - piped onto a buffer (see output() method). There is only one output
-// buffer in total. If both stdout and stderr are set to kBuffer mode, they
-// will be merged onto the same. There doesn't seem any use case where they
-// are needed distinctly.
-//
-// Some caveats worth mentioning:
-// - It always waitpid()s, to avoid leaving zombies around. If the process is
-// not terminated by the time the destructor is reached, the dtor will
-// send a SIGKILL and wait for the termination.
-// - After fork()-ing it will close all file descriptors, preserving only
-// stdin/out/err and the fds listed in |args.preserve_fds|.
-// - On Linux/Android, the child process will be SIGKILL-ed if the calling
-// thread exists, even if the Subprocess is std::move()-d onto another thread.
-// This happens by virtue PR_SET_PDEATHSIG, which is used to avoid that
-// child processes are leaked in the case of a crash of the parent (frequent
-// in tests). However, the child process might still be leaked if execing
-// a setuid/setgid binary (see man 2 prctl).
-//
-// Usage:
-// base::Subprocess p({"/bin/cat", "-"});
-// (or equivalently:
-// base::Subprocess p;
-// p.args.exec_cmd.push_back("/bin/cat");
-// p.args.exec_cmd.push_back("-");
-// )
-// p.args.stdout_mode = base::Subprocess::kBuffer;
-// p.args.stderr_mode = base::Subprocess::kInherit;
-// p.args.input = "stdin contents";
-// p.Call();
-// (or equivalently:
-// p.Start();
-// p.Wait();
-// )
-// EXPECT_EQ(p.status(), base::Subprocess::kTerminated);
-// EXPECT_EQ(p.returncode(), 0);
-class Subprocess {
+// A waitable event for cross-thread synchronization.
+// All methods on this class can be called from any thread.
+class WaitableEvent {
public:
- enum Status {
- kNotStarted = 0, // Before calling Start() or Call().
- kRunning, // After calling Start(), before Wait().
- kTerminated, // The subprocess terminated, either successfully or not.
- // This includes crashes or other signals on UNIX.
- };
-
- enum class OutputMode {
- kInherit = 0, // Inherit's the caller process stdout/stderr.
- kDevNull, // dup() onto /dev/null.
- kBuffer, // dup() onto a pipe and move it into the output() buffer.
- kFd, // dup() onto the passed args.fd.
- };
-
- enum class InputMode {
- kBuffer = 0, // dup() onto a pipe and write args.input on it.
- kDevNull, // dup() onto /dev/null.
- };
-
- // Input arguments for configuring the subprocess behavior.
- struct Args {
- Args(std::initializer_list<std::string> _cmd = {}) : exec_cmd(_cmd) {}
- Args(Args&&) noexcept;
- Args& operator=(Args&&);
- // If non-empty this will cause an exec() when Start()/Call() are called.
- std::vector<std::string> exec_cmd;
-
-#if !PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
- // If non-empty, it changes the argv[0] argument passed to exec. If
- // unset, argv[0] == exec_cmd[0]. This is to handle cases like:
- // exec_cmd = {"/proc/self/exec"}, argv0: "my_custom_test_override".
- std::string posix_argv0_override_for_testing;
-
- // If non-empty this will be invoked on the fork()-ed child process, after
- // stdin/out/err has been redirected and all other file descriptor are
- // closed. It is valid to specify both |exec_cmd| AND
- // |posix_entrypoint_for_testing|. In this case the latter will be invoked
- // just before the exec() call, but after having closed all fds % stdin/o/e.
- // This is for synchronization barriers in tests.
- std::function<void()> posix_entrypoint_for_testing;
-
- // When set, will will move the process to the given process group. If set
- // and zero, it will create a new process group. Effectively this calls
- // setpgid(0 /*self_pid*/, posix_proc_group_id).
- // This can be used to avoid that subprocesses receive CTRL-C from the
- // terminal, while still living in the same session.
- std::optional<pid_t> posix_proc_group_id{};
-#endif
-
- // If non-empty, replaces the environment passed to exec().
- std::vector<std::string> env;
-
- // The file descriptors in this list will not be closed.
- std::vector<int> preserve_fds;
-
- // The data to push in the child process stdin, if input_mode ==
- // InputMode::kBuffer.
- std::string input;
-
- InputMode stdin_mode = InputMode::kBuffer;
- OutputMode stdout_mode = OutputMode::kInherit;
- OutputMode stderr_mode = OutputMode::kInherit;
-
- base::ScopedPlatformHandle out_fd;
-
- // Returns " ".join(exec_cmd), quoting arguments.
- std::string GetCmdString() const;
- };
-
- struct ResourceUsage {
- uint32_t cpu_utime_ms = 0;
- uint32_t cpu_stime_ms = 0;
- uint32_t max_rss_kb = 0;
- uint32_t min_page_faults = 0;
- uint32_t maj_page_faults = 0;
- uint32_t vol_ctx_switch = 0;
- uint32_t invol_ctx_switch = 0;
-
- uint32_t cpu_time_ms() const { return cpu_utime_ms + cpu_stime_ms; }
- };
-
- explicit Subprocess(std::initializer_list<std::string> exec_cmd = {});
- Subprocess(Subprocess&&) noexcept;
- Subprocess& operator=(Subprocess&&);
- ~Subprocess(); // It will KillAndWaitForTermination() if still alive.
-
- // Starts the subprocess but doesn't wait for its termination. The caller
- // is expected to either call Wait() or Poll() after this call.
- void Start();
-
- // Wait for process termination. Can be called more than once.
- // Args:
- // |timeout_ms| = 0: wait indefinitely.
- // |timeout_ms| > 0: wait for at most |timeout_ms|.
- // Returns:
- // True: The process terminated. See status() and returncode().
- // False: Timeout reached, the process is still running. In this case the
- // process will be left in the kRunning state.
- bool Wait(int timeout_ms = 0);
-
- // Equivalent of Start() + Wait();
- // Returns true if the process exited cleanly with return code 0. False in
- // any othe case.
- bool Call(int timeout_ms = 0);
-
- Status Poll();
-
- // Kills the process (SIGKILL if not specified) but doesn't wait for its
- // termination.
- void Kill(int sig_num = 0);
-
- // Sends a signal (SIGKILL if not specified) and wait for process termination.
- void KillAndWaitForTermination(int sig_num = 0);
-
- PlatformProcessId pid() const { return s_->pid; }
-
- // The accessors below are updated only after a call to Poll(), Wait() or
- // KillAndWaitForTermination().
- // In most cases you want to call Poll() rather than these accessors.
-
- Status status() const { return s_->status; }
- int returncode() const { return s_->returncode; }
- bool timed_out() const { return s_->timed_out; }
-
- // This contains both stdout and stderr (if the corresponding _mode ==
- // OutputMode::kBuffer). It's non-const so the caller can std::move() it.
- std::string& output() { return s_->output; }
- const std::string& output() const { return s_->output; }
+ WaitableEvent();
+ ~WaitableEvent();
+ WaitableEvent(const WaitableEvent&) = delete;
+ WaitableEvent operator=(const WaitableEvent&) = delete;
- const ResourceUsage& posix_rusage() const { return *s_->rusage; }
+ // Synchronously block until the event is notified `notification` times.
+ void Wait(uint64_t notifications = 1);
- Args args;
+ // Signal the event, waking up blocked waiters.
+ void Notify();
private:
- // The signal/exit code used when killing the process in case of a timeout.
- static const int kTimeoutSignal;
-
- Subprocess(const Subprocess&) = delete;
- Subprocess& operator=(const Subprocess&) = delete;
-
- // This is to deal robustly with the move operators, without having to
- // manually maintain member-wise move instructions.
- struct MovableState {
- base::Pipe stdin_pipe;
- base::Pipe stdouterr_pipe;
- PlatformProcessId pid;
- Status status = kNotStarted;
- int returncode = -1;
- std::string output; // Stdin+stderr. Only when OutputMode::kBuffer.
- std::unique_ptr<ResourceUsage> rusage{new ResourceUsage()};
- bool timed_out = false;
-#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
- std::thread stdouterr_thread;
- std::thread stdin_thread;
- ScopedPlatformHandle win_proc_handle;
- ScopedPlatformHandle win_thread_handle;
-
- base::EventFd stdouterr_done_event;
- std::mutex mutex; // Protects locked_outerr_buf and the two pipes.
- std::string locked_outerr_buf;
-#else
- base::Pipe exit_status_pipe;
- size_t input_written = 0;
- std::thread waitpid_thread;
-#endif
- };
-
-#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
- static void StdinThread(MovableState*, const std::string& input);
- static void StdoutErrThread(MovableState*);
-#else
- void TryPushStdin();
- void TryReadStdoutAndErr();
- void TryReadExitStatus();
- bool PollInternal(int poll_timeout_ms);
-#endif
-
- std::unique_ptr<MovableState> s_;
+ std::mutex mutex_;
+ std::condition_variable event_ PERFETTO_GUARDED_BY(mutex_);
+ uint64_t notifications_ PERFETTO_GUARDED_BY(mutex_) = 0;
};
} // namespace base
} // namespace perfetto
-#endif // INCLUDE_PERFETTO_EXT_BASE_SUBPROCESS_H_
+#endif // INCLUDE_PERFETTO_EXT_BASE_WAITABLE_EVENT_H_
/*
- * Copyright (C) 2020 The Android Open Source Project
+ * 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.
@@ -13460,73 +13370,138 @@ class Subprocess {
* limitations under the License.
*/
-// gen_amalgamated expanded: #include "perfetto/ext/base/subprocess.h"
-
-#include <tuple>
-
-// This file contains only the common bits (ctors / dtors / move operators).
-// The rest lives in subprocess_posix.cc and subprocess_windows.cc.
+// gen_amalgamated expanded: #include "perfetto/ext/base/waitable_event.h"
namespace perfetto {
namespace base {
-Subprocess::Args::Args(Args&&) noexcept = default;
-Subprocess::Args& Subprocess::Args::operator=(Args&&) = default;
+WaitableEvent::WaitableEvent() = default;
+WaitableEvent::~WaitableEvent() = default;
-Subprocess::Subprocess(std::initializer_list<std::string> a)
- : args(a), s_(new MovableState()) {}
-
-Subprocess::Subprocess(Subprocess&& other) noexcept {
- static_assert(sizeof(Subprocess) ==
- sizeof(std::tuple<std::unique_ptr<MovableState>, Args>),
- "base::Subprocess' move ctor needs updating");
- s_ = std::move(other.s_);
- args = std::move(other.args);
-
- // Reset the state of the moved-from object.
- other.s_.reset(new MovableState());
- other.~Subprocess();
- new (&other) Subprocess();
+void WaitableEvent::Wait(uint64_t notifications)
+ PERFETTO_NO_THREAD_SAFETY_ANALYSIS {
+ // 'std::unique_lock' lock doesn't work well with thread annotations
+ // (see https://github.com/llvm/llvm-project/issues/63239),
+ // so we suppress thread safety static analysis for this method.
+ std::unique_lock<std::mutex> lock(mutex_);
+ return event_.wait(lock, [&]() PERFETTO_EXCLUSIVE_LOCKS_REQUIRED(mutex_) {
+ return notifications_ >= notifications;
+ });
}
-Subprocess& Subprocess::operator=(Subprocess&& other) {
- this->~Subprocess();
- new (this) Subprocess(std::move(other));
- return *this;
+void WaitableEvent::Notify() {
+ std::lock_guard<std::mutex> lock(mutex_);
+ ++notifications_;
+ event_.notify_all();
}
-Subprocess::~Subprocess() {
- if (s_->status == kRunning)
- KillAndWaitForTermination();
-}
+} // namespace base
+} // namespace perfetto
+// gen_amalgamated begin source: src/base/watchdog_posix.cc
+// gen_amalgamated begin header: include/perfetto/ext/base/watchdog.h
+// gen_amalgamated begin header: include/perfetto/ext/base/flags.h
+/*
+ * Copyright (C) 2025 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.
+ */
-bool Subprocess::Call(int timeout_ms) {
- PERFETTO_CHECK(s_->status == kNotStarted);
- Start();
+#ifndef INCLUDE_PERFETTO_EXT_BASE_FLAGS_H_
+#define INCLUDE_PERFETTO_EXT_BASE_FLAGS_H_
- if (!Wait(timeout_ms)) {
- s_->timed_out = true;
- KillAndWaitForTermination(kTimeoutSignal);
- }
- PERFETTO_DCHECK(s_->status != kRunning);
- return s_->status == kTerminated && s_->returncode == 0;
-}
+// gen_amalgamated expanded: #include "perfetto/base/build_config.h"
-std::string Subprocess::Args::GetCmdString() const {
- std::string str;
- for (size_t i = 0; i < exec_cmd.size(); i++) {
- str += i > 0 ? " \"" : "";
- str += exec_cmd[i];
- str += i > 0 ? "\"" : "";
+#if PERFETTO_BUILDFLAG(PERFETTO_ANDROID_BUILD) && \
+ PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID)
+// Android: aconfig generates PERFETTO_FLAGS_* macros in perfetto_flags.h
+#include <perfetto_flags.h>
+#else
+// Non-Android: Define fallback PERFETTO_FLAGS_* macros
+// These match the pattern from Android's aconfig codegen
+#define PERFETTO_FLAGS(FLAG) PERFETTO_FLAGS_##FLAG
+
+#define PERFETTO_FLAGS_TEST_READ_ONLY_FLAG false
+#define PERFETTO_FLAGS_USE_LOCKFREE_TASKRUNNER \
+ PERFETTO_BUILDFLAG(PERFETTO_ENABLE_LOCKFREE_TASKRUNNER)
+#define PERFETTO_FLAGS_BUFFER_CLONE_PRESERVE_READ_ITER true
+#define PERFETTO_FLAGS_USE_UNIX_SOCKET_INOTIFY \
+ PERFETTO_BUILDFLAG(PERFETTO_ENABLE_SOCK_INOTIFY)
+#define PERFETTO_FLAGS_TRIGGER_PERFETTO_ON_TRACED_PROBES_DISCONNECT false
+#define PERFETTO_FLAGS_USE_ANON_RSS_IN_WATCHDOG true
+
+#endif // PERFETTO_BUILDFLAG(PERFETTO_ANDROID_BUILD) && ...
+
+#endif // INCLUDE_PERFETTO_EXT_BASE_FLAGS_H_
+// gen_amalgamated begin header: include/perfetto/ext/base/watchdog_noop.h
+/*
+ * 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.
+ */
+
+#ifndef INCLUDE_PERFETTO_EXT_BASE_WATCHDOG_NOOP_H_
+#define INCLUDE_PERFETTO_EXT_BASE_WATCHDOG_NOOP_H_
+
+#include <stdint.h>
+
+#include <functional>
+
+namespace perfetto {
+namespace base {
+
+class TaskRunner;
+
+enum class WatchdogCrashReason; // Defined in watchdog.h.
+struct WatchdogCrashInfo; // Defined in watchdog.h.
+
+class Watchdog {
+ public:
+ class Timer {
+ public:
+ // Define an empty dtor to avoid "unused variable" errors on the call site.
+ Timer() {}
+ Timer(const Timer&) {}
+ ~Timer() {}
+ };
+ static Watchdog* GetInstance() {
+ static Watchdog* watchdog = new Watchdog();
+ return watchdog;
}
- return str;
-}
+ Timer CreateFatalTimer(uint32_t /*ms*/, WatchdogCrashReason) {
+ return Timer();
+ }
+ void Start(TaskRunner* /*task_runner*/ = nullptr,
+ std::function<void(WatchdogCrashInfo)> /*handler*/ = {}) {}
+ void SetMemoryLimit(uint64_t /*bytes*/, uint32_t /*window_ms*/) {}
+ void SetCpuLimit(uint32_t /*percentage*/, uint32_t /*window_ms*/) {}
+};
} // namespace base
} // namespace perfetto
-// gen_amalgamated begin source: src/base/subprocess_posix.cc
+
+#endif // INCLUDE_PERFETTO_EXT_BASE_WATCHDOG_NOOP_H_
/*
- * Copyright (C) 2020 The Android Open Source Project
+ * 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.
@@ -13541,451 +13516,655 @@ std::string Subprocess::Args::GetCmdString() const {
* limitations under the License.
*/
-// gen_amalgamated expanded: #include "perfetto/ext/base/subprocess.h"
+#ifndef INCLUDE_PERFETTO_EXT_BASE_WATCHDOG_H_
+#define INCLUDE_PERFETTO_EXT_BASE_WATCHDOG_H_
+
+#include <functional>
// gen_amalgamated expanded: #include "perfetto/base/build_config.h"
+// gen_amalgamated expanded: #include "perfetto/ext/base/flags.h"
-#if PERFETTO_BUILDFLAG(PERFETTO_OS_LINUX) || \
- PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID) || \
- PERFETTO_BUILDFLAG(PERFETTO_OS_FREEBSD) || \
- PERFETTO_BUILDFLAG(PERFETTO_OS_APPLE)
+// The POSIX watchdog is only supported on Linux and Android in non-embedder
+// builds.
+#if PERFETTO_BUILDFLAG(PERFETTO_WATCHDOG)
+// gen_amalgamated expanded: #include "perfetto/ext/base/watchdog_posix.h"
+#else
+// gen_amalgamated expanded: #include "perfetto/ext/base/watchdog_noop.h"
+#endif
+
+namespace perfetto {
+namespace base {
+
+// Used only to add more details to crash reporting.
+enum class WatchdogCrashReason {
+ kUnspecified = 0,
+ kCpuGuardrail = 1,
+ kMemGuardrail = 2,
+ kTaskRunnerHung = 3,
+ kTraceDidntStop = 4,
+};
+
+// Information about an imminent watchdog-triggered crash. Passed to the fatal
+// handler installed via Watchdog::Start() so embedders can record it (e.g. via
+// metatrace counters) before the process is force-killed.
+struct WatchdogCrashInfo {
+ int thread_id = 0;
+ WatchdogCrashReason reason = WatchdogCrashReason::kUnspecified;
+
+ // The time in CLOCK_BOOTTIME when the watchdog triggered.
+ int64_t alarm_time_ms = 0;
+
+ // The initial timeout passed to CreateFatalTimer.
+ int timeout_s = 0;
+
+ // Elapsed seconds, since the offending fatal timer was created, sampled
+ // from CLOCK_MONOTONIC, CLOCK_BOOTTIME and CLOCK_PROCESS_CPUTIME_ID
+ // respectively. These mirror the wdog_actual_{mono,boot,cpu} crash keys.
+ // They are 0 for cpu/memory guardrail crashes (no associated timer).
+ int actual_mono_s = 0;
+ int actual_boot_s = 0;
+ int actual_cpu_s = 0;
+};
+
+// Make the limits more relaxed on desktop, where multi-GB traces are likely.
+// Multi-GB traces can take bursts of cpu time to write into disk at the end of
+// the trace.
+#if PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID)
+constexpr uint32_t kWatchdogDefaultCpuLimit = 75;
+constexpr uint32_t kWatchdogDefaultCpuWindow = 5 * 60 * 1000; // 5 minutes.
+#else
+constexpr uint32_t kWatchdogDefaultCpuLimit = 90;
+constexpr uint32_t kWatchdogDefaultCpuWindow = 10 * 60 * 1000; // 10 minutes.
+#endif
+
+// The default memory margin we give to our processes. This is used as as a
+// constant to put on top of the trace buffers.
+constexpr uint64_t kWatchdogDefaultMemorySlack =
+ PERFETTO_FLAGS(USE_ANON_RSS_IN_WATCHDOG) ? 32 * 1024 * 1024 // 32 MiB
+ : 64 * 1024 * 1024; // 64 MiB
+constexpr uint32_t kWatchdogDefaultMemoryWindow = 30 * 1000; // 30 seconds.
+
+inline void RunTaskWithWatchdogGuard(const std::function<void()>& task) {
+ // The longest duration allowed for a single task within the TaskRunner.
+ // Exceeding this limit will trigger program termination.
+ constexpr int64_t kWatchdogMillis = 180000; // 180s
+
+ Watchdog::Timer handle = base::Watchdog::GetInstance()->CreateFatalTimer(
+ kWatchdogMillis, WatchdogCrashReason::kTaskRunnerHung);
+ task();
+
+ // Suppress unused variable warnings in the client library amalgamated build.
+ (void)kWatchdogDefaultCpuLimit;
+ (void)kWatchdogDefaultCpuWindow;
+ (void)kWatchdogDefaultMemorySlack;
+ (void)kWatchdogDefaultMemoryWindow;
+}
+
+} // namespace base
+} // namespace perfetto
+
+#endif // INCLUDE_PERFETTO_EXT_BASE_WATCHDOG_H_
+/*
+ * 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.
+ */
+
+// gen_amalgamated expanded: #include "perfetto/ext/base/platform.h"
+// gen_amalgamated expanded: #include "perfetto/ext/base/string_utils.h"
+// gen_amalgamated expanded: #include "perfetto/ext/base/watchdog.h"
+
+#if PERFETTO_BUILDFLAG(PERFETTO_WATCHDOG)
#include <fcntl.h>
#include <poll.h>
#include <signal.h>
-#include <stdio.h>
-#include <sys/resource.h>
-#include <sys/types.h>
-#include <sys/wait.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <sys/syscall.h>
+#include <sys/timerfd.h>
#include <unistd.h>
#include <algorithm>
+#include <cinttypes>
+#include <fstream>
+#include <optional>
#include <thread>
-#include <tuple>
-
-#if PERFETTO_BUILDFLAG(PERFETTO_OS_LINUX_BUT_NOT_QNX) || \
- PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID)
-#include <sys/prctl.h>
-#endif
+// gen_amalgamated expanded: #include "perfetto/base/build_config.h"
// gen_amalgamated expanded: #include "perfetto/base/logging.h"
+// gen_amalgamated expanded: #include "perfetto/base/task_runner.h"
+// gen_amalgamated expanded: #include "perfetto/base/thread_utils.h"
// gen_amalgamated expanded: #include "perfetto/base/time.h"
+// gen_amalgamated expanded: #include "perfetto/ext/base/crash_keys.h"
+// gen_amalgamated expanded: #include "perfetto/ext/base/file_utils.h"
+// gen_amalgamated expanded: #include "perfetto/ext/base/flags.h"
+// gen_amalgamated expanded: #include "perfetto/ext/base/scoped_file.h"
// gen_amalgamated expanded: #include "perfetto/ext/base/utils.h"
-// In MacOS this is not defined in any header.
-extern "C" char** environ;
-
namespace perfetto {
namespace base {
namespace {
-struct ChildProcessArgs {
- Subprocess::Args* create_args;
- const char* exec_cmd = nullptr;
- std::vector<char*> argv;
- std::vector<char*> env;
- int stdin_pipe_rd = -1;
- int stdouterr_pipe_wr = -1;
-};
-
-// Don't add any dynamic allocation in this function. This will be invoked
-// under a fork(), potentially in a state where the allocator lock is held.
-void __attribute__((noreturn)) ChildProcess(ChildProcessArgs* args) {
-#if PERFETTO_BUILDFLAG(PERFETTO_OS_LINUX_BUT_NOT_QNX) || \
- PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID)
- // In no case we want a child process to outlive its parent process. This is
- // relevant for tests, so that a test failure/crash doesn't leave child
- // processes around that get reparented to init.
- prctl(PR_SET_PDEATHSIG, SIGKILL);
-#endif
-
- auto die = [args](const char* err) __attribute__((noreturn)) {
- base::ignore_result(write(args->stdouterr_pipe_wr, err, strlen(err)));
- base::ignore_result(write(args->stdouterr_pipe_wr, "\n", 1));
- // From https://www.gnu.org/software/libc/manual/html_node/Exit-Status.html
- // "In particular, the value 128 is used to indicate failure to execute
- // another program in a subprocess. This convention is not universally
- // obeyed, but it is a good idea to follow it in your programs."
- _exit(128);
- };
+constexpr uint32_t kDefaultPollingInterval = 30 * 1000;
- if (args->create_args->posix_proc_group_id.has_value()) {
- if (setpgid(0 /*self*/, args->create_args->posix_proc_group_id.value())) {
- die("setpgid() failed");
- }
- }
+// Grace period given to a fatal handler (passed to Start()) to
+// crash the process on its own before the watchdog force-kills it.
+constexpr uint32_t kFatalHandlerGraceMs = 60 * 1000;
- auto set_fd_close_on_exec = [&die](int fd, bool close_on_exec) {
- int flags = fcntl(fd, F_GETFD, 0);
- if (flags < 0)
- die("fcntl(F_GETFD) failed");
- flags = close_on_exec ? (flags | FD_CLOEXEC) : (flags & ~FD_CLOEXEC);
- if (fcntl(fd, F_SETFD, flags) < 0)
- die("fcntl(F_SETFD) failed");
- };
+base::CrashKey g_crash_key_reason("wdog_reason");
+base::CrashKey g_crash_key_timeout("wdog_timeout");
+base::CrashKey g_crash_key_actual_mono("wdog_actual_mono");
+base::CrashKey g_crash_key_actual_boot("wdog_actual_boot");
+base::CrashKey g_crash_key_actual_cpu("wdog_actual_cpu");
- if (getppid() == 1)
- die("terminating because parent process died");
+bool IsMultipleOf(uint32_t number, uint32_t divisor) {
+ return number >= divisor && number % divisor == 0;
+}
- switch (args->create_args->stdin_mode) {
- case Subprocess::InputMode::kBuffer:
- if (dup2(args->stdin_pipe_rd, STDIN_FILENO) == -1)
- die("Failed to dup2(STDIN)");
- close(args->stdin_pipe_rd);
- break;
- case Subprocess::InputMode::kDevNull:
- if (dup2(open("/dev/null", O_RDONLY), STDIN_FILENO) == -1)
- die("Failed to dup2(STDOUT)");
- break;
+double MeanForArray(const uint64_t array[], size_t size) {
+ uint64_t total = 0;
+ for (size_t i = 0; i < size; i++) {
+ total += array[i];
}
+ return static_cast<double>(total / size);
+}
- switch (args->create_args->stdout_mode) {
- case Subprocess::OutputMode::kInherit:
- break;
- case Subprocess::OutputMode::kDevNull: {
- if (dup2(open("/dev/null", O_RDWR), STDOUT_FILENO) == -1)
- die("Failed to dup2(STDOUT)");
- break;
- }
- case Subprocess::OutputMode::kBuffer:
- if (dup2(args->stdouterr_pipe_wr, STDOUT_FILENO) == -1)
- die("Failed to dup2(STDOUT)");
- break;
- case Subprocess::OutputMode::kFd:
- if (dup2(*args->create_args->out_fd, STDOUT_FILENO) == -1)
- die("Failed to dup2(STDOUT)");
+bool ReadFileToString(int fd, char* buf, size_t size) {
+ size_t pos = 0;
+ while (pos < size - 1) {
+ ssize_t rd = PERFETTO_EINTR(read(fd, buf + pos, size - 1 - pos));
+ if (rd < 0)
+ return false;
+ if (rd == 0)
break;
+ pos += static_cast<size_t>(rd);
}
+ buf[pos] = '\0';
+ return true;
+}
- switch (args->create_args->stderr_mode) {
- case Subprocess::OutputMode::kInherit:
- break;
- case Subprocess::OutputMode::kDevNull: {
- if (dup2(open("/dev/null", O_RDWR), STDERR_FILENO) == -1)
- die("Failed to dup2(STDERR)");
- break;
- }
- case Subprocess::OutputMode::kBuffer:
- if (dup2(args->stdouterr_pipe_wr, STDERR_FILENO) == -1)
- die("Failed to dup2(STDERR)");
- break;
- case Subprocess::OutputMode::kFd:
- if (dup2(*args->create_args->out_fd, STDERR_FILENO) == -1)
- die("Failed to dup2(STDERR)");
- break;
- }
+} // namespace
- // Close all FDs % stdin/out/err and the ones that the client explicitly
- // asked to retain. The reason for this is twofold:
- // 1. For exec-only (i.e. entrypoint == empty) cases: it avoids leaking FDs
- // that didn't get marked as O_CLOEXEC by accident.
- // 2. In fork() mode (entrypoint not empty) avoids retaining a dup of eventfds
- // that would prevent the parent process to receive EOFs (tests usually use
- // pipes as a synchronization mechanism between subprocesses).
- const auto& preserve_fds = args->create_args->preserve_fds;
- for (int i = 0; i < 512; i++) {
- if (i != STDIN_FILENO && i != STDERR_FILENO && i != STDOUT_FILENO &&
- i != args->stdouterr_pipe_wr &&
- !std::count(preserve_fds.begin(), preserve_fds.end(), i)) {
- close(i);
- }
+bool ReadProcStat(int fd, ProcStat* out) {
+ char str[512];
+ if (!ReadFileToString(fd, str, sizeof(str))) {
+ PERFETTO_ELOG("Failed to read stat file to enforce resource limits.");
+ return false;
}
- // Clears O_CLOEXEC from stdin/out/err and the |preserve_fds| list. These are
- // the only FDs that we want to be preserved after the exec().
- set_fd_close_on_exec(STDIN_FILENO, false);
- set_fd_close_on_exec(STDOUT_FILENO, false);
- set_fd_close_on_exec(STDERR_FILENO, false);
+ if (sscanf(str,
+ "%*d %*s %*c %*d %*d %*d %*d %*d %*u %*u %*u %*u %*u %lu "
+ "%lu %*d %*d %*d %*d %*d %*d %*u %*u %ld",
+ &out->utime, &out->stime, &out->rss_pages) != 3) {
+ PERFETTO_ELOG("Invalid stat format: %s", str);
+ return false;
+ }
+ return true;
+}
- for (auto fd : preserve_fds)
- set_fd_close_on_exec(fd, false);
+bool ReadProcStatm(int fd, ProcStatm* out) {
+ char str[256];
+ if (!ReadFileToString(fd, str, sizeof(str))) {
+ PERFETTO_ELOG("Failed to read statm file to enforce resource limits.");
+ return false;
+ }
- // If the caller specified a std::function entrypoint, run that first.
- if (args->create_args->posix_entrypoint_for_testing)
- args->create_args->posix_entrypoint_for_testing();
+ if (sscanf(str,
+ "%" SCNu64 " %" SCNu64 " %" SCNu64 " %" SCNu64 " %" SCNu64
+ " %" SCNu64 " %" SCNu64,
+ &out->size, &out->resident, &out->shared, &out->text, &out->lib,
+ &out->data, &out->dt) != 7) {
+ PERFETTO_ELOG("Invalid statm format: %s", str);
+ return false;
+ }
+ return true;
+}
- // If the caller specified only an entrypoint, without any args, exit now.
- // Otherwise proceed with the exec() below.
- if (!args->exec_cmd)
- _exit(0);
+Watchdog::Watchdog(uint32_t polling_interval_ms)
+ : polling_interval_ms_(polling_interval_ms) {}
- // If |args[0]| is a path use execv() (which takes a path), otherwise use
- // exevp(), which uses the shell and follows PATH.
- if (strchr(args->exec_cmd, '/')) {
- char** env = args->env.empty() ? environ : args->env.data();
- execve(args->exec_cmd, args->argv.data(), env);
- } else {
- // There is no execvpe() on Mac.
- if (!args->env.empty())
- die("A full path is required for |exec_cmd| when setting |env|");
- execvp(args->exec_cmd, args->argv.data());
+Watchdog::~Watchdog() {
+ if (!thread_.joinable()) {
+ PERFETTO_DCHECK(!enabled_);
+ return;
}
+ PERFETTO_DCHECK(enabled_);
+ enabled_ = false;
+ // Rearm the timer to 1ns from now. This will cause the watchdog thread to
+ // wakeup from the poll() and see |enabled_| == false.
+ // This code path is used only in tests. In production code the watchdog
+ // is a singleton and is never destroyed.
+ struct itimerspec ts{};
+ ts.it_value.tv_sec = 0;
+ ts.it_value.tv_nsec = 1;
+ timerfd_settime(*timer_fd_, /*flags=*/0, &ts, nullptr);
- // Reached only if execv fails.
- die("execve() failed");
+ thread_.join();
}
-} // namespace
+Watchdog* Watchdog::GetInstance() {
+ static Watchdog* watchdog = new Watchdog(kDefaultPollingInterval);
+ return watchdog;
+}
-// static
-const int Subprocess::kTimeoutSignal = SIGKILL;
+// Can be called from any thread.
+Watchdog::Timer Watchdog::CreateFatalTimer(uint32_t ms,
+ WatchdogCrashReason crash_reason) {
+ if (!enabled_.load(std::memory_order_relaxed))
+ return Watchdog::Timer(this, 0, crash_reason);
-void Subprocess::Start() {
- ChildProcessArgs proc_args;
- proc_args.create_args = &args;
+ return Watchdog::Timer(this, ms, crash_reason);
+}
- // Setup argv.
- if (!args.exec_cmd.empty()) {
- proc_args.exec_cmd = args.exec_cmd[0].c_str();
- for (const std::string& arg : args.exec_cmd)
- proc_args.argv.push_back(const_cast<char*>(arg.c_str()));
- proc_args.argv.push_back(nullptr);
+// Can be called from any thread.
+void Watchdog::AddFatalTimer(TimerData timer) {
+ std::lock_guard<std::mutex> guard(mutex_);
+ timers_.emplace_back(std::move(timer));
+ RearmTimerFd_Locked();
+}
- if (!args.posix_argv0_override_for_testing.empty()) {
- proc_args.argv[0] =
- const_cast<char*>(args.posix_argv0_override_for_testing.c_str());
+// Can be called from any thread.
+void Watchdog::RemoveFatalTimer(TimerData timer) {
+ std::lock_guard<std::mutex> guard(mutex_);
+ for (auto it = timers_.begin(); it != timers_.end(); it++) {
+ if (*it == timer) {
+ timers_.erase(it);
+ break; // Remove only one. Doesn't matter which one.
}
}
+ RearmTimerFd_Locked();
+}
- // Setup env.
- if (!args.env.empty()) {
- for (const std::string& str : args.env)
- proc_args.env.push_back(const_cast<char*>(str.c_str()));
- proc_args.env.push_back(nullptr);
- }
+void Watchdog::RearmTimerFd_Locked() {
+ if (!enabled_)
+ return;
+ auto it = std::min_element(timers_.begin(), timers_.end());
- // Setup the pipes for stdin/err redirection.
- if (args.stdin_mode == InputMode::kBuffer) {
- s_->stdin_pipe = base::Pipe::Create(base::Pipe::kWrNonBlock);
- proc_args.stdin_pipe_rd = *s_->stdin_pipe.rd;
+ // We use one timerfd to handle all the outstanding |timers_|. Keep it armed
+ // to the task expiring soonest.
+ struct itimerspec ts{};
+ if (it != timers_.end()) {
+ ts.it_value = ToPosixTimespec(it->deadline);
}
- s_->stdouterr_pipe = base::Pipe::Create(base::Pipe::kRdNonBlock);
- proc_args.stdouterr_pipe_wr = *s_->stdouterr_pipe.wr;
+ // If |timers_| is empty (it == end()) |ts.it_value| will remain
+ // zero-initialized and that will disarm the timer in the call below.
+ int res = timerfd_settime(*timer_fd_, TFD_TIMER_ABSTIME, &ts, nullptr);
+ PERFETTO_DCHECK(res == 0);
+}
- // Spawn the child process that will exec().
- s_->pid = fork();
- PERFETTO_CHECK(s_->pid >= 0);
- if (s_->pid == 0) {
- // Close the parent-ends of the pipes.
- s_->stdin_pipe.wr.reset();
- s_->stdouterr_pipe.rd.reset();
- ChildProcess(&proc_args);
- // ChildProcess() doesn't return, not even in case of failures.
- PERFETTO_FATAL("not reached");
+void Watchdog::Start(TaskRunner* task_runner,
+ std::function<void(WatchdogCrashInfo)> fatal_handler) {
+ std::lock_guard<std::mutex> guard(mutex_);
+ if (thread_.joinable()) {
+ PERFETTO_DCHECK(enabled_);
+ } else {
+ PERFETTO_DCHECK(!enabled_);
+
+ // |fatal_handler_*| are written here, before the watchdog thread is
+ // created. The watchdog thread is the only reader, so no locking is
+ // needed when accessing them from ThreadMain().
+ fatal_handler_task_runner_ = task_runner;
+ fatal_handler_ = std::move(fatal_handler);
+
+#if PERFETTO_BUILDFLAG(PERFETTO_OS_LINUX) || \
+ PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID)
+ // Kick the thread to start running but only on Android or Linux.
+ timer_fd_.reset(
+ timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC | TFD_NONBLOCK));
+ if (!timer_fd_) {
+ PERFETTO_PLOG(
+ "timerfd_create failed, the Perfetto watchdog is not available");
+ return;
+ }
+ enabled_ = true;
+ RearmTimerFd_Locked(); // Deal with timers created before Start().
+ thread_ = std::thread(&Watchdog::ThreadMain, this);
+#endif
}
+}
- s_->status = kRunning;
+void Watchdog::SetMemoryLimit(uint64_t bytes, uint32_t window_ms) {
+ // Update the fields under the lock.
+ std::lock_guard<std::mutex> guard(mutex_);
- // Close the child-end of the pipes.
- // Deliberately NOT closing the s_->stdin_pipe.rd. This is to avoid crashing
- // with a SIGPIPE if the process exits without consuming its stdin, while
- // the parent tries to write() on the other end of the stdin pipe.
- s_->stdouterr_pipe.wr.reset();
- proc_args.create_args->out_fd.reset();
+ PERFETTO_CHECK(IsMultipleOf(window_ms, polling_interval_ms_) || bytes == 0);
- // Spawn a thread that is blocked on waitpid() and writes the termination
- // status onto a pipe. The problem here is that waipid() doesn't have a
- // timeout option and can't be passed to poll(). The alternative would be
- // using a SIGCHLD handler, but anecdotally signal handlers introduce more
- // problems than what they solve.
- s_->exit_status_pipe = base::Pipe::Create(base::Pipe::kRdNonBlock);
+ size_t size = bytes == 0 ? 0 : window_ms / polling_interval_ms_ + 1;
+ memory_window_bytes_.Reset(size);
+ memory_limit_bytes_ = bytes;
+}
- // Both ends of the pipe are closed after the thread.join().
- int pid = s_->pid;
- int exit_status_pipe_wr = s_->exit_status_pipe.wr.release();
- auto* rusage = s_->rusage.get();
- s_->waitpid_thread = std::thread([pid, exit_status_pipe_wr, rusage] {
- int pid_stat = -1;
- struct rusage usg{};
- int wait_res = PERFETTO_EINTR(wait4(pid, &pid_stat, 0, &usg));
- PERFETTO_CHECK(wait_res == pid);
+void Watchdog::SetCpuLimit(uint32_t percentage, uint32_t window_ms) {
+ std::lock_guard<std::mutex> guard(mutex_);
- auto tv_to_ms = [](const struct timeval& tv) {
- return static_cast<uint32_t>(tv.tv_sec * 1000 + tv.tv_usec / 1000);
- };
- rusage->cpu_utime_ms = tv_to_ms(usg.ru_utime);
- rusage->cpu_stime_ms = tv_to_ms(usg.ru_stime);
- rusage->max_rss_kb = static_cast<uint32_t>(usg.ru_maxrss) / 1000;
- rusage->min_page_faults = static_cast<uint32_t>(usg.ru_minflt);
- rusage->maj_page_faults = static_cast<uint32_t>(usg.ru_majflt);
- rusage->vol_ctx_switch = static_cast<uint32_t>(usg.ru_nvcsw);
- rusage->invol_ctx_switch = static_cast<uint32_t>(usg.ru_nivcsw);
+ PERFETTO_CHECK(percentage <= 100);
+ PERFETTO_CHECK(IsMultipleOf(window_ms, polling_interval_ms_) ||
+ percentage == 0);
- base::ignore_result(PERFETTO_EINTR(
- write(exit_status_pipe_wr, &pid_stat, sizeof(pid_stat))));
- PERFETTO_CHECK(close(exit_status_pipe_wr) == 0 || errno == EINTR);
- });
+ size_t size = percentage == 0 ? 0 : window_ms / polling_interval_ms_ + 1;
+ cpu_window_time_ticks_.Reset(size);
+ cpu_limit_percentage_ = percentage;
}
-Subprocess::Status Subprocess::Poll() {
- if (s_->status != kRunning)
- return s_->status; // Nothing to poll.
- while (PollInternal(0 /* don't block*/)) {
- }
- return s_->status;
-}
+void Watchdog::ThreadMain() {
+ // Register crash keys explicitly to avoid running out of slots at crash time.
+ g_crash_key_reason.Register();
+ g_crash_key_timeout.Register();
+ g_crash_key_actual_boot.Register();
+ g_crash_key_actual_mono.Register();
+ g_crash_key_actual_cpu.Register();
-// |timeout_ms| semantic:
-// -1: Block indefinitely.
-// 0: Don't block, return immediately.
-// >0: Block for at most X ms.
-// Returns:
-// True: Read at least one fd (so there might be more queued).
-// False: if all fds reached quiescent (no data to read/write).
-bool Subprocess::PollInternal(int poll_timeout_ms) {
- struct pollfd fds[3]{};
- size_t num_fds = 0;
- if (s_->exit_status_pipe.rd) {
- fds[num_fds].fd = *s_->exit_status_pipe.rd;
- fds[num_fds].events = POLLIN;
- num_fds++;
- }
- if (s_->stdouterr_pipe.rd) {
- fds[num_fds].fd = *s_->stdouterr_pipe.rd;
- fds[num_fds].events = POLLIN;
- num_fds++;
+ base::ScopedFile stat_fd(base::OpenFile("/proc/self/stat", O_RDONLY));
+ if (!stat_fd) {
+ PERFETTO_ELOG("Failed to open stat file to enforce resource limits.");
+ return;
}
- if (s_->stdin_pipe.wr) {
- fds[num_fds].fd = *s_->stdin_pipe.wr;
- fds[num_fds].events = POLLOUT;
- num_fds++;
+
+ base::ScopedFile statm_fd;
+ if constexpr (PERFETTO_FLAGS(USE_ANON_RSS_IN_WATCHDOG)) {
+ statm_fd = (base::OpenFile("/proc/self/statm", O_RDONLY));
+ if (!statm_fd) {
+ PERFETTO_DLOG(
+ "Failed to open statm file to enforce resource limits. Using RSS for "
+ "the guardrail");
+ }
}
- if (num_fds == 0)
- return false;
+ PERFETTO_DCHECK(timer_fd_);
- auto nfds = static_cast<nfds_t>(num_fds);
- int poll_res = PERFETTO_EINTR(poll(fds, nfds, poll_timeout_ms));
- PERFETTO_CHECK(poll_res >= 0);
+ constexpr uint8_t kFdCount = 1;
+ struct pollfd fds[kFdCount]{};
+ fds[0].fd = *timer_fd_;
+ fds[0].events = POLLIN;
- TryReadStdoutAndErr();
- TryPushStdin();
- TryReadExitStatus();
+ for (;;) {
+ // We use the poll() timeout to drive the periodic ticks for the cpu/memory
+ // checks. The only other case when the poll() unblocks is when we crash
+ // (or have to quit via enabled_ == false, but that happens only in tests).
+ platform::BeforeMaybeBlockingSyscall();
+ auto ret = poll(fds, kFdCount, static_cast<int>(polling_interval_ms_));
+ platform::AfterMaybeBlockingSyscall();
+ if (!enabled_)
+ return;
+ if (ret < 0) {
+ if (errno == ENOMEM || errno == EINTR) {
+ // Should happen extremely rarely.
+ std::this_thread::sleep_for(std::chrono::milliseconds(100));
+ continue;
+ }
+ PERFETTO_FATAL("watchdog poll() failed");
+ }
- return poll_res > 0;
-}
+ // If we get here either:
+ // 1. poll() timed out, in which case we should process cpu/mem guardrails.
+ // 2. A timer expired, in which case we shall crash.
-bool Subprocess::Wait(int timeout_ms) {
- PERFETTO_CHECK(s_->status != kNotStarted);
+ uint64_t expired = 0; // Must be exactly 8 bytes.
+ auto res = PERFETTO_EINTR(read(*timer_fd_, &expired, sizeof(expired)));
+ PERFETTO_DCHECK((res < 0 && (errno == EAGAIN)) ||
+ (res == sizeof(expired) && expired > 0));
+ const TimeMillis now_mono_ms = GetWallTimeMs();
- // Break out of the loop only after both conditions are satisfied:
- // - All stdout/stderr data has been read (if kBuffer).
- // - The process exited.
- // Note that the two events can happen arbitrary order. After the process
- // exits, there might be still data in the pipe buffer, which we want to
- // read fully.
- //
- // Instead, don't wait on the stdin to be fully written. The child process
- // might exit prematurely (or crash). If that happens, we can end up in a
- // state where the write(stdin_pipe_.wr) will never unblock.
+ // Check if any of the timers expired.
+ WatchdogCrashInfo info{};
+ {
+ std::lock_guard<std::mutex> guard(mutex_);
+ for (const auto& timer : timers_) {
+ if (now_mono_ms >= timer.deadline) {
+ info.thread_id = timer.thread_id;
+ info.reason = timer.crash_reason;
+ const TimeMillis now_boot_ms = GetBootTimeMs();
+ info.alarm_time_ms = now_boot_ms.count();
+ info.timeout_s =
+ static_cast<int>(std::chrono::duration_cast<TimeSeconds>(
+ timer.deadline - timer.ctime_mono)
+ .count());
+ info.actual_mono_s =
+ static_cast<int>(std::chrono::duration_cast<TimeSeconds>(
+ now_mono_ms - timer.ctime_mono)
+ .count());
+ info.actual_boot_s =
+ static_cast<int>(std::chrono::duration_cast<TimeSeconds>(
+ now_boot_ms - timer.ctime_boot)
+ .count());
+ info.actual_cpu_s =
+ static_cast<int>(std::chrono::duration_cast<TimeSeconds>(
+ GetProcessCPUTimeNs() - timer.ctime_cpu)
+ .count());
+ break;
+ }
+ }
+ }
- const int64_t t_start = base::GetWallTimeMs().count();
- while (s_->exit_status_pipe.rd || s_->stdouterr_pipe.rd) {
- int poll_timeout_ms = -1; // Block until a FD is ready.
- if (timeout_ms > 0) {
- const int64_t now = GetWallTimeMs().count();
- poll_timeout_ms = timeout_ms - static_cast<int>(now - t_start);
- if (poll_timeout_ms <= 0)
- return false;
+ if (info.thread_id) {
+ SerializeLogsAndKillThread(info.thread_id, info);
}
- PollInternal(poll_timeout_ms);
- } // while(...)
- return true;
-}
-void Subprocess::TryReadExitStatus() {
- if (!s_->exit_status_pipe.rd)
- return;
+ // Check CPU and memory guardrails (if enabled).
+ lseek(stat_fd.get(), 0, SEEK_SET);
+ ProcStat stat;
+ if (!ReadProcStat(stat_fd.get(), &stat))
+ continue;
- int pid_stat = -1;
- int64_t rsize = PERFETTO_EINTR(
- read(*s_->exit_status_pipe.rd, &pid_stat, sizeof(pid_stat)));
- if (rsize < 0 && errno == EAGAIN)
- return;
+ const uint64_t cpu_time = stat.utime + stat.stime;
+ // max(stat.rss_pages, 0) is used since rss_pages is signed.
+ const uint64_t rss_bytes =
+ stat.rss_pages > 0
+ ? static_cast<uint64_t>(stat.rss_pages) * base::GetSysPageSize()
+ : 0;
- if (rsize > 0) {
- PERFETTO_CHECK(rsize == sizeof(pid_stat));
- } else if (rsize < 0) {
- PERFETTO_PLOG("Subprocess read(s_->exit_status_pipe) failed");
- }
- s_->waitpid_thread.join();
- s_->exit_status_pipe.rd.reset();
+ std::optional<uint64_t> rss_anon_bytes = std::nullopt;
+ if (statm_fd) {
+ lseek(statm_fd.get(), 0, SEEK_SET);
+ ProcStatm statm;
+ if (ReadProcStatm(statm_fd.get(), &statm))
+ rss_anon_bytes = statm.rss_anon_pages() * base::GetSysPageSize();
+ }
- s_->status = kTerminated;
- if (WIFEXITED(pid_stat)) {
- s_->returncode = WEXITSTATUS(pid_stat);
- } else if (WIFSIGNALED(pid_stat)) {
- s_->returncode = 128 + WTERMSIG(pid_stat); // Follow bash convention.
- } else {
- PERFETTO_FATAL("waitpid() returned an unexpected value (%d)", pid_stat);
+ bool threshold_exceeded = false;
+ WatchdogCrashReason crash_reason{};
+ {
+ std::lock_guard<std::mutex> guard(mutex_);
+ if (CheckMemory_Locked(rss_anon_bytes.value_or(rss_bytes)) &&
+ !IsSyncMemoryTaggingEnabled()) {
+ threshold_exceeded = true;
+ crash_reason = WatchdogCrashReason::kMemGuardrail;
+ } else if (CheckCpu_Locked(cpu_time)) {
+ threshold_exceeded = true;
+ crash_reason = WatchdogCrashReason::kCpuGuardrail;
+ }
+ }
+
+ if (threshold_exceeded) {
+ info.reason = crash_reason;
+ // No associated timer: info.actual_*_s remain 0.
+ SerializeLogsAndKillThread(getpid(), info);
+ }
}
}
-// If the stidn pipe is still open, push input data and close it at the end.
-void Subprocess::TryPushStdin() {
- if (!s_->stdin_pipe.wr)
+void Watchdog::SerializeLogsAndKillThread(int tid,
+ const WatchdogCrashInfo& info) {
+ g_crash_key_timeout.Set(info.timeout_s);
+ g_crash_key_actual_mono.Set(info.actual_mono_s);
+ g_crash_key_actual_boot.Set(info.actual_boot_s);
+ g_crash_key_actual_cpu.Set(info.actual_cpu_s);
+ g_crash_key_reason.Set(static_cast<int>(info.reason));
+
+ // If the embedder installed a fatal handler, give it a chance to run (e.g.
+ // to flush in-flight state) before we force-kill the process. The handler
+ // is expected to crash the process on its own (e.g. via PERFETTO_FATAL once
+ // it's done). If it doesn't crash within |kFatalHandlerGraceMs|, we proceed
+ // and force-kill from here.
+ // |fatal_handler_*| are set in Start() before the watchdog thread is
+ // created, so no locking is needed. Clearing them after invocation prevents
+ // re-posting if the same expired condition is observed again.
+ if (fatal_handler_ && fatal_handler_task_runner_) {
+ fatal_handler_task_runner_->PostTask(
+ [h = std::move(fatal_handler_), info] { h(info); });
+ fatal_handler_ = nullptr;
+ fatal_handler_task_runner_ = nullptr;
+ if (!disable_kill_failsafe_for_testing_) {
+ std::this_thread::sleep_for(
+ std::chrono::milliseconds(kFatalHandlerGraceMs));
+ }
+ }
+
+ // We are about to die. Serialize the logs into the crash buffer so the
+ // debuggerd crash handler picks them up and attaches to the bugreport.
+ // In the case of a PERFETTO_CHECK/PERFETTO_FATAL this is done in logging.h.
+ // But in the watchdog case, we don't hit that codepath and must do ourselves.
+ MaybeSerializeLastLogsForCrashReporting();
+
+ // Send a SIGABRT to the thread that armed the timer. This is to see the
+ // callstack of the thread that is stuck in a long task rather than the
+ // watchdog thread.
+ if (syscall(__NR_tgkill, getpid(), tid, SIGABRT) < 0) {
+ // At this point the process must die. If for any reason the tgkill doesn't
+ // work (e.g. the thread has disappeared), force a crash from here.
+ abort();
+ }
+
+ if (disable_kill_failsafe_for_testing_)
return;
- PERFETTO_DCHECK(args.input.empty() || s_->input_written < args.input.size());
- if (!args.input.empty()) {
- int64_t wsize =
- PERFETTO_EINTR(write(*s_->stdin_pipe.wr, &args.input[s_->input_written],
- args.input.size() - s_->input_written));
- if (wsize < 0 && errno == EAGAIN)
- return;
+ // The tgkill() above will take some milliseconds to cause a crash, as it
+ // involves the kernel to queue the SIGABRT on the target thread (often the
+ // main thread, which is != watchdog thread) and do a scheduling round.
+ // If something goes wrong though (the target thread has signals masked or
+ // is stuck in an uninterruptible+wakekill syscall) force quit from this
+ // thread.
+ std::this_thread::sleep_for(std::chrono::seconds(10));
+ abort();
+}
- if (wsize >= 0) {
- // Whether write() can return 0 is one of the greatest mysteries of UNIX.
- // Just ignore it.
- s_->input_written += static_cast<size_t>(wsize);
- } else {
- PERFETTO_PLOG("Subprocess write(stdin) failed");
- s_->stdin_pipe.wr.reset();
+bool Watchdog::CheckMemory_Locked(uint64_t rss_anon_bytes) {
+ if (memory_limit_bytes_ == 0)
+ return false;
+
+ // Add the current stat value to the ring buffer and check that the mean
+ // remains under our threshold.
+ if (memory_window_bytes_.Push(rss_anon_bytes)) {
+ if (memory_window_bytes_.Mean() >
+ static_cast<double>(memory_limit_bytes_)) {
+ PERFETTO_ELOG(
+ "Memory watchdog trigger. Memory window of %f bytes is above the "
+ "%" PRIu64 " bytes limit.",
+ memory_window_bytes_.Mean(), memory_limit_bytes_);
+ return true;
}
}
- PERFETTO_DCHECK(s_->input_written <= args.input.size());
- if (s_->input_written == args.input.size())
- s_->stdin_pipe.wr.reset(); // Close stdin.
+ return false;
}
-void Subprocess::TryReadStdoutAndErr() {
- if (!s_->stdouterr_pipe.rd)
- return;
- char buf[4096];
- int64_t rsize =
- PERFETTO_EINTR(read(*s_->stdouterr_pipe.rd, buf, sizeof(buf)));
- if (rsize < 0 && errno == EAGAIN)
- return;
+bool Watchdog::CheckCpu_Locked(uint64_t cpu_time) {
+ if (cpu_limit_percentage_ == 0)
+ return false;
- if (rsize > 0) {
- s_->output.append(buf, static_cast<size_t>(rsize));
- } else if (rsize == 0 /* EOF */) {
- s_->stdouterr_pipe.rd.reset();
- } else {
- PERFETTO_PLOG("Subprocess read(stdout/err) failed");
- s_->stdouterr_pipe.rd.reset();
+ // Add the cpu time to the ring buffer.
+ if (cpu_window_time_ticks_.Push(cpu_time)) {
+ // Compute the percentage over the whole window and check that it remains
+ // under the threshold.
+ uint64_t difference_ticks = cpu_window_time_ticks_.NewestWhenFull() -
+ cpu_window_time_ticks_.OldestWhenFull();
+ double window_interval_ticks =
+ (static_cast<double>(WindowTimeForRingBuffer(cpu_window_time_ticks_)) /
+ 1000.0) *
+ static_cast<double>(sysconf(_SC_CLK_TCK));
+ double percentage = static_cast<double>(difference_ticks) /
+ static_cast<double>(window_interval_ticks) * 100;
+ if (percentage > cpu_limit_percentage_) {
+ PERFETTO_ELOG("CPU watchdog trigger. %f%% CPU use is above the %" PRIu32
+ "%% CPU limit.",
+ percentage, cpu_limit_percentage_);
+ return true;
+ }
}
+ return false;
}
-void Subprocess::Kill(int sig_num) {
- kill(s_->pid, sig_num ? sig_num : SIGKILL);
+uint32_t Watchdog::WindowTimeForRingBuffer(const WindowedInterval& window) {
+ return static_cast<uint32_t>(window.size() - 1) * polling_interval_ms_;
}
-void Subprocess::KillAndWaitForTermination(int sig_num) {
- Kill(sig_num);
- Wait();
- // TryReadExitStatus must have joined the thread.
- PERFETTO_DCHECK(!s_->waitpid_thread.joinable());
+bool Watchdog::WindowedInterval::Push(uint64_t sample) {
+ // Add the sample to the current position in the ring buffer.
+ buffer_[position_] = sample;
+
+ // Update the position with next one circularily.
+ position_ = (position_ + 1) % size_;
+
+ // Set the filled flag the first time we wrap.
+ filled_ = filled_ || position_ == 0;
+ return filled_;
+}
+
+double Watchdog::WindowedInterval::Mean() const {
+ return MeanForArray(buffer_.get(), size_);
+}
+
+void Watchdog::WindowedInterval::Clear() {
+ position_ = 0;
+ buffer_.reset(new uint64_t[size_]());
+}
+
+void Watchdog::WindowedInterval::Reset(size_t new_size) {
+ position_ = 0;
+ size_ = new_size;
+ buffer_.reset(new_size == 0 ? nullptr : new uint64_t[new_size]());
+}
+
+Watchdog::Timer::Timer(Watchdog* watchdog,
+ uint32_t ms,
+ WatchdogCrashReason crash_reason)
+ : watchdog_(watchdog) {
+ if (!ms)
+ return; // No-op timer created when the watchdog is disabled.
+
+ TimeMillis now_mono = GetWallTimeMs();
+ timer_data_.deadline = now_mono + std::chrono::milliseconds(ms);
+ timer_data_.ctime_mono = now_mono;
+ timer_data_.ctime_boot = GetBootTimeMs();
+ timer_data_.ctime_cpu =
+ std::chrono::duration_cast<TimeMillis>(GetProcessCPUTimeNs());
+ timer_data_.thread_id = GetThreadId();
+ timer_data_.crash_reason = crash_reason;
+ PERFETTO_DCHECK(watchdog_);
+ watchdog_->AddFatalTimer(timer_data_);
+}
+
+Watchdog::Timer::~Timer() {
+ if (timer_data_.deadline.count())
+ watchdog_->RemoveFatalTimer(timer_data_);
+}
+
+Watchdog::Timer::Timer(Timer&& other) noexcept {
+ watchdog_ = std::move(other.watchdog_);
+ other.watchdog_ = nullptr;
+ timer_data_ = std::move(other.timer_data_);
+ other.timer_data_ = TimerData();
}
} // namespace base
} // namespace perfetto
-#endif // PERFETTO_OS_LINUX || PERFETTO_OS_ANDROID || PERFETTO_OS_APPLE
-// gen_amalgamated begin source: src/base/subprocess_windows.cc
+#endif // PERFETTO_BUILDFLAG(PERFETTO_WATCHDOG)
+// gen_amalgamated begin source: src/base/weak_runner.cc
+// gen_amalgamated begin header: include/perfetto/ext/base/weak_runner.h
/*
- * Copyright (C) 2020 The Android Open Source Project
+ * Copyright (C) 2024 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.
@@ -14000,335 +14179,54 @@ void Subprocess::KillAndWaitForTermination(int sig_num) {
* limitations under the License.
*/
-// gen_amalgamated expanded: #include "perfetto/ext/base/subprocess.h"
-
-// gen_amalgamated expanded: #include "perfetto/base/build_config.h"
+#ifndef INCLUDE_PERFETTO_EXT_BASE_WEAK_RUNNER_H_
+#define INCLUDE_PERFETTO_EXT_BASE_WEAK_RUNNER_H_
-#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
+#include <stdint.h>
-#include <stdio.h>
+#include <functional>
+#include <memory>
-#include <algorithm>
-#include <mutex>
-#include <tuple>
+namespace perfetto::base {
-#include <windows.h>
+class TaskRunner;
-// gen_amalgamated expanded: #include "perfetto/base/logging.h"
-// gen_amalgamated expanded: #include "perfetto/base/time.h"
-// gen_amalgamated expanded: #include "perfetto/ext/base/pipe.h"
-// gen_amalgamated expanded: #include "perfetto/ext/base/utils.h"
-
-namespace perfetto {
-namespace base {
-
-// static
-const int Subprocess::kTimeoutSignal = static_cast<int>(STATUS_TIMEOUT);
-
-void Subprocess::Start() {
- if (args.exec_cmd.empty()) {
- PERFETTO_ELOG("Subprocess.exec_cmd cannot be empty on Windows");
- return;
- }
-
- // Quote arguments but only when ambiguous. When quoting, CreateProcess()
- // assumes that the command is an absolute path and does not search in the
- // %PATH%. If non quoted, instead, CreateProcess() tries both. This is to
- // allow Subprocess("cmd.exe", "/c", "shell command").
- std::string cmd;
- for (const auto& part : args.exec_cmd) {
- if (part.find(" ") != std::string::npos) {
- cmd += "\"" + part + "\" ";
- } else {
- cmd += part + " ";
- }
- }
- // Remove trailing space.
- if (!cmd.empty())
- cmd.resize(cmd.size() - 1);
-
- if (args.stdin_mode == InputMode::kBuffer) {
- s_->stdin_pipe = Pipe::Create();
- // Allow the child process to inherit the other end of the pipe.
- PERFETTO_CHECK(
- ::SetHandleInformation(*s_->stdin_pipe.rd, HANDLE_FLAG_INHERIT, 1));
- }
-
- if (args.stderr_mode == OutputMode::kBuffer ||
- args.stdout_mode == OutputMode::kBuffer) {
- s_->stdouterr_pipe = Pipe::Create();
- PERFETTO_CHECK(
- ::SetHandleInformation(*s_->stdouterr_pipe.wr, HANDLE_FLAG_INHERIT, 1));
- }
-
- ScopedPlatformHandle nul_handle;
- if (args.stderr_mode == OutputMode::kDevNull ||
- args.stdout_mode == OutputMode::kDevNull) {
- nul_handle.reset(::CreateFileA(
- "NUL", GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE,
- nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr));
- PERFETTO_CHECK(::SetHandleInformation(*nul_handle, HANDLE_FLAG_INHERIT, 1));
- }
-
- PROCESS_INFORMATION proc_info{};
- STARTUPINFOA start_info{};
- start_info.cb = sizeof(STARTUPINFOA);
-
- if (args.stderr_mode == OutputMode::kInherit) {
- start_info.hStdError = ::GetStdHandle(STD_ERROR_HANDLE);
- } else if (args.stderr_mode == OutputMode::kBuffer) {
- start_info.hStdError = *s_->stdouterr_pipe.wr;
- } else if (args.stderr_mode == OutputMode::kDevNull) {
- start_info.hStdError = *nul_handle;
- } else if (args.stderr_mode == OutputMode::kFd) {
- PERFETTO_CHECK(
- ::SetHandleInformation(*args.out_fd, HANDLE_FLAG_INHERIT, 1));
- start_info.hStdError = *args.out_fd;
- } else {
- PERFETTO_CHECK(false);
- }
-
- if (args.stdout_mode == OutputMode::kInherit) {
- start_info.hStdOutput = ::GetStdHandle(STD_OUTPUT_HANDLE);
- } else if (args.stdout_mode == OutputMode::kBuffer) {
- start_info.hStdOutput = *s_->stdouterr_pipe.wr;
- } else if (args.stdout_mode == OutputMode::kDevNull) {
- start_info.hStdOutput = *nul_handle;
- } else if (args.stdout_mode == OutputMode::kFd) {
- PERFETTO_CHECK(
- ::SetHandleInformation(*args.out_fd, HANDLE_FLAG_INHERIT, 1));
- start_info.hStdOutput = *args.out_fd;
- } else {
- PERFETTO_CHECK(false);
- }
-
- if (args.stdin_mode == InputMode::kBuffer) {
- start_info.hStdInput = *s_->stdin_pipe.rd;
- } else if (args.stdin_mode == InputMode::kDevNull) {
- start_info.hStdInput = *nul_handle;
- }
-
- start_info.dwFlags |= STARTF_USESTDHANDLES;
-
- // Create the child process.
- bool success =
- ::CreateProcessA(nullptr, // App name. Needs to be null to use PATH.
- &cmd[0], // Command line.
- nullptr, // Process security attributes.
- nullptr, // Primary thread security attributes.
- true, // Handles are inherited.
- 0, // Flags.
- nullptr, // Use parent's environment.
- nullptr, // Use parent's current directory.
- &start_info, // STARTUPINFO pointer.
- &proc_info); // Receives PROCESS_INFORMATION.
-
- // Close on our side the pipe ends that we passed to the child process.
- s_->stdin_pipe.rd.reset();
- s_->stdouterr_pipe.wr.reset();
- args.out_fd.reset();
-
- if (!success) {
- s_->returncode = ERROR_FILE_NOT_FOUND;
- s_->status = kTerminated;
- s_->stdin_pipe.wr.reset();
- s_->stdouterr_pipe.rd.reset();
- PERFETTO_ELOG("CreateProcess failed: %lx, cmd: %s", GetLastError(),
- &cmd[0]);
- return;
- }
-
- s_->pid = proc_info.dwProcessId;
- s_->win_proc_handle = ScopedPlatformHandle(proc_info.hProcess);
- s_->win_thread_handle = ScopedPlatformHandle(proc_info.hThread);
- s_->status = kRunning;
-
- MovableState* s = s_.get();
- if (args.stdin_mode == InputMode::kBuffer) {
- s_->stdin_thread = std::thread(&Subprocess::StdinThread, s, args.input);
- }
-
- if (args.stderr_mode == OutputMode::kBuffer ||
- args.stdout_mode == OutputMode::kBuffer) {
- PERFETTO_DCHECK(s_->stdouterr_pipe.rd);
- s_->stdouterr_thread = std::thread(&Subprocess::StdoutErrThread, s);
- }
-}
-
-// static
-void Subprocess::StdinThread(MovableState* s, const std::string& input) {
- size_t input_written = 0;
- while (input_written < input.size()) {
- DWORD wsize = 0;
- if (::WriteFile(*s->stdin_pipe.wr, input.data() + input_written,
- static_cast<DWORD>(input.size() - input_written), &wsize,
- nullptr)) {
- input_written += wsize;
- } else {
- // ERROR_BROKEN_PIPE is WAI when the child just closes stdin and stops
- // accepting input.
- auto err = ::GetLastError();
- if (err != ERROR_BROKEN_PIPE)
- PERFETTO_PLOG("Subprocess WriteFile(stdin) failed %lx", err);
- break;
- }
- } // while(...)
- std::unique_lock<std::mutex> lock(s->mutex);
- s->stdin_pipe.wr.reset();
-}
-
-// static
-void Subprocess::StdoutErrThread(MovableState* s) {
- char buf[4096];
- for (;;) {
- DWORD rsize = 0;
- bool res =
- ::ReadFile(*s->stdouterr_pipe.rd, buf, sizeof(buf), &rsize, nullptr);
- if (!res) {
- auto err = GetLastError();
- if (err != ERROR_BROKEN_PIPE)
- PERFETTO_PLOG("Subprocess ReadFile(stdouterr) failed %lx", err);
- }
-
- if (rsize > 0) {
- std::unique_lock<std::mutex> lock(s->mutex);
- s->locked_outerr_buf.append(buf, static_cast<size_t>(rsize));
- } else { // EOF or some error.
- break;
- }
- } // For(..)
-
- // Close the stdouterr_pipe. The main loop looks at the pipe closure to
- // determine whether the stdout/err thread has completed.
- {
- std::unique_lock<std::mutex> lock(s->mutex);
- s->stdouterr_pipe.rd.reset();
- }
- s->stdouterr_done_event.Notify();
-}
-
-Subprocess::Status Subprocess::Poll() {
- if (s_->status != kRunning)
- return s_->status; // Nothing to poll.
- Wait(1 /*ms*/);
- return s_->status;
-}
-
-bool Subprocess::Wait(int timeout_ms) {
- PERFETTO_CHECK(s_->status != kNotStarted);
- const bool wait_forever = timeout_ms == 0;
- const int64_t wait_start_ms = base::GetWallTimeMs().count();
+// This is a wrapper around a `base::TaskRunner*`. It is intended to be used by
+// classes that want to post tasks on themselves. When the object is destroyed,
+// all posted tasks become noops.
+//
+// A class that embeds a WeakRunner can safely capture `this` on the posted
+// tasks.
+class WeakRunner {
+ public:
+ explicit WeakRunner(base::TaskRunner* task_runner);
+ ~WeakRunner();
+ base::TaskRunner* task_runner() const { return task_runner_; }
- // Break out of the loop only after both conditions are satisfied:
- // - All stdout/stderr data has been read (if OutputMode::kBuffer).
- // - The process exited.
- // Note that the two events can happen arbitrary order. After the process
- // exits, there might be still data in the pipe buffer, which we want to
- // read fully.
- // Note also that stdout/err might be "complete" before starting, if neither
- // is operating in OutputMode::kBuffer mode. In that case we just want to wait
- // for the process termination.
+ // Schedules `f` for immediate execution. `f` will not be executed is `*this`
+ // is destroyed.
//
- // Instead, don't wait on the stdin to be fully written. The child process
- // might exit prematurely (or crash). If that happens, we can end up in a
- // state where the write(stdin_pipe_.wr) will never unblock.
- bool stdouterr_complete = false;
- for (;;) {
- HANDLE wait_handles[2]{};
- DWORD num_handles = 0;
-
- // Check if the process exited.
- bool process_exited = !s_->win_proc_handle;
- if (!process_exited) {
- DWORD exit_code = STILL_ACTIVE;
- PERFETTO_CHECK(::GetExitCodeProcess(*s_->win_proc_handle, &exit_code));
- if (exit_code != STILL_ACTIVE) {
- s_->returncode = static_cast<int>(exit_code);
- s_->status = kTerminated;
- s_->win_proc_handle.reset();
- s_->win_thread_handle.reset();
- process_exited = true;
- }
- } else {
- PERFETTO_DCHECK(s_->status != kRunning);
- }
- if (!process_exited) {
- wait_handles[num_handles++] = *s_->win_proc_handle;
- }
-
- // Check if there is more output and if the stdout/err pipe has been closed.
- {
- std::unique_lock<std::mutex> lock(s_->mutex);
- // Move the output from the internal buffer shared with the
- // stdouterr_thread to the final buffer exposed to the client.
- if (!s_->locked_outerr_buf.empty()) {
- s_->output.append(std::move(s_->locked_outerr_buf));
- s_->locked_outerr_buf.clear();
- }
- stdouterr_complete = !s_->stdouterr_pipe.rd;
- if (!stdouterr_complete) {
- wait_handles[num_handles++] = s_->stdouterr_done_event.fd();
- }
- } // lock(s_->mutex)
-
- if (num_handles == 0) {
- PERFETTO_DCHECK(process_exited && stdouterr_complete);
- break;
- }
-
- DWORD wait_ms; // Note: DWORD is unsigned.
- if (wait_forever) {
- wait_ms = INFINITE;
- } else {
- const int64_t now = GetWallTimeMs().count();
- const int64_t wait_left_ms = timeout_ms - (now - wait_start_ms);
- if (wait_left_ms <= 0)
- return false; // Timed out
- wait_ms = static_cast<DWORD>(wait_left_ms);
- }
-
- auto wait_res =
- ::WaitForMultipleObjects(num_handles, wait_handles, false, wait_ms);
- PERFETTO_CHECK(wait_res != WAIT_FAILED);
- }
-
- PERFETTO_DCHECK(!s_->win_proc_handle);
- PERFETTO_DCHECK(!s_->win_thread_handle);
-
- if (s_->stdin_thread.joinable()) // Might not exist if CreateProcess failed.
- s_->stdin_thread.join();
- if (s_->stdouterr_thread.joinable())
- s_->stdouterr_thread.join();
-
- // The stdin pipe is closed by the dedicated stdin thread. However if that is
- // not started (e.g. because of no redirection) force close it now. Needs to
- // happen after the join() to be thread safe.
- s_->stdin_pipe.wr.reset();
- s_->stdouterr_pipe.rd.reset();
-
- return true;
-}
+ // Can be called from any thread, but the caller needs to make sure that
+ // `*this` is alive while `PostTask` is running: this is not obvious when
+ // multiple threads are involved.
+ void PostTask(std::function<void()> f) const;
-void Subprocess::Kill(int exit_code) {
- auto code = exit_code ? static_cast<DWORD>(exit_code) : STATUS_CONTROL_C_EXIT;
- ::TerminateProcess(*s_->win_proc_handle, code);
-}
+ // Schedules `f` for execution after |delay_ms|.
+ // Can be called from any thread, but the caller needs to make sure that
+ // `*this` is alive while `PostDelayedTask` is running: this is not obvious
+ // when multiple threads are involved.
+ void PostDelayedTask(std::function<void()> f, uint32_t delay_ms) const;
-void Subprocess::KillAndWaitForTermination(int exit_code) {
- Kill(exit_code);
- Wait();
- // TryReadExitStatus must have joined the threads.
- PERFETTO_DCHECK(!s_->stdin_thread.joinable());
- PERFETTO_DCHECK(!s_->stdouterr_thread.joinable());
-}
+ private:
+ base::TaskRunner* const task_runner_;
+ std::shared_ptr<bool> destroyed_;
+};
-} // namespace base
-} // namespace perfetto
+} // namespace perfetto::base
-#endif // PERFETTO_OS_WIN
-// gen_amalgamated begin source: src/protozero/field.cc
+#endif // INCLUDE_PERFETTO_EXT_BASE_WEAK_RUNNER_H_
/*
- * Copyright (C) 2019 The Android Open Source Project
+ * Copyright (C) 2024 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.
@@ -14343,74 +14241,46 @@ void Subprocess::KillAndWaitForTermination(int exit_code) {
* limitations under the License.
*/
-// gen_amalgamated expanded: #include "perfetto/protozero/field.h"
+// gen_amalgamated expanded: #include "perfetto/ext/base/weak_runner.h"
-// gen_amalgamated expanded: #include "perfetto/base/compiler.h"
-// gen_amalgamated expanded: #include "perfetto/base/logging.h"
+// gen_amalgamated expanded: #include "perfetto/base/task_runner.h"
-#if !PERFETTO_IS_LITTLE_ENDIAN()
-// The memcpy() for fixed32/64 below needs to be adjusted if we want to
-// support big endian CPUs. There doesn't seem to be a compelling need today.
-#error Unimplemented for big endian archs.
-#endif
+namespace perfetto::base {
-namespace protozero {
+WeakRunner::WeakRunner(base::TaskRunner* task_runner)
+ : task_runner_(task_runner), destroyed_(std::make_shared<bool>(false)) {}
-template <typename Container>
-void Field::SerializeAndAppendToInternal(Container* dst) const {
- namespace pu = proto_utils;
- size_t initial_size = dst->size();
- dst->resize(initial_size + pu::kMaxSimpleFieldEncodedSize + size_);
- uint8_t* start = reinterpret_cast<uint8_t*>(&(*dst)[initial_size]);
- uint8_t* wptr = start;
- switch (type_) {
- case static_cast<int>(pu::ProtoWireType::kVarInt): {
- wptr = pu::WriteVarInt(pu::MakeTagVarInt(id_), wptr);
- wptr = pu::WriteVarInt(int_value_, wptr);
- break;
- }
- case static_cast<int>(pu::ProtoWireType::kFixed32): {
- wptr = pu::WriteVarInt(pu::MakeTagFixed<uint32_t>(id_), wptr);
- uint32_t value32 = static_cast<uint32_t>(int_value_);
- memcpy(wptr, &value32, sizeof(value32));
- wptr += sizeof(uint32_t);
- break;
- }
- case static_cast<int>(pu::ProtoWireType::kFixed64): {
- wptr = pu::WriteVarInt(pu::MakeTagFixed<uint64_t>(id_), wptr);
- memcpy(wptr, &int_value_, sizeof(int_value_));
- wptr += sizeof(uint64_t);
- break;
- }
- case static_cast<int>(pu::ProtoWireType::kLengthDelimited): {
- ConstBytes payload = as_bytes();
- wptr = pu::WriteVarInt(pu::MakeTagLengthDelimited(id_), wptr);
- wptr = pu::WriteVarInt(payload.size, wptr);
- memcpy(wptr, payload.data, payload.size);
- wptr += payload.size;
- break;
- }
- default:
- PERFETTO_FATAL("Unknown field type %d", type_);
- }
- size_t written_size = static_cast<size_t>(wptr - start);
- PERFETTO_DCHECK(written_size > 0 && written_size < pu::kMaxMessageLength);
- PERFETTO_DCHECK(initial_size + written_size <= dst->size());
- dst->resize(initial_size + written_size);
+WeakRunner::~WeakRunner() {
+ *destroyed_ = true;
}
-void Field::SerializeAndAppendTo(std::string* dst) const {
- SerializeAndAppendToInternal(dst);
+void WeakRunner::PostTask(std::function<void()> f) const {
+ task_runner_->PostTask([destroyed = destroyed_, f = std::move(f)]() {
+ if (*destroyed) {
+ return;
+ }
+ f();
+ });
}
-void Field::SerializeAndAppendTo(std::vector<uint8_t>* dst) const {
- SerializeAndAppendToInternal(dst);
+void WeakRunner::PostDelayedTask(std::function<void()> f,
+ uint32_t delay_ms) const {
+ task_runner_->PostDelayedTask(
+ [destroyed = destroyed_, f = std::move(f)]() {
+ if (*destroyed) {
+ return;
+ }
+ f();
+ },
+ delay_ms);
}
-} // namespace protozero
-// gen_amalgamated begin source: src/protozero/gen_field_helpers.cc
+} // namespace perfetto::base
+// gen_amalgamated begin source: src/base/lock_free_task_runner.cc
+// gen_amalgamated begin header: include/perfetto/ext/base/lock_free_task_runner.h
+// gen_amalgamated begin header: include/perfetto/ext/base/unix_task_runner.h
/*
- * Copyright (C) 2023 The Android Open Source Project
+ * 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.
@@ -14425,98 +14295,131 @@ void Field::SerializeAndAppendTo(std::vector<uint8_t>* dst) const {
* limitations under the License.
*/
-// gen_amalgamated expanded: #include "perfetto/protozero/gen_field_helpers.h"
+#ifndef INCLUDE_PERFETTO_EXT_BASE_UNIX_TASK_RUNNER_H_
+#define INCLUDE_PERFETTO_EXT_BASE_UNIX_TASK_RUNNER_H_
-namespace protozero {
-namespace internal {
-namespace gen_helpers {
+// gen_amalgamated expanded: #include "perfetto/base/build_config.h"
+// gen_amalgamated expanded: #include "perfetto/base/task_runner.h"
+// gen_amalgamated expanded: #include "perfetto/base/thread_annotations.h"
+// gen_amalgamated expanded: #include "perfetto/base/thread_utils.h"
+// gen_amalgamated expanded: #include "perfetto/base/time.h"
+// gen_amalgamated expanded: #include "perfetto/ext/base/event_fd.h"
+// gen_amalgamated expanded: #include "perfetto/ext/base/rt_mutex.h"
+// gen_amalgamated expanded: #include "perfetto/ext/base/scoped_file.h"
+// gen_amalgamated expanded: #include "perfetto/ext/base/thread_checker.h"
-void DeserializeString(const protozero::Field& field, std::string* dst) {
- field.get(dst);
-}
+#include <chrono>
+#include <deque>
+#include <map>
+#include <mutex>
+#include <vector>
-template bool DeserializePackedRepeated<proto_utils::ProtoWireType::kVarInt,
- uint64_t>(const protozero::Field& field,
- std::vector<uint64_t>* dst);
+#if !PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
+#include <poll.h>
+#endif
-template bool DeserializePackedRepeated<proto_utils::ProtoWireType::kVarInt,
- int64_t>(const protozero::Field& field,
- std::vector<int64_t>* dst);
+namespace perfetto {
+namespace base {
-template bool DeserializePackedRepeated<proto_utils::ProtoWireType::kVarInt,
- uint32_t>(const protozero::Field& field,
- std::vector<uint32_t>* dst);
+// Runs a task runner on the current thread.
+//
+// Implementation note: we currently assume (and enforce in debug builds) that
+// Run() is called from the thread that constructed the UnixTaskRunner. This is
+// not strictly necessary, and we could instead track the thread that invokes
+// Run(). However, a related property that *might* be important to enforce is
+// that the destructor runs on the task-running thread. Otherwise, if there are
+// still-pending tasks at the time of destruction, we would destroy those
+// outside of the task thread (which might be unexpected to the caller). On the
+// other hand, the std::function task interface discourages use of any
+// resource-owning tasks (as the callable needs to be copyable), so this might
+// not be important in practice.
+//
+// TODO(rsavitski): consider adding a thread-check in the destructor, after
+// auditing existing usages.
+// TODO(primiano): rename this to TaskRunnerImpl. The "Unix" part is misleading
+// now as it supports also Windows.
+class UnixTaskRunner : public TaskRunner {
+ public:
+ UnixTaskRunner();
+ ~UnixTaskRunner() override;
-template bool DeserializePackedRepeated<proto_utils::ProtoWireType::kVarInt,
- int32_t>(const protozero::Field& field,
- std::vector<int32_t>* dst);
+ // Start executing tasks. Doesn't return until Quit() is called. Run() may be
+ // called multiple times on the same task runner.
+ void Run();
+ void Quit();
-void SerializeTinyVarInt(uint32_t field_id, bool value, Message* msg) {
- msg->AppendTinyVarInt(field_id, value);
-}
+ // Checks whether there are any pending immediate tasks to run. Note that
+ // delayed tasks don't count even if they are due to run.
+ bool IsIdleForTesting();
-template void SerializeExtendedVarInt<uint64_t>(uint32_t field_id,
- uint64_t value,
- Message* msg);
+ // Pretends (for the purposes of running delayed tasks) that time advanced by
+ // `ms`.
+ void AdvanceTimeForTesting(uint32_t ms);
-template void SerializeExtendedVarInt<uint32_t>(uint32_t field_id,
- uint32_t value,
- Message* msg);
+ // TaskRunner implementation:
+ void PostTask(std::function<void()>) override;
+ void PostDelayedTask(std::function<void()>, uint32_t delay_ms) override;
+ void AddFileDescriptorWatch(PlatformHandle, std::function<void()>) override;
+ void RemoveFileDescriptorWatch(PlatformHandle) override;
+ bool RunsTasksOnCurrentThread() const override;
-template void SerializeFixed<double>(uint32_t field_id,
- double value,
- Message* msg);
+ // Returns true if the task runner is quitting, or has quit and hasn't been
+ // restarted since. Exposed primarily for ThreadTaskRunner, not necessary for
+ // normal use of this class.
+ bool QuitCalled();
-template void SerializeFixed<float>(uint32_t field_id,
- float value,
- Message* msg);
-
-template void SerializeFixed<uint64_t>(uint32_t field_id,
- uint64_t value,
- Message* msg);
-
-template void SerializeFixed<int64_t>(uint32_t field_id,
- int64_t value,
- Message* msg);
-
-template void SerializeFixed<uint32_t>(uint32_t field_id,
- uint32_t value,
- Message* msg);
+ private:
+ void WakeUp();
+ void UpdateWatchTasksLocked() PERFETTO_EXCLUSIVE_LOCKS_REQUIRED(lock_);
+ int GetDelayMsToNextTaskLocked() const
+ PERFETTO_EXCLUSIVE_LOCKS_REQUIRED(lock_);
+ void RunImmediateAndDelayedTask();
+ void PostFileDescriptorWatches(uint64_t windows_wait_result);
+ void RunFileDescriptorWatch(PlatformHandle);
-template void SerializeFixed<int32_t>(uint32_t field_id,
- int32_t value,
- Message* msg);
+ ThreadChecker thread_checker_;
+ std::atomic<PlatformThreadId> created_thread_id_ = GetThreadId();
-void SerializeString(uint32_t field_id,
- const std::string& value,
- Message* msg) {
- msg->AppendString(field_id, value);
-}
+ EventFd event_;
-void SerializeUnknownFields(const std::string& unknown_fields, Message* msg) {
- msg->AppendRawProtoBytes(unknown_fields.data(), unknown_fields.size());
-}
+// The array of fds/handles passed to poll(2) / WaitForMultipleObjects().
+#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
+ std::vector<PlatformHandle> poll_fds_;
+#else
+ std::vector<struct pollfd> poll_fds_;
+#endif
-MessageSerializer::MessageSerializer() = default;
+ base::MaybeRtMutex lock_;
-MessageSerializer::~MessageSerializer() = default;
+ std::deque<std::function<void()>> immediate_tasks_ PERFETTO_GUARDED_BY(lock_);
+ std::multimap<TimeMillis, std::function<void()>> delayed_tasks_
+ PERFETTO_GUARDED_BY(lock_);
+ bool quit_ PERFETTO_GUARDED_BY(lock_) = false;
+ TimeMillis advanced_time_for_testing_ PERFETTO_GUARDED_BY(lock_) =
+ TimeMillis(0);
-std::vector<uint8_t> MessageSerializer::SerializeAsArray() {
- return msg_.SerializeAsArray();
-}
+ struct WatchTask {
+ std::function<void()> callback;
+#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
+ // On UNIX systems we make the FD number negative in |poll_fds_| to avoid
+ // polling it again until the queued task runs. On Windows we can't do that.
+ // Instead we keep track of its state here.
+ bool pending = false;
+#else
+ size_t poll_fd_index; // Index into |poll_fds_|.
+#endif
+ };
-std::string MessageSerializer::SerializeAsString() {
- return msg_.SerializeAsString();
-}
+ std::map<PlatformHandle, WatchTask> watch_tasks_ PERFETTO_GUARDED_BY(lock_);
+ bool watch_tasks_changed_ PERFETTO_GUARDED_BY(lock_) = false;
+};
-template bool EqualsField<std::string>(const std::string&, const std::string&);
+} // namespace base
+} // namespace perfetto
-} // namespace gen_helpers
-} // namespace internal
-} // namespace protozero
-// gen_amalgamated begin source: src/protozero/message.cc
+#endif // INCLUDE_PERFETTO_EXT_BASE_UNIX_TASK_RUNNER_H_
/*
- * Copyright (C) 2017 The Android Open Source Project
+ * Copyright (C) 2025 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.
@@ -14531,213 +14434,272 @@ template bool EqualsField<std::string>(const std::string&, const std::string&);
* limitations under the License.
*/
-// gen_amalgamated expanded: #include "perfetto/protozero/message.h"
+#ifndef INCLUDE_PERFETTO_EXT_BASE_LOCK_FREE_TASK_RUNNER_H_
+#define INCLUDE_PERFETTO_EXT_BASE_LOCK_FREE_TASK_RUNNER_H_
+
+// gen_amalgamated expanded: #include "perfetto/base/flat_set.h"
+// gen_amalgamated expanded: #include "perfetto/base/task_runner.h"
+// gen_amalgamated expanded: #include "perfetto/base/thread_annotations.h"
+// gen_amalgamated expanded: #include "perfetto/base/time.h"
+// gen_amalgamated expanded: #include "perfetto/ext/base/event_fd.h"
+// gen_amalgamated expanded: #include "perfetto/ext/base/flags.h"
+// gen_amalgamated expanded: #include "perfetto/ext/base/scoped_file.h"
+// gen_amalgamated expanded: #include "perfetto/ext/base/unix_task_runner.h"
+
+#if !PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
+#include <poll.h>
+#endif
+#include <array>
#include <atomic>
-#include <type_traits>
+#include <thread>
+#include <unordered_map>
-// gen_amalgamated expanded: #include "perfetto/base/compiler.h"
-// gen_amalgamated expanded: #include "perfetto/base/logging.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/message_arena.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/message_handle.h"
+namespace perfetto {
+namespace base {
-#if !PERFETTO_IS_LITTLE_ENDIAN()
-// The memcpy() for float and double below needs to be adjusted if we want to
-// support big endian CPUs. There doesn't seem to be a compelling need today.
-#error Unimplemented for big endian archs.
-#endif
+namespace task_runner_internal {
+class ScopedRefcount;
+struct Slab;
-namespace protozero {
+// Exposed for testing
+constexpr uint32_t kNumRefcountBuckets = 32;
+constexpr size_t kSlabSize = 512;
-namespace {
+} // namespace task_runner_internal
-constexpr int kBytesToCompact = proto_utils::kMessageLengthFieldSize - 1u;
+template <typename T>
+class TaskRunnerTest;
-#if PERFETTO_DCHECK_IS_ON()
-std::atomic<uint32_t> g_generation;
-#endif
+// This class implements a lock-less multi-producer single-consumer task runner.
+// This is achieved by using a linked list of "slabs". Each slab is a fixed-size
+// array of tasks.
+// See /docs/design-docs/lock-free-task-runner.md for more details
+class PERFETTO_EXPORT_COMPONENT LockFreeTaskRunner : public TaskRunner {
+ public:
+ LockFreeTaskRunner();
+ ~LockFreeTaskRunner() override;
-} // namespace
+ void Run();
+ void Quit();
-// Do NOT put any code in the constructor or use default initialization.
-// Use the Reset() method below instead.
+ // Checks whether there are any pending immediate tasks to run. Note that
+ // delayed tasks don't count even if they are due to run.
+ bool IsIdleForTesting();
-// This method is called to initialize both root and nested messages.
-void Message::Reset(ScatteredStreamWriter* stream_writer, MessageArena* arena) {
-// Older versions of libstdcxx don't have is_trivially_constructible.
-#if !defined(__GLIBCXX__) || __GLIBCXX__ >= 20170516
- static_assert(std::is_trivially_constructible<Message>::value,
- "Message must be trivially constructible");
+ // TaskRunner implementation:
+ void PostTask(std::function<void()>) override;
+ void PostDelayedTask(std::function<void()>, uint32_t delay_ms) override;
+ void AddFileDescriptorWatch(PlatformHandle, std::function<void()>) override;
+ void RemoveFileDescriptorWatch(PlatformHandle) override;
+ bool RunsTasksOnCurrentThread() const override;
+
+ // Pretends (for the purposes of running delayed tasks) that time advanced by
+ // `ms`.
+ void AdvanceTimeForTesting(uint32_t ms);
+
+ // Stats for testing.
+ size_t slabs_allocated() const {
+ return slabs_allocated_.load(std::memory_order_relaxed);
+ }
+ size_t slabs_freed() const {
+ return slabs_freed_.load(std::memory_order_relaxed);
+ }
+
+ private:
+ using Slab = task_runner_internal::Slab;
+ using ScopedRefcount = task_runner_internal::ScopedRefcount;
+ friend class task_runner_internal::ScopedRefcount;
+
+ struct DelayedTask {
+ TimeMillis time;
+ uint64_t seq;
+ std::function<void()> task;
+
+ // Note that the < operator keeps the DelayedTasks sorted in reverse order
+ // (the latest one is first, the earliest one is last). This is so we can
+ // have a FIFO queue using a vector by just doing an O(1) pop_back().
+ bool operator<(const DelayedTask& other) const {
+ if (time != other.time)
+ return time > other.time;
+ return seq > other.seq;
+ }
+ bool operator==(const DelayedTask& other) const {
+ return time == other.time && seq == other.seq;
+ }
+ };
+
+ PERFETTO_ALWAYS_INLINE std::function<void()> PopNextImmediateTask();
+ std::function<void()> PopTaskRecursive(Slab*, Slab* next_slab);
+ std::function<void()> PopNextExpiredDelayedTask();
+ int GetDelayMsToNextTask() const;
+ void WakeUp() { wakeup_event_.Notify(); }
+ Slab* AllocNewSlab();
+ void DeleteSlab(Slab*);
+ void PostFileDescriptorWatches(uint64_t windows_wait_result);
+ void RunFileDescriptorWatch(PlatformHandle);
+ void UpdateWatchTasks();
+
+ // These two are semantically a unique_ptr, but are accessed from different
+ // threads.
+ std::atomic<Slab*> tail_{}; // This is never null.
+ std::atomic<Slab*> free_slab_{};
+
+ EventFd wakeup_event_;
+ bool quit_ = false;
+ std::thread::id run_task_thread_id_;
+
+ // Delayed tasks, accessed only by the main thread. Items are stored in
+ // reverse temporal order, see comment in the operator<.
+ FlatSet<DelayedTask> delayed_tasks_;
+ uint64_t next_delayed_task_seq_ = 0;
+ std::atomic<uint32_t> advanced_time_for_testing_{};
+
+ // The array of fds/handles passed to poll(2) / WaitForMultipleObjects().
+#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
+ std::vector<PlatformHandle> poll_fds_;
+#else
+ std::vector<struct pollfd> poll_fds_;
#endif
- static_assert(std::is_trivially_destructible<Message>::value,
- "Message must be trivially destructible");
- stream_writer_ = stream_writer;
- arena_ = arena;
- size_ = 0;
- size_field_ = nullptr;
- nested_message_ = nullptr;
- message_state_ = MessageState::kNotFinalized;
-#if PERFETTO_DCHECK_IS_ON()
- handle_ = nullptr;
- generation_ = g_generation.fetch_add(1, std::memory_order_relaxed);
+ struct WatchTask {
+ std::function<void()> callback;
+#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
+ // On UNIX systems we make the FD number negative in |poll_fds_| to avoid
+ // polling it again until the queued task runs. On Windows we can't do that.
+ // Instead we keep track of its state here.
+ bool pending = false;
+#else
+ size_t poll_fd_index; // Index into |poll_fds_|.
#endif
-}
+ };
-void Message::AppendString(uint32_t field_id, const char* str) {
- AppendBytes(field_id, str, strlen(str));
-}
+ // Accessed only from the main thread.
+ std::unordered_map<PlatformHandle, WatchTask> watch_tasks_;
+ bool watch_tasks_changed_ = false;
-void Message::AppendBytes(uint32_t field_id, const void* src, size_t size) {
- PERFETTO_DCHECK(field_id);
- if (nested_message_)
- EndNestedMessage();
+ // An array of 32 refcount buckets. Every Slab* maps to a bucket via a hash
+ // function. Every PostTask() thread increases the refcount before accessing
+ // a slab, and decreases it when done.
+ // This allows the Run() main thread to tell if any thread has possibly been
+ // able to observe the Slab through the tail_ before deleting it.
+ std::array<std::atomic<int32_t>, task_runner_internal::kNumRefcountBuckets>
+ refcounts_{};
- PERFETTO_DCHECK(size < proto_utils::kMaxMessageLength);
- // Write the proto preamble (field id, type and length of the field).
- uint8_t buffer[proto_utils::kMaxSimpleFieldEncodedSize];
- uint8_t* pos = buffer;
- pos = proto_utils::WriteVarInt(proto_utils::MakeTagLengthDelimited(field_id),
- pos);
- pos = proto_utils::WriteVarInt(static_cast<uint32_t>(size), pos);
- WriteToStream(buffer, pos);
+ // Stats for testing.
+ std::atomic<size_t> slabs_allocated_{};
+ std::atomic<size_t> slabs_freed_{};
+};
- const uint8_t* src_u8 = reinterpret_cast<const uint8_t*>(src);
- WriteToStream(src_u8, src_u8 + size);
-}
+namespace task_runner_internal {
-size_t Message::AppendScatteredBytes(uint32_t field_id,
- ContiguousMemoryRange* ranges,
- size_t num_ranges) {
- PERFETTO_DCHECK(field_id);
- if (nested_message_)
- EndNestedMessage();
+// Returns the index of the refcount_ bucket for the passed Slab pointer.
+static uint32_t HashSlabPtr(Slab* slab) {
+ // This is a SplitMix64 hash, which is very fast and effective with pointers
+ // (See the test LockFreeTaskRunnerTest.HashSpreading).
+ uint64_t u = reinterpret_cast<uintptr_t>(slab);
+ u &= 0x00FFFFFFFFFFFFFFull; // Clear asan/MTE top byte for tagged pointers.
+ u += 0x9E3779B97F4A7C15ull;
+ u = (u ^ (u >> 30)) * 0xBF58476D1CE4E5B9ull;
+ u = (u ^ (u >> 27)) * 0x94D049BB133111EBull;
+ return static_cast<uint32_t>((u ^ (u >> 31)) % kNumRefcountBuckets);
+}
- size_t size = 0;
- for (size_t i = 0; i < num_ranges; ++i) {
- size += ranges[i].size();
- }
+// A slab is a fixed-size array of tasks. The lifecycle of a task slot
+// within a slab goes through three phases:
+//
+// 1. Reservation: A writer thread atomically increments `next_task_slot` to
+// reserve a slot in the `tasks` array. This reservation establishes the
+// implicit order in which the consumer will attempt to read tasks (but
+// only if they are published in the bitmap, see below).
+//
+// 2. Publishing: After writing the task into its reserved slot, the writer
+// thread atomically sets the corresponding bit in the `tasks_written`
+// bitmask. This acts as a memory barrier and makes the task visible to
+// the consumer (main) thread.
+//
+// 3. Consumption: The main thread acquire-reads the `tasks_written` bitmask.
+// For each bit that is set, it processes the task and then sets the
+// corresponding bit in its private `tasks_read` bitmask to prevent
+// reading the same task again.
+struct Slab {
+ Slab();
+ ~Slab();
- PERFETTO_DCHECK(size < proto_utils::kMaxMessageLength);
+ std::atomic<size_t> next_task_slot{0};
- uint8_t buffer[proto_utils::kMaxSimpleFieldEncodedSize];
- uint8_t* pos = buffer;
- pos = proto_utils::WriteVarInt(proto_utils::MakeTagLengthDelimited(field_id),
- pos);
- pos = proto_utils::WriteVarInt(static_cast<uint32_t>(size), pos);
- WriteToStream(buffer, pos);
+ // `tasks` and `next_task_slot` are accessed by writer threads only.
+ // The main thread can access `tasks[i]` but only after ensuring that the
+ // corresponding bit in `tasks_written` is set.
+ std::array<std::function<void()>, kSlabSize> tasks{};
- for (size_t i = 0; i < num_ranges; ++i) {
- auto& range = ranges[i];
- WriteToStream(range.begin, range.end);
- }
+ // A bitmask indicating which tasks in the `tasks` array have been written
+ // and are ready to be read by the main thread.
+ // This is atomically updated by writer threads and read by the main thread.
+ using BitWord = size_t;
+ static constexpr size_t kBitsPerWord = sizeof(BitWord) * 8;
+ static constexpr size_t kNumWords = kSlabSize / kBitsPerWord;
+ std::array<std::atomic<BitWord>, kNumWords> tasks_written{};
- return size;
-}
+ // A bitmask indicating which tasks have been read by the main thread.
+ // This is accessed only by the main thread, so no atomicity is required.
+ std::array<BitWord, kNumWords> tasks_read{};
-uint32_t Message::Finalize() {
- if (is_finalized())
- return size_;
+ // The link to the previous slab.
+ // This is written by writer threads when they create a new slab and link it
+ // to the previous tail. But they do so when nobody else can see the Slab,
+ // so there is no need for an atomic ptr. After the initial creation,
+ // this is accessed only by the main thread when:
+ // 1. draining tasks (to walk back to the oldest slab)
+ // 2. deleting slabs, setting it to nullptr, when they are fully consumed.
+ Slab* prev = nullptr;
+};
- if (nested_message_)
- EndNestedMessage();
+class ScopedRefcount {
+ public:
+ ScopedRefcount(LockFreeTaskRunner* tr, LockFreeTaskRunner::Slab* slab) {
+ bucket_ = &tr->refcounts_[HashSlabPtr(slab)];
+ auto prev_value = bucket_->fetch_add(1);
+ PERFETTO_DCHECK(prev_value >= 0);
+ }
- // Write the length of the nested message a posteriori, using a leading-zero
- // redundant varint encoding. This can be nullptr for the root message, among
- // many reasons, because the TraceWriterImpl delegate is keeping track of the
- // root fragment size independently.
- if (size_field_) {
- PERFETTO_DCHECK(!is_finalized());
- PERFETTO_DCHECK(size_ < proto_utils::kMaxMessageLength);
- //
- // Normally the size of a protozero message is written with 4 bytes just
- // before the contents of the message itself:
- //
- // size message data
- // [aa bb cc dd] [01 23 45 67 ...]
- //
- // We always reserve 4 bytes for the size, because the real size of the
- // message isn't known until the call to Finalize(). This is possible
- // because we can use leading zero redundant varint coding to expand any
- // size smaller than 256 MiB to 4 bytes.
- //
- // However this is wasteful for short, frequently written messages, so the
- // code below uses a 1 byte size field when possible. This is done by
- // shifting the already-written data (which should still be in the cache)
- // back by 3 bytes, resulting in this layout:
- //
- // size message data
- // [aa] [01 23 45 67 ...]
- //
- // We can only do this optimization if the message is contained in a single
- // chunk (since we can't modify previously committed chunks). We can check
- // this by verifying that the size field is immediately before the message
- // in memory and is fully contained by the current chunk.
- //
- if (PERFETTO_LIKELY(size_ <= proto_utils::kMaxOneByteMessageLength &&
- size_field_ ==
- stream_writer_->write_ptr() - size_ -
- proto_utils::kMessageLengthFieldSize &&
- size_field_ >= stream_writer_->cur_range().begin)) {
- stream_writer_->Rewind(size_, kBytesToCompact);
- PERFETTO_DCHECK(size_field_ == stream_writer_->write_ptr() - size_ - 1u);
- *size_field_ = static_cast<uint8_t>(size_);
- message_state_ = MessageState::kFinalizedWithCompaction;
- } else {
- proto_utils::WriteRedundantVarInt(size_, size_field_);
- message_state_ = MessageState::kFinalized;
+ ~ScopedRefcount() {
+ if (bucket_) {
+ auto prev_value = bucket_->fetch_sub(1);
+ PERFETTO_DCHECK(prev_value > 0);
}
- size_field_ = nullptr;
- } else {
- message_state_ = MessageState::kFinalized;
}
-#if PERFETTO_DCHECK_IS_ON()
- if (handle_)
- handle_->reset_message();
-#endif
-
- return size_;
-}
+ ScopedRefcount(ScopedRefcount&& other) noexcept {
+ bucket_ = other.bucket_;
+ other.bucket_ = nullptr;
+ }
-Message* Message::BeginNestedMessageInternal(uint32_t field_id) {
- PERFETTO_DCHECK(field_id);
- if (nested_message_)
- EndNestedMessage();
+ ScopedRefcount& operator=(ScopedRefcount&& other) noexcept {
+ this->~ScopedRefcount();
+ new (this) ScopedRefcount(std::move(other));
+ return *this;
+ }
- // Write the proto preamble for the nested message.
- uint8_t data[proto_utils::kMaxTagEncodedSize];
- uint8_t* data_end = proto_utils::WriteVarInt(
- proto_utils::MakeTagLengthDelimited(field_id), data);
- WriteToStream(data, data_end);
+ ScopedRefcount(const ScopedRefcount&) = delete;
+ ScopedRefcount& operator=(const ScopedRefcount&) = delete;
- Message* message = arena_->NewMessage();
- message->Reset(stream_writer_, arena_);
+ std::atomic<int32_t>* bucket_{};
+};
+} // namespace task_runner_internal
- // The length of the nested message cannot be known upfront. So right now
- // just reserve the bytes to encode the size after the nested message is done.
- message->set_size_field(
- stream_writer_->ReserveBytes(proto_utils::kMessageLengthFieldSize));
- size_ += proto_utils::kMessageLengthFieldSize;
+using MaybeLockFreeTaskRunner =
+ std::conditional_t<PERFETTO_FLAGS(USE_LOCKFREE_TASKRUNNER),
+ LockFreeTaskRunner,
+ UnixTaskRunner>;
- nested_message_ = message;
- return message;
-}
+} // namespace base
+} // namespace perfetto
-void Message::EndNestedMessage() {
- size_ += nested_message_->Finalize();
- if (nested_message_->message_state_ ==
- MessageState::kFinalizedWithCompaction) {
- size_ -= kBytesToCompact;
- }
- arena_->DeleteLastMessage(nested_message_);
- nested_message_ = nullptr;
-}
+#endif // INCLUDE_PERFETTO_EXT_BASE_LOCK_FREE_TASK_RUNNER_H_
-} // namespace protozero
-// gen_amalgamated begin source: src/protozero/message_arena.cc
/*
- * Copyright (C) 2020 The Android Open Source Project
+ * Copyright (C) 2025 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.
@@ -14745,586 +14707,546 @@ void Message::EndNestedMessage() {
*
* 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,
+ * Unless required by applicable law of 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.
*/
-// gen_amalgamated expanded: #include "perfetto/protozero/message_arena.h"
+// gen_amalgamated expanded: #include "perfetto/ext/base/lock_free_task_runner.h"
-#include <atomic>
-#include <type_traits>
+// gen_amalgamated expanded: #include "perfetto/base/build_config.h"
+
+#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
+#include <windows.h>
+
+// Keep the \n before to prevent clang-format reordering.
+#include <synchapi.h>
+#else
+#include <poll.h>
+#include <unistd.h>
+#endif
+
+#include <thread>
// gen_amalgamated expanded: #include "perfetto/base/logging.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/message_handle.h"
+// gen_amalgamated expanded: #include "perfetto/base/time.h"
+// gen_amalgamated expanded: #include "perfetto/ext/base/bits.h"
+// gen_amalgamated expanded: #include "perfetto/ext/base/platform.h"
+// gen_amalgamated expanded: #include "perfetto/ext/base/utils.h"
+// gen_amalgamated expanded: #include "perfetto/ext/base/watchdog.h"
-namespace protozero {
+namespace perfetto {
+namespace base {
-MessageArena::MessageArena() {
- // The code below assumes that there is always at least one block.
- blocks_.emplace_front();
+namespace task_runner_internal {
+Slab::Slab() = default;
+Slab::~Slab() {
+ PERFETTO_DCHECK(!prev); // We should never delete linked slabs.
}
+} // namespace task_runner_internal
-MessageArena::~MessageArena() = default;
+namespace {
+static constexpr auto kSlabSize = task_runner_internal::kSlabSize;
+}
-Message* MessageArena::NewMessage() {
- PERFETTO_DCHECK(!blocks_.empty()); // Should never become empty.
+LockFreeTaskRunner::LockFreeTaskRunner()
+ : run_task_thread_id_(std::this_thread::get_id()) {
+ static_assert((kSlabSize & (kSlabSize - 1)) == 0, "kSlabSize must be a pow2");
+ static_assert(kSlabSize >= Slab::kBitsPerWord);
- Block* block = &blocks_.front();
- if (PERFETTO_UNLIKELY(block->entries >= Block::kCapacity)) {
- blocks_.emplace_front();
- block = &blocks_.front();
- }
- const auto idx = block->entries++;
- void* storage = block->storage[idx];
- PERFETTO_ASAN_UNPOISON(storage, sizeof(Message));
- return new (storage) Message();
-}
-
-void MessageArena::DeleteLastMessageInternal() {
- PERFETTO_DCHECK(!blocks_.empty()); // Should never be empty, see below.
- Block* block = &blocks_.front();
- PERFETTO_DCHECK(block->entries > 0);
+ // Populate both the tail and the freelist, to minimize the chance of
+ // allocations at runtime.
+ tail_.store(AllocNewSlab());
+ free_slab_.store(AllocNewSlab());
- // This is the reason why there is no ~Message() call here.
- // MessageArea::Reset() (see header) also relies on dtor being trivial.
- static_assert(std::is_trivially_destructible<Message>::value,
- "Message must be trivially destructible");
+ AddFileDescriptorWatch(wakeup_event_.fd(), [] {
+ // Not reached -- see PostFileDescriptorWatches().
+ PERFETTO_DFATAL("Should be unreachable.");
+ });
+}
- --block->entries;
- PERFETTO_ASAN_POISON(&block->storage[block->entries], sizeof(Message));
+LockFreeTaskRunner::~LockFreeTaskRunner() {
+ PERFETTO_DCHECK(RunsTasksOnCurrentThread());
- // Don't remove the first block to avoid malloc/free calls when the root
- // message is reset. Hitting the allocator all the times is a waste of time.
- if (block->entries == 0 && std::next(blocks_.cbegin()) != blocks_.cend()) {
- blocks_.pop_front();
+ for (Slab* slab = tail_.exchange(nullptr); slab;) {
+ Slab* prev = slab->prev;
+ slab->prev = nullptr;
+ delete slab;
+ slab = prev;
}
+ delete free_slab_.exchange(nullptr);
}
-} // namespace protozero
-// gen_amalgamated begin source: src/protozero/packed_repeated_fields.cc
-/*
- * 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.
- */
+void LockFreeTaskRunner::PostTask(std::function<void()> closure) {
+ // We use nullity of std::function in PopTaskRecursive() to determine exit
+ // criteria. Posting a null task would break that logic. Also a null task
+ // would cause an abort when trying to run it later on.
+ PERFETTO_CHECK(PERFETTO_LIKELY(closure));
+ using BitWord = Slab::BitWord;
+ for (;;) {
+ Slab* slab = tail_.load();
+ PERFETTO_DCHECK(slab); // The tail_ must be always valid.
+ ScopedRefcount scoped_refcount(this, slab);
+ // After incrementing the refcount, re-verify that `slab` is still the
+ // current tail. If it isn't, the slab might have been deleted between
+ // our tail_.load() above and the refcount inc (the reader's check on
+ // refcount==0 may have happened before our inc). Retry with the new tail.
+ // If the second tail.load() returns the same slab, in seq_cst order
+ // any subsequent CAS that replaces tail_ comes after this load, hence
+ // any reader's later refcount check is also after our inc and will
+ // observe refcount > 0.
+ if (PERFETTO_UNLIKELY(tail_.load() != slab)) {
+ continue;
+ }
-// gen_amalgamated expanded: #include "perfetto/protozero/packed_repeated_fields.h"
+ // Now that we have a slab, try appending a task to it (if there is space).
+ // We have 3 cases:
+ // 1. slot < kSlabSize: the nominal case. Append the task and return.
+ // 2. slot == kSlabSize: the common overflow case: The slab was full and we
+ // tried to allocate the N+1 th element. We have to allocate a new Slab.
+ // 3. slot > kSlabSize: like 2, but but two (or more) threads raced on it.
+ // One thread will win the race and alloc a new slab, the other one will
+ // repeat.
+ size_t slot = slab->next_task_slot.fetch_add(1, std::memory_order_relaxed);
-// gen_amalgamated expanded: #include "perfetto/ext/base/utils.h"
+ if (slot >= kSlabSize) { // Cases 2,3
+ Slab* new_slab = AllocNewSlab();
+ new_slab->prev = slab;
+ new_slab->next_task_slot.store(1, std::memory_order_relaxed);
+ slot = 0;
+ if (PERFETTO_UNLIKELY(!tail_.compare_exchange_strong(slab, new_slab))) {
+ // If the cmpxcgh fails, another thread tried to allocate a new tail
+ // slab and won the race. Do another round, we'll observe the new slab.
+ // We have to release the prev pointer as at this point we found out
+ // another thread also has it.
+ new_slab->prev = nullptr;
+ DeleteSlab(new_slab);
+ continue;
+ }
-namespace protozero {
+ slab = new_slab;
+ scoped_refcount = ScopedRefcount(this, new_slab);
+ }
-void PackedBufferBase::GrowSlowpath() {
- size_t write_off = static_cast<size_t>(write_ptr_ - storage_begin_);
- size_t old_size = static_cast<size_t>(storage_end_ - storage_begin_);
- size_t new_size = old_size < 65536 ? (old_size * 2) : (old_size * 3 / 2);
- new_size = perfetto::base::AlignUp<4096>(new_size);
- std::unique_ptr<uint8_t[]> new_buf(new uint8_t[new_size]);
- memcpy(new_buf.get(), storage_begin_, old_size);
- heap_buf_ = std::move(new_buf);
- storage_begin_ = heap_buf_.get();
- storage_end_ = storage_begin_ + new_size;
- write_ptr_ = storage_begin_ + write_off;
-}
+ // Nominal case: publish the task and return.
+ PERFETTO_DCHECK(!slab->tasks[slot]);
+ slab->tasks[slot] = std::move(closure);
+ size_t s_word = slot / Slab::kBitsPerWord;
+ size_t s_bit = slot % Slab::kBitsPerWord;
+ BitWord s_mask = BitWord(1) << s_bit;
+ PERFETTO_DCHECK(
+ (slab->tasks_written[s_word].load(std::memory_order_relaxed) &
+ s_mask) == 0);
+ slab->tasks_written[s_word].fetch_or(s_mask, std::memory_order_release);
-void PackedBufferBase::Reset() {
- heap_buf_.reset();
- storage_begin_ = reinterpret_cast<uint8_t*>(&stack_buf_[0]);
- storage_end_ = reinterpret_cast<uint8_t*>(&stack_buf_[kOnStackStorageSize]);
- write_ptr_ = storage_begin_;
+ if (!RunsTasksOnCurrentThread()) {
+ // We don't need any clever logic to avoid spurious wake ups from other
+ // threads. Most PostTask()s in our codebase are done by the main thread.
+ // In the rare cases of a PostTask() coming from another thread, the odds
+ // of the main thread being woken up at the same time are tiny.
+ WakeUp();
+ }
+ return;
+ }
}
-} // namespace protozero
-// gen_amalgamated begin source: src/protozero/proto_decoder.cc
-/*
- * 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.
- */
-
-// gen_amalgamated expanded: #include "perfetto/protozero/proto_decoder.h"
-
-#include <string.h>
+void LockFreeTaskRunner::Run() {
+ PERFETTO_CHECK(run_task_thread_id_ == std::this_thread::get_id());
+ quit_ = false;
-#include <cinttypes>
-#include <limits>
-#include <memory>
+ while (!quit_) {
+ // Pop one immediate and one delayed task, for fairness.
+ std::function<void()> immediate_task = PopNextImmediateTask();
+ std::function<void()> delayed_task = PopNextExpiredDelayedTask();
+ bool has_task = immediate_task || delayed_task;
+ int poll_timeout_ms = has_task ? 0 : GetDelayMsToNextTask();
-// gen_amalgamated expanded: #include "perfetto/base/compiler.h"
-// gen_amalgamated expanded: #include "perfetto/base/logging.h"
-// gen_amalgamated expanded: #include "perfetto/ext/base/utils.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/proto_utils.h"
-// gen_amalgamated expanded: #include "perfetto/public/compiler.h"
+ // run the poll(). We need it for two different reasons:
+ // 1. Blocks until the next event on the horizon, which:
+ // - If we pulled a task, poll in non-blocking mode (0 delay). There
+ // might be other tasks ready and we want to run them soon after.
+ // - If there is a delayed task, compute the time remaining for it.
+ // - Otherwise polls indefinitely, waiting for a PostTask() or a Quit()
+ // call from another thread.
+ // 2. Regardless of timing, we need to read the FD watches.
+ // We want to do this even if we know already that we have an immediate
+ // task (when poll_timeout_ms = 0) to ensure fairness.
-namespace protozero {
+ // TODO(primiano): we could optimize this and avoid a syscall for each
+ // task when we have bursts of tasks (with some saturation, e.g. do still
+ // a poll() every 10 tasks). Unfortunately, however, some users of
+ // TestTaskRunner.RunUntilIdle() rely on the fact that FD watches are
+ // polled before the current task is ran, so that the task can tell if
+ // there are more tasks upcoming or it has reached quiescence.
+ // TL;DR RunUntilIdle() was a mistake as it has ill-defined semantics but
+ // now tests rely on those subtle semantics.
-using namespace proto_utils;
+ // Recompute the list of FDs to watch.
+ UpdateWatchTasks();
-#if !PERFETTO_IS_LITTLE_ENDIAN()
-#error Unimplemented for big endian archs.
+ uint64_t windows_wait_res = 0;
+#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
+ // Unlike poll(2), WaitForMultipleObjects() returns only *one* handle in the
+ // set, even when >1 is signalled. In order to avoid starvation,
+ // PostFileDescriptorWatches() will WaitForSingleObject() each other handle
+ // to ensure fairness. |windows_wait_res| is passed just to avoid an extra
+ // WaitForSingleObject() for the one handle that WaitForMultipleObject()
+ // returned.
+ DWORD timeout =
+ poll_timeout_ms >= 0 ? static_cast<DWORD>(poll_timeout_ms) : INFINITE;
+ windows_wait_res =
+ WaitForMultipleObjects(static_cast<DWORD>(poll_fds_.size()),
+ &poll_fds_[0], /*bWaitAll=*/false, timeout);
+#else
+ platform::BeforeMaybeBlockingSyscall();
+ int ret = PERFETTO_EINTR(poll(
+ &poll_fds_[0], static_cast<nfds_t>(poll_fds_.size()), poll_timeout_ms));
+ platform::AfterMaybeBlockingSyscall();
+ PERFETTO_CHECK(ret >= 0);
#endif
+ PostFileDescriptorWatches(windows_wait_res);
-const Field TypedProtoDecoderBase::kInvalidField{};
-
-namespace {
-
-struct ParseFieldResult {
- enum ParseResult { kAbort, kSkip, kOk };
- ParseResult parse_res;
- const uint8_t* next;
- Field field;
-};
+ if (immediate_task) {
+ errno = 0;
+ RunTaskWithWatchdogGuard(std::move(immediate_task));
+ }
-// Parses one field and returns the field itself and a pointer to the next
-// field to parse. If parsing fails, the returned |next| == |buffer|.
-// Force-inlined so that, after inlining, the result struct is decomposed by
-// the compiler and does not round-trip through memory.
-PERFETTO_ALWAYS_INLINE ParseFieldResult
-ParseOneField(const uint8_t* const buffer, const uint8_t* const end) {
- ParseFieldResult res{ParseFieldResult::kAbort, buffer, Field{}};
+ if (delayed_task) {
+ errno = 0;
+ RunTaskWithWatchdogGuard(std::move(delayed_task));
+ }
+ }
- const uint8_t* pos = buffer;
+ // Wait for all other threads to have finished the Quit's PostTask().
+ // This is to prevent the following race in tests:
+ // - Thread1 (!= main thread) invokes Quit, which in turn becomes a PostTask.
+ // - This function sees quit_=true and returns from Run().
+ // - The owner of the LFTR at that point is entitled to destroy LFTR.
+ // - Thread1 is still executing the epilogue of the PostTask, decrementing the
+ // refcount, and ends up operating on invalid memory.
+ while (
+ std::any_of(refcounts_.begin(), refcounts_.end(),
+ [](std::atomic<int32_t>& bucket) { return bucket.load(); })) {
+ std::this_thread::yield();
+ }
+}
- // If we've already hit the end, just return an invalid field.
- if (PERFETTO_UNLIKELY(pos >= end))
- return res;
+std::function<void()> LockFreeTaskRunner::PopNextImmediateTask() {
+ return PopTaskRecursive(tail_.load(), nullptr);
+}
- uint64_t preamble = 0;
- if (PERFETTO_LIKELY(*pos < 0x80)) { // Fastpath for fields with ID < 16.
- preamble = *(pos++);
- } else {
- const uint8_t* next = ParseVarIntFast(pos, end, &preamble);
- if (PERFETTO_UNLIKELY(!next))
- return res;
- pos = next;
+std::function<void()> LockFreeTaskRunner::PopTaskRecursive(Slab* slab,
+ Slab* next_slab) {
+ PERFETTO_DCHECK(RunsTasksOnCurrentThread());
+ Slab* prev = slab->prev;
+ if (PERFETTO_UNLIKELY(prev)) {
+ // In practice it's extemely unlikely that a slab has >1 predecessors.
+ // In nominal conditions it is going to have 0 predecessors most of the
+ // times and 1 predecessors 1 every kSlabSize times.
+ auto task = PopTaskRecursive(prev, slab);
+ if (task)
+ return task;
}
- uint32_t field_id =
- static_cast<uint32_t>(proto_utils::GetTagFieldId(preamble));
- if (field_id == 0 || pos >= end)
- return res;
+ size_t words_fully_consumed = 0;
+ for (size_t w = 0; w < Slab::kNumWords; ++w) {
+ using BitWord = Slab::BitWord;
+ BitWord wr_word = slab->tasks_written[w].load(std::memory_order_acquire);
+ BitWord rd_word = slab->tasks_read[w];
+ words_fully_consumed += base::AllBitsSet(rd_word) ? 1 : 0;
+ BitWord unread_word = wr_word & ~rd_word;
- auto field_type =
- static_cast<uint8_t>(proto_utils::GetTagFieldType(preamble));
- const uint8_t* new_pos = pos;
- uint64_t int_value = 0;
- uint64_t size = 0;
+ if (unread_word == 0)
+ continue;
- // If-chain ordered by observed frequency: wire types within a message are
- // near-constant, so these branches predict better than a switch jump.
- if (PERFETTO_LIKELY(field_type ==
- static_cast<uint8_t>(ProtoWireType::kVarInt))) {
- new_pos = ParseVarIntFast(pos, end, &int_value);
+ // Find the first unread task in the word.
+ uint32_t bit = base::CountTrailZeros(unread_word);
+ BitWord bit_mask = BitWord(1) << bit;
+ size_t slot = w * Slab::kBitsPerWord + bit;
+ std::function<void()> task = std::move(slab->tasks[slot]);
+ slab->tasks[slot] = nullptr;
+ slab->tasks_read[w] |= bit_mask;
+ return task;
+ } // for(word in tasks_written)
- // new_pos being null means ParseVarIntFast could not fully parse the
- // number. This is because we are out of space in the buffer. Set the id
- // to zero and return but don't update the offset so a future read can
- // read this field.
- if (PERFETTO_UNLIKELY(!new_pos))
- return res;
- } else if (PERFETTO_LIKELY(
- field_type ==
- static_cast<uint8_t>(ProtoWireType::kLengthDelimited))) {
- uint64_t payload_length;
- new_pos = ParseVarIntFast(pos, end, &payload_length);
- if (PERFETTO_UNLIKELY(!new_pos))
- return res;
+ // There are no unconsumed tasks in this Slab. Reached this point, this
+ // invocation will return null. However, before doing so, if the slab is fully
+ // written (are no slots left) and fully consumed delete it.
+ // We never delete the latest slab (the one pointed to by tail_) because
+ // we want the tail_ to always point to a valid slab.
+ // In principle, we only delete non-tail slabs, and PostTask() threads only
+ // access the tail, never walk back on the list, which sounds safe. However
+ // there is a potential race we have to guard against:
+ // A PostTask() thread could observe Slab 1 (e.g., the only slab), then
+ // another PostTask thread() could append (and replace tail_ with) a new
+ // Slab 2 (because Slab 1 was full).
+ // If Run() comes along and sees the Slab 1 full it will delete it, without
+ // realizing that the first thread is still accessing it, thinking it was the
+ // tail.
+ // Essentially, it is safe to delete non-tail slabs as long as we can
+ // guarrantee that no other thread observed that slab through the `tail_` at
+ // some point in the recent past. In order to do so, we use a refcount
+ // mechanism. If the refcount is 0 we know that no other PostTask thread
+ // has loaded the tail, and hence we can safely delete any non-tail slab.
+ // If a PostTask thread comes immediately after our check they will observe
+ // the new tail (we never delete the tail slab, only the predecessors).
- // ParseVarIntFast guarantees that |new_pos| <= |end| when it succeeds;
- if (payload_length > static_cast<uint64_t>(end - new_pos))
- return res;
+ bool slab_fully_consumed = words_fully_consumed == Slab::kNumWords;
- const uintptr_t payload_start = reinterpret_cast<uintptr_t>(new_pos);
- int_value = payload_start;
- size = payload_length;
- new_pos += payload_length;
- } else if (field_type == static_cast<uint8_t>(ProtoWireType::kFixed64)) {
- new_pos = pos + sizeof(uint64_t);
- if (PERFETTO_UNLIKELY(new_pos > end))
- return res;
- memcpy(&int_value, pos, sizeof(uint64_t));
- } else if (field_type == static_cast<uint8_t>(ProtoWireType::kFixed32)) {
- new_pos = pos + sizeof(uint32_t);
- if (PERFETTO_UNLIKELY(new_pos > end))
- return res;
- memcpy(&int_value, pos, sizeof(uint32_t));
- } else {
- PERFETTO_DLOG("Invalid proto field type: %u", field_type);
- return res;
+ const uint32_t bucket = HashSlabPtr(slab);
+ if (slab_fully_consumed && next_slab && refcounts_[bucket].load() == 0) {
+ // NOTE: only the main thread follows the `prev` linked list, writers never
+ // look at `prev`. The only contention entrypoint is the `tail_` pointer,
+ // which can be modified both by us and by writers.
+ PERFETTO_DCHECK(next_slab->prev == slab);
+ next_slab->prev = slab->prev;
+ slab->prev = nullptr;
+ DeleteSlab(slab);
}
- res.next = new_pos;
+ return nullptr;
+}
- if (PERFETTO_UNLIKELY(field_id > Field::kMaxId)) {
- PERFETTO_DLOG("Skipping field %" PRIu32 " because its id > %" PRIu32,
- field_id, Field::kMaxId);
- res.parse_res = ParseFieldResult::kSkip;
- return res;
+void LockFreeTaskRunner::Quit() {
+ // We have to post the writing of the quit if we are not on the right thread.
+ // The alternative would be writing quit_ + WakeUp(), but that is racy:
+ // - We write quit_=true from another thread
+ // - The main thread sees it immediately (it just happens to be iterating)
+ // and destroys itself.
+ // - We try to call WakeUp() while the main thread is being destroyed.
+ if (!RunsTasksOnCurrentThread()) {
+ PostTask([this] { this->Quit(); });
+ return;
}
+ quit_ = true;
+}
- if (PERFETTO_UNLIKELY(size > proto_utils::kMaxMessageLength)) {
- PERFETTO_DLOG("Skipping field %" PRIu32 " because it's too big (%" PRIu64
- " KB)",
- field_id, size / 1024);
- res.parse_res = ParseFieldResult::kSkip;
- return res;
+bool LockFreeTaskRunner::IsIdleForTesting() {
+ PERFETTO_DCHECK(RunsTasksOnCurrentThread());
+ for (Slab* slab = tail_; slab; slab = slab->prev) {
+ for (size_t i = 0; i < Slab::kNumWords; ++i) {
+ if (slab->tasks_written[i] & ~slab->tasks_read[i]) {
+ return false;
+ }
+ }
}
-
- res.parse_res = ParseFieldResult::kOk;
- res.field.initialize(field_id, field_type, int_value,
- static_cast<uint32_t>(size));
- return res;
+ return true;
}
-// Grows the selective-decoding spill area once the inline slots are
-// exhausted, moving the spilled fields to the heap. The append itself is
-// open-coded in the decode loop; see the comment there.
-PERFETTO_NO_INLINE void ExpandSpill(Field** spill,
- uint32_t* spill_capacity,
- uint32_t spill_size,
- std::unique_ptr<Field[]>* heap_spill) {
- // Double the capacity, with a floor so that an exhausted spill that somehow
- // starts from zero capacity (e.g. a moved-from state) doesn't keep doubling
- // zero. The floor matches SelectiveTypedProtoDecoder::kSpillStackCapacity.
- const uint32_t new_capacity = std::max(*spill_capacity * 2, 16u);
- PERFETTO_CHECK(new_capacity > spill_size);
- std::unique_ptr<Field[]> new_storage(new Field[new_capacity]);
- if (spill_size > 0)
- memcpy(&new_storage[0], *spill, sizeof(Field) * spill_size);
- *heap_spill = std::move(new_storage);
- *spill = &(*heap_spill)[0];
- *spill_capacity = new_capacity;
+std::function<void()> LockFreeTaskRunner::PopNextExpiredDelayedTask() {
+ PERFETTO_DCHECK(RunsTasksOnCurrentThread());
+ TimeMillis now =
+ GetWallTimeMs() +
+ TimeMillis(advanced_time_for_testing_.load(std::memory_order_relaxed));
+ if (!delayed_tasks_.empty() && delayed_tasks_.back().time <= now) {
+ auto task = std::move(delayed_tasks_.back().task);
+ delayed_tasks_.pop_back();
+ return task;
+ }
+ return nullptr;
}
-} // namespace
-
-Field ProtoDecoder::FindField(uint32_t field_id) {
- Field res{};
- auto old_position = read_ptr_;
- read_ptr_ = begin_;
- for (auto f = ReadField(); f.valid(); f = ReadField()) {
- if (f.id() == field_id) {
- res = f;
- break;
- }
+int LockFreeTaskRunner::GetDelayMsToNextTask() const {
+ PERFETTO_DCHECK(RunsTasksOnCurrentThread());
+ if (delayed_tasks_.empty()) {
+ return -1; // Forever.
}
- read_ptr_ = old_position;
- return res;
+ TimeMillis now =
+ GetWallTimeMs() +
+ TimeMillis(advanced_time_for_testing_.load(std::memory_order_relaxed));
+ TimeMillis deadline = delayed_tasks_.back().time;
+ if (deadline <= now) {
+ return 0;
+ }
+ return static_cast<int>((deadline - now).count());
}
-Field ProtoDecoder::ReadField() {
- ParseFieldResult res;
- do {
- res = ParseOneField(read_ptr_, end_);
- read_ptr_ = res.next;
- } while (PERFETTO_UNLIKELY(res.parse_res == ParseFieldResult::kSkip));
- return res.field;
+LockFreeTaskRunner::Slab* LockFreeTaskRunner::AllocNewSlab() {
+ Slab* free_slab = free_slab_.exchange(nullptr);
+ if (free_slab) {
+ free_slab->~Slab();
+ new (free_slab) Slab();
+ return free_slab;
+ }
+ slabs_allocated_.fetch_add(1, std::memory_order_relaxed);
+ return new Slab();
}
-void TypedProtoDecoderBase::ParseAllFields() {
- ParseAllFieldsImpl<false>(nullptr, nullptr, nullptr, nullptr, nullptr);
+void LockFreeTaskRunner::DeleteSlab(Slab* slab) {
+ PERFETTO_DCHECK(!slab->prev); // We should never delete a linked slab.
+ Slab* null_slab = nullptr;
+ if (!free_slab_.compare_exchange_strong(null_slab, slab)) {
+ slabs_freed_.fetch_add(1, std::memory_order_relaxed);
+ delete slab;
+ }
}
-void TypedProtoDecoderBase::ParseAllFieldsSelective(
- const uint64_t* dense_mask,
- Field** spill,
- uint32_t* spill_capacity,
- uint32_t* spill_size,
- std::unique_ptr<Field[]>* heap_spill) {
- PERFETTO_DCHECK(dense_mask && spill && spill_capacity && spill_size &&
- heap_spill);
- ParseAllFieldsImpl<true>(dense_mask, spill, spill_capacity, spill_size,
- heap_spill);
-}
-
-// Force-inlined into the two thin entry points above: the plain
-// instantiation compiles to a loop with no trace of the mask support and
-// the wrappers' arguments fold away entirely.
-template <bool kSelective>
-PERFETTO_ALWAYS_INLINE void TypedProtoDecoderBase::ParseAllFieldsImpl(
- const uint64_t* dense_mask,
- Field** spill,
- uint32_t* spill_capacity,
- uint32_t* spill_size,
- std::unique_ptr<Field[]>* heap_spill) {
- const uint8_t* cur = begin_;
- ParseFieldResult res;
- for (;;) {
- res = ParseOneField(cur, end_);
- PERFETTO_DCHECK(res.parse_res != ParseFieldResult::kOk || res.next != cur);
- cur = res.next;
- if (PERFETTO_UNLIKELY(res.parse_res == ParseFieldResult::kSkip))
- continue;
- if (PERFETTO_UNLIKELY(res.parse_res == ParseFieldResult::kAbort))
- break;
-
- PERFETTO_DCHECK(res.parse_res == ParseFieldResult::kOk);
- PERFETTO_DCHECK(res.field.valid());
- auto field_id = res.field.id();
- if constexpr (kSelective) {
- // Selective decoding: only allowlisted in-range ids go to the dense
- // storage; everything else (including ids beyond the in-tree range) is
- // appended, in wire order, to the spill area. |num_fields_| is capped
- // at the mask's extent by SelectiveTypedProtoDecoder, so this also
- // bounds the mask read.
- const bool dense =
- field_id < num_fields_ &&
- (dense_mask[field_id / 64] & (1ULL << (field_id % 64))) != 0;
- if (!dense) {
- // The spill append is open-coded from the field's scalar components:
- // a function taking the whole Field (by value or reference) makes
- // the compiler materialize the packed Field representation on every
- // loop iteration, including for fields that are not spilled.
- if (PERFETTO_UNLIKELY(*spill_size >= *spill_capacity))
- ExpandSpill(spill, spill_capacity, *spill_size, heap_spill);
- (*spill)[(*spill_size)++].initialize(
- field_id, static_cast<uint8_t>(res.field.type()),
- res.field.raw_int_value(), res.field.raw_size());
- continue;
- }
- } else if (PERFETTO_UNLIKELY(field_id >= num_fields_)) {
- // Fields with an id beyond the highest field id known in-tree at compile
- // time are out-of-tree "extension" fields (e.g. carved out of
- // TracePacket's `extensions 1000 to 1999` range). They are intentionally
- // not stored here because fields_ is indexed directly by field id, and
- // extension ids are sparse and potentially very high. Callers that need
- // them should decode selectively and consume them from unknown_fields().
- continue;
- }
-
- // There are two reasons why we might want to expand the heap capacity:
- // 1. We are writing a non-repeated field, which has an id >
- // INITIAL_STACK_CAPACITY. In this case ExpandHeapStorage() ensures to
- // allocate at least (num_fields_ + 1) slots.
- // 2. We are writing a repeated field but ran out of capacity.
- if (PERFETTO_UNLIKELY(field_id >= size_ || size_ >= capacity_))
- ExpandHeapStorage();
-
- PERFETTO_DCHECK(field_id < size_);
- Field* fld = &fields_[field_id];
- if (PERFETTO_LIKELY(!HasField(field_id))) {
- // This is the first time we see this field.
- SetField(field_id);
- *fld = std::move(res.field);
- } else {
- // Repeated field case.
- // In this case we need to:
- // 1. Append the last value of the field to end of the repeated field
- // storage.
- // 2. Replace the default instance at offset |field_id| with the current
- // value. This is because in case of repeated field a call to Get(X) is
- // supposed to return the last value of X, not the first one.
- // This is so that the RepeatedFieldIterator will iterate in the right
- // order, see comments on RepeatedFieldIterator.
- if (num_fields_ > size_) {
- ExpandHeapStorage();
- fld = &fields_[field_id];
- }
-
- PERFETTO_DCHECK(size_ < capacity_);
- fields_[size_++] = *fld;
- *fld = std::move(res.field);
- }
+void LockFreeTaskRunner::PostDelayedTask(std::function<void()> task,
+ uint32_t delay_ms) {
+ if (!RunsTasksOnCurrentThread()) {
+ PostTask([this, task = std::move(task), delay_ms] {
+ this->PostDelayedTask(std::move(task), delay_ms);
+ });
+ return;
}
- read_ptr_ = res.next;
-}
-
-void TypedProtoDecoderBase::ExpandHeapStorage() {
- // When we expand the heap we must ensure that we have at very last capacity
- // to deal with all known fields plus at least one repeated field. We go +2048
- // here based on observations on a large 4GB android trace. This is to avoid
- // trivial re-allocations when dealing with repeated fields of a message that
- // has > INITIAL_STACK_CAPACITY fields.
- const uint32_t min_capacity = num_fields_ + 2048; // Any num >= +1 will do.
- const uint32_t new_capacity = std::max(capacity_ * 2, min_capacity);
- PERFETTO_CHECK(new_capacity > size_ && new_capacity > num_fields_);
- std::unique_ptr<Field[]> new_storage(new Field[new_capacity]);
- static_assert(std::is_trivially_constructible<Field>::value,
- "Field must be trivially constructible");
- static_assert(std::is_trivially_copyable<Field>::value,
- "Field must be trivially copyable");
-
- // There is no need to initialize the slots for known field IDs: reads of
- // them are gated on the presence bitmap. There is also no need to initialize
- // the repeated slots, because they are written linearly with no gaps and are
- // always initialized before incrementing |size_|.
- const uint32_t new_size = std::max(size_, num_fields_);
- memcpy(&new_storage[0], fields_, sizeof(Field) * size_);
-
- heap_storage_ = std::move(new_storage);
- fields_ = &heap_storage_[0];
- capacity_ = new_capacity;
- size_ = new_size;
+ TimeMillis runtime =
+ GetWallTimeMs() + TimeMillis(delay_ms) +
+ TimeMillis(advanced_time_for_testing_.load(std::memory_order_relaxed));
+ delayed_tasks_.insert(
+ DelayedTask{runtime, next_delayed_task_seq_++, std::move(task)});
}
-} // namespace protozero
-// gen_amalgamated begin source: src/protozero/scattered_heap_buffer.cc
-/*
- * 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.
- */
-
-// gen_amalgamated expanded: #include "perfetto/protozero/scattered_heap_buffer.h"
-
-#include <algorithm>
-
-namespace protozero {
-
-ScatteredHeapBuffer::Slice::Slice()
- : buffer_(nullptr), size_(0u), unused_bytes_(0u) {}
-
-ScatteredHeapBuffer::Slice::Slice(size_t size)
- : buffer_(std::unique_ptr<uint8_t[]>(new uint8_t[size])),
- size_(size),
- unused_bytes_(size) {
- PERFETTO_DCHECK(size);
- Clear();
+void LockFreeTaskRunner::AdvanceTimeForTesting(uint32_t ms) {
+ advanced_time_for_testing_.fetch_add(ms);
+ WakeUp();
}
-ScatteredHeapBuffer::Slice::Slice(Slice&& slice) noexcept = default;
-
-ScatteredHeapBuffer::Slice::~Slice() = default;
+void LockFreeTaskRunner::PostFileDescriptorWatches(
+ uint64_t windows_wait_result) {
+ PERFETTO_DCHECK(RunsTasksOnCurrentThread());
+ for (size_t i = 0; i < poll_fds_.size(); i++) {
+#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
+ const PlatformHandle handle = poll_fds_[i];
+ // |windows_wait_result| is the result of WaitForMultipleObjects() call. If
+ // one of the objects was signalled, it will have a value between
+ // [0, poll_fds_.size()].
+ if (i != windows_wait_result &&
+ WaitForSingleObject(handle, 0) != WAIT_OBJECT_0) {
+ continue;
+ }
+#else
+ base::ignore_result(windows_wait_result);
+ const PlatformHandle handle = poll_fds_[i].fd;
+ if (!(poll_fds_[i].revents & (POLLIN | POLLHUP)))
+ continue;
+ poll_fds_[i].revents = 0;
+#endif
-ScatteredHeapBuffer::Slice& ScatteredHeapBuffer::Slice::operator=(Slice&&) =
- default;
+ // The wake-up event is handled inline to avoid an infinite recursion of
+ // posted tasks.
+ if (handle == wakeup_event_.fd()) {
+ wakeup_event_.Clear();
+ continue;
+ }
-void ScatteredHeapBuffer::Slice::Clear() {
- unused_bytes_ = size_;
-#if PERFETTO_DCHECK_IS_ON()
- memset(start(), 0xff, size_);
-#endif // PERFETTO_DCHECK_IS_ON()
-}
+ // Binding to |this| is safe since we are the only object executing the
+ // task.
+ PostTask([this, handle] { this->RunFileDescriptorWatch(handle); });
-ScatteredHeapBuffer::ScatteredHeapBuffer(size_t initial_slice_size_bytes,
- size_t maximum_slice_size_bytes)
- : next_slice_size_(initial_slice_size_bytes),
- maximum_slice_size_(maximum_slice_size_bytes) {
- PERFETTO_DCHECK(next_slice_size_ && maximum_slice_size_);
- PERFETTO_DCHECK(maximum_slice_size_ >= initial_slice_size_bytes);
+ // Flag the task as pending.
+#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
+ // On Windows this is done by marking the WatchTask entry as pending. This
+ // is more expensive than Linux as requires rebuilding the |poll_fds_|
+ // vector on each call. There doesn't seem to be a good alternative though.
+ auto it = watch_tasks_.find(handle);
+ PERFETTO_CHECK(it != watch_tasks_.end());
+ PERFETTO_DCHECK(!it->second.pending);
+ it->second.pending = true;
+#else
+ // On UNIX systems instead, we just make the fd negative while its task is
+ // pending. This makes poll(2) ignore the fd.
+ PERFETTO_DCHECK(poll_fds_[i].fd >= 0);
+ poll_fds_[i].fd = -poll_fds_[i].fd;
+#endif
+ }
}
-ScatteredHeapBuffer::~ScatteredHeapBuffer() = default;
+void LockFreeTaskRunner::RunFileDescriptorWatch(PlatformHandle fd) {
+ PERFETTO_DCHECK(RunsTasksOnCurrentThread());
-protozero::ContiguousMemoryRange ScatteredHeapBuffer::GetNewBuffer() {
- PERFETTO_CHECK(writer_);
- AdjustUsedSizeOfCurrentSlice();
+ std::function<void()> task;
+ auto it = watch_tasks_.find(fd);
+ if (it == watch_tasks_.end())
+ return;
+ WatchTask& watch_task = it->second;
- if (cached_slice_.start()) {
- slices_.push_back(std::move(cached_slice_));
- PERFETTO_DCHECK(!cached_slice_.start());
- } else {
- slices_.emplace_back(next_slice_size_);
- }
- next_slice_size_ = std::min(maximum_slice_size_, next_slice_size_ * 2);
- return slices_.back().GetTotalRange();
-}
+ // Make poll(2) pay attention to the fd again. Since another thread may have
+ // updated this watch we need to refresh the set first.
+ UpdateWatchTasks();
-const std::vector<ScatteredHeapBuffer::Slice>&
-ScatteredHeapBuffer::GetSlices() {
- AdjustUsedSizeOfCurrentSlice();
- return slices_;
+#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
+ // On Windows we manually track the presence of outstanding tasks for the
+ // watch. The UpdateWatchTasksLocked() in the Run() loop will re-add the
+ // task to the |poll_fds_| vector.
+ PERFETTO_DCHECK(watch_task.pending);
+ watch_task.pending = false;
+#else
+ size_t fd_index = watch_task.poll_fd_index;
+ PERFETTO_DCHECK(fd_index < poll_fds_.size());
+ PERFETTO_DCHECK(::abs(poll_fds_[fd_index].fd) == fd);
+ poll_fds_[fd_index].fd = fd;
+#endif
+ task = watch_task.callback;
+ errno = 0;
+ RunTaskWithWatchdogGuard(task);
}
-std::vector<uint8_t> ScatteredHeapBuffer::StitchSlices() {
- size_t stitched_size = 0u;
- const auto& slices = GetSlices();
- for (const auto& slice : slices)
- stitched_size += slice.size() - slice.unused_bytes();
-
- std::vector<uint8_t> buffer;
- buffer.reserve(stitched_size);
- for (const auto& slice : slices) {
- auto used_range = slice.GetUsedRange();
- buffer.insert(buffer.end(), used_range.begin, used_range.end);
+void LockFreeTaskRunner::UpdateWatchTasks() {
+ PERFETTO_DCHECK(RunsTasksOnCurrentThread());
+#if !PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
+ if (!watch_tasks_changed_)
+ return;
+ watch_tasks_changed_ = false;
+#endif
+ poll_fds_.clear();
+ for (auto& it : watch_tasks_) {
+ PlatformHandle handle = it.first;
+ WatchTask& watch_task = it.second;
+#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
+ if (!watch_task.pending)
+ poll_fds_.push_back(handle);
+#else
+ watch_task.poll_fd_index = poll_fds_.size();
+ poll_fds_.push_back({handle, POLLIN | POLLHUP, 0});
+#endif
}
- return buffer;
}
-std::pair<std::unique_ptr<uint8_t[]>, size_t>
-ScatteredHeapBuffer::StitchAsUniquePtr() {
- size_t stitched_size = 0u;
- const auto& slices = GetSlices();
- for (const auto& slice : slices)
- stitched_size += slice.size() - slice.unused_bytes();
+void LockFreeTaskRunner::AddFileDescriptorWatch(PlatformHandle fd,
+ std::function<void()> task) {
+ PERFETTO_DCHECK(PlatformHandleChecker::IsValid(fd));
- std::unique_ptr<uint8_t[]> buffer(new uint8_t[stitched_size]);
- uint8_t* ptr = buffer.get();
- for (const auto& slice : slices) {
- auto used_range = slice.GetUsedRange();
- memcpy(ptr, used_range.begin, used_range.size());
- ptr += used_range.size();
+ if (!RunsTasksOnCurrentThread()) {
+ PostTask([this, task = std::move(task), fd] {
+ this->AddFileDescriptorWatch(fd, std::move(task));
+ });
+ return;
}
- return std::make_pair(std::move(buffer), stitched_size);
-}
-
-std::vector<protozero::ContiguousMemoryRange> ScatteredHeapBuffer::GetRanges() {
- std::vector<protozero::ContiguousMemoryRange> ranges;
- for (const auto& slice : GetSlices())
- ranges.push_back(slice.GetUsedRange());
- return ranges;
-}
-
-void ScatteredHeapBuffer::AdjustUsedSizeOfCurrentSlice() {
- if (!slices_.empty())
- slices_.back().set_unused_bytes(writer_->bytes_available());
+ PERFETTO_DCHECK(!watch_tasks_.count(fd));
+ WatchTask& watch_task = watch_tasks_[fd];
+ watch_task.callback = std::move(task);
+#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
+ watch_task.pending = false;
+#else
+ watch_task.poll_fd_index = SIZE_MAX;
+#endif
+ watch_tasks_changed_ = true;
}
-size_t ScatteredHeapBuffer::GetTotalSize() {
- size_t total_size = 0;
- for (auto& slice : slices_) {
- total_size += slice.size();
+void LockFreeTaskRunner::RemoveFileDescriptorWatch(PlatformHandle fd) {
+ if (!RunsTasksOnCurrentThread()) {
+ PostTask([this, fd] { this->RemoveFileDescriptorWatch(fd); });
+ return;
}
- return total_size;
+
+ PERFETTO_DCHECK(watch_tasks_.count(fd));
+ watch_tasks_.erase(fd);
+ watch_tasks_changed_ = true;
}
-void ScatteredHeapBuffer::Reset() {
- if (slices_.empty())
- return;
- cached_slice_ = std::move(slices_.front());
- cached_slice_.Clear();
- slices_.clear();
+bool LockFreeTaskRunner::RunsTasksOnCurrentThread() const {
+ return run_task_thread_id_ == std::this_thread::get_id();
}
-} // namespace protozero
-// gen_amalgamated begin source: src/protozero/scattered_stream_null_delegate.cc
+} // namespace base
+} // namespace perfetto
+// gen_amalgamated begin source: src/base/thread_task_runner.cc
+// gen_amalgamated begin header: include/perfetto/ext/base/thread_task_runner.h
/*
- * Copyright (C) 2018 The Android Open Source Project
+ * 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.
@@ -15339,30 +15261,81 @@ void ScatteredHeapBuffer::Reset() {
* limitations under the License.
*/
-// gen_amalgamated expanded: #include "perfetto/protozero/scattered_stream_null_delegate.h"
+#ifndef INCLUDE_PERFETTO_EXT_BASE_THREAD_TASK_RUNNER_H_
+#define INCLUDE_PERFETTO_EXT_BASE_THREAD_TASK_RUNNER_H_
-namespace protozero {
+#include <functional>
+#include <thread>
-// An implementation of ScatteredStreamWriter::Delegate which always returns
-// the same piece of memory.
-// This is used when we need to no-op the writers (e.g. during teardown or in
-// case of resource exhaustion), avoiding that the clients have to deal with
-// nullptr checks.
-ScatteredStreamWriterNullDelegate::ScatteredStreamWriterNullDelegate(
- size_t chunk_size)
- : chunk_size_(chunk_size),
- chunk_(std::unique_ptr<uint8_t[]>(new uint8_t[chunk_size_])) {}
+// gen_amalgamated expanded: #include "perfetto/ext/base/lock_free_task_runner.h"
-ScatteredStreamWriterNullDelegate::~ScatteredStreamWriterNullDelegate() {}
+namespace perfetto {
+namespace base {
-ContiguousMemoryRange ScatteredStreamWriterNullDelegate::GetNewBuffer() {
- return {chunk_.get(), chunk_.get() + chunk_size_};
-}
+// A MaybeLockFreeTaskRunner backed by a dedicated task thread. Shuts down the
+// runner and joins the thread upon destruction. Can be moved to transfer
+// ownership.
+//
+// Guarantees that:
+// * the MaybeLockFreeTaskRunner will be constructed and destructed on the task
+// thread.
+// * the task thread will live for the lifetime of the MaybeLockFreeTaskRunner.
+//
+class PERFETTO_EXPORT_COMPONENT ThreadTaskRunner : public TaskRunner {
+ public:
+ static ThreadTaskRunner CreateAndStart(const std::string& name = "") {
+ return ThreadTaskRunner(name);
+ }
-} // namespace protozero
-// gen_amalgamated begin source: src/protozero/scattered_stream_writer.cc
+ ThreadTaskRunner(const ThreadTaskRunner&) = delete;
+ ThreadTaskRunner& operator=(const ThreadTaskRunner&) = delete;
+
+ ThreadTaskRunner(ThreadTaskRunner&&) noexcept;
+ ThreadTaskRunner& operator=(ThreadTaskRunner&&);
+ ~ThreadTaskRunner() override;
+
+ // Executes the given function on the task runner thread and blocks the caller
+ // thread until the function has run.
+ void PostTaskAndWaitForTesting(std::function<void()>);
+
+ // Can be called from another thread to get the CPU time of the thread the
+ // task-runner is executing on.
+ uint64_t GetThreadCPUTimeNsForTesting();
+
+ PlatformThreadId GetThreadIdForTesting();
+
+ // Returns a pointer to the MaybeLockFreeTaskRunner, which is valid for the
+ // lifetime of this ThreadTaskRunner object (unless this object is moved-from,
+ // in which case the pointer remains valid for the lifetime of the new owning
+ // ThreadTaskRunner).
+ //
+ // Warning: do not call Quit() on the returned runner pointer, the termination
+ // should be handled exclusively by this class' destructor.
+ MaybeLockFreeTaskRunner* get() const { return task_runner_; }
+
+ // TaskRunner implementation.
+ // These methods just proxy to the underlying task_runner_.
+ void PostTask(std::function<void()>) override;
+ void PostDelayedTask(std::function<void()>, uint32_t delay_ms) override;
+ void AddFileDescriptorWatch(PlatformHandle, std::function<void()>) override;
+ void RemoveFileDescriptorWatch(PlatformHandle) override;
+ bool RunsTasksOnCurrentThread() const override;
+
+ private:
+ explicit ThreadTaskRunner(const std::string& name);
+ void RunTaskThread(std::function<void(MaybeLockFreeTaskRunner*)> initializer);
+
+ std::thread thread_;
+ std::string name_;
+ MaybeLockFreeTaskRunner* task_runner_ = nullptr;
+};
+
+} // namespace base
+} // namespace perfetto
+
+#endif // INCLUDE_PERFETTO_EXT_BASE_THREAD_TASK_RUNNER_H_
/*
- * Copyright (C) 2017 The Android Open Source Project
+ * 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.
@@ -15377,123 +15350,138 @@ ContiguousMemoryRange ScatteredStreamWriterNullDelegate::GetNewBuffer() {
* limitations under the License.
*/
-// gen_amalgamated expanded: #include "perfetto/protozero/scattered_stream_writer.h"
+// gen_amalgamated expanded: #include "perfetto/base/build_config.h"
-#include <algorithm>
+// gen_amalgamated expanded: #include "perfetto/ext/base/thread_task_runner.h"
+
+#include <condition_variable>
+#include <functional>
+#include <mutex>
+#include <thread>
// gen_amalgamated expanded: #include "perfetto/base/logging.h"
+// gen_amalgamated expanded: #include "perfetto/ext/base/lock_free_task_runner.h"
+// gen_amalgamated expanded: #include "perfetto/ext/base/thread_utils.h"
-namespace protozero {
+#if PERFETTO_BUILDFLAG(PERFETTO_OS_LINUX_BUT_NOT_QNX) || \
+ PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID)
+#include <sys/prctl.h>
+#endif
-ScatteredStreamWriter::Delegate::~Delegate() {}
+namespace perfetto {
+namespace base {
-uint8_t* ScatteredStreamWriter::Delegate::AnnotatePatch(uint8_t* patch_addr) {
- // In most cases, a patch is transparent. The caller can write directly into
- // `to_patch`, because its memory is not going away. TraceWriterImpl, however,
- // requires a more complicated logic, because the chunks might be copied
- // earlier.
- return patch_addr;
+ThreadTaskRunner::ThreadTaskRunner(ThreadTaskRunner&& other) noexcept
+ : thread_(std::move(other.thread_)), task_runner_(other.task_runner_) {
+ other.task_runner_ = nullptr;
}
-ScatteredStreamWriter::ScatteredStreamWriter(Delegate* delegate)
- : delegate_(delegate),
- cur_range_({nullptr, nullptr}),
- write_ptr_(nullptr) {}
+ThreadTaskRunner& ThreadTaskRunner::operator=(ThreadTaskRunner&& other) {
+ this->~ThreadTaskRunner();
+ new (this) ThreadTaskRunner(std::move(other));
+ return *this;
+}
-ScatteredStreamWriter::~ScatteredStreamWriter() {}
+ThreadTaskRunner::~ThreadTaskRunner() {
+ if (task_runner_) {
+ task_runner_->Quit();
-void ScatteredStreamWriter::Reset(ContiguousMemoryRange range) {
- written_previously_ += static_cast<uint64_t>(write_ptr_ - cur_range_.begin);
- cur_range_ = range;
- write_ptr_ = range.begin;
- PERFETTO_DCHECK(!write_ptr_ || write_ptr_ < cur_range_.end);
+ PERFETTO_DCHECK(thread_.joinable());
+ }
+ if (thread_.joinable())
+ thread_.join();
}
-void ScatteredStreamWriter::Extend() {
- Reset(delegate_->GetNewBuffer());
+ThreadTaskRunner::ThreadTaskRunner(const std::string& name) : name_(name) {
+ std::mutex init_lock;
+ std::condition_variable init_cv;
+
+ std::function<void(MaybeLockFreeTaskRunner*)> initializer =
+ [this, &init_lock, &init_cv](MaybeLockFreeTaskRunner* task_runner) {
+ std::lock_guard<std::mutex> lock(init_lock);
+ task_runner_ = task_runner;
+ // Notify while still holding the lock, as init_cv ceases to exist as
+ // soon as the main thread observes a non-null task_runner_, and it can
+ // wake up spuriously (i.e. before the notify if we had unlocked before
+ // notifying).
+ init_cv.notify_one();
+ };
+
+ thread_ = std::thread(&ThreadTaskRunner::RunTaskThread, this,
+ std::move(initializer));
+
+ std::unique_lock<std::mutex> lock(init_lock);
+ init_cv.wait(lock, [this] { return !!task_runner_; });
}
-void ScatteredStreamWriter::WriteBytesSlowPath(const uint8_t* src,
- size_t size) {
- size_t bytes_left = size;
- while (bytes_left > 0) {
- if (write_ptr_ >= cur_range_.end)
- Extend();
- const size_t burst_size = std::min(bytes_available(), bytes_left);
- WriteBytesUnsafe(src, burst_size);
- bytes_left -= burst_size;
- src += burst_size;
+void ThreadTaskRunner::RunTaskThread(
+ std::function<void(MaybeLockFreeTaskRunner*)> initializer) {
+ if (!name_.empty()) {
+ base::MaybeSetThreadName(name_);
}
+
+ MaybeLockFreeTaskRunner task_runner;
+ task_runner.PostTask(std::bind(std::move(initializer), &task_runner));
+ task_runner.Run();
}
-// TODO(primiano): perf optimization: I suspect that at the end this will always
-// be called with |size| == 4, in which case we might just hardcode it.
-uint8_t* ScatteredStreamWriter::ReserveBytes(size_t size) {
- PERFETTO_DCHECK(write_ptr_ <= cur_range_.end);
- if (size > static_cast<size_t>(cur_range_.end - write_ptr_)) {
- // Assume the reservations are always < Delegate::GetNewBuffer().size(),
- // so that one single call to Extend() will definitely give enough headroom.
- Extend();
- PERFETTO_DCHECK(write_ptr_ <= cur_range_.end);
- PERFETTO_DCHECK(size <= static_cast<size_t>(cur_range_.end - write_ptr_));
- }
- uint8_t* begin = write_ptr_;
- write_ptr_ += size;
-#if PERFETTO_DCHECK_IS_ON()
- // In the past, the service had a matching DCHECK in
- // TraceBuffer::TryPatchChunkContents, which was assuming that service and all
- // producers are built with matching DCHECK levels. This turned out to be a
- // source of problems and was removed in b/197340286. This memset is useless
- // these days and is here only to maintain ABI compatibility between producers
- // that use a v20+ SDK and older versions of the service that were built in
- // debug mode. At some point around 2023 it should be safe to remove it.
- // (running a debug version of traced in production seems a bad idea
- // regardless).
- memset(begin, 0, size);
-#endif
- return begin;
+void ThreadTaskRunner::PostTaskAndWaitForTesting(std::function<void()> fn) {
+ std::mutex mutex;
+ std::condition_variable cv;
+
+ std::unique_lock<std::mutex> lock(mutex);
+ bool done = false;
+ task_runner_->PostTask([&mutex, &cv, &done, &fn] {
+ fn();
+
+ std::lock_guard<std::mutex> inner_lock(mutex);
+ done = true;
+ cv.notify_one();
+ });
+ cv.wait(lock, [&done] { return done; });
}
-} // namespace protozero
-// gen_amalgamated begin source: src/protozero/static_buffer.cc
-/*
- * 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.
- */
+uint64_t ThreadTaskRunner::GetThreadCPUTimeNsForTesting() {
+ uint64_t thread_time_ns = 0;
+ PostTaskAndWaitForTesting([&thread_time_ns] {
+ thread_time_ns = static_cast<uint64_t>(base::GetThreadCPUTimeNs().count());
+ });
+ return thread_time_ns;
+}
+PlatformThreadId ThreadTaskRunner::GetThreadIdForTesting() {
+ PlatformThreadId thread_id = static_cast<PlatformThreadId>(-1);
+ PostTaskAndWaitForTesting([&thread_id] { thread_id = GetThreadId(); });
+ return thread_id;
+}
-// gen_amalgamated expanded: #include "perfetto/protozero/static_buffer.h"
+void ThreadTaskRunner::PostTask(std::function<void()> task) {
+ task_runner_->PostTask(std::move(task));
+}
-// gen_amalgamated expanded: #include "perfetto/base/logging.h"
+void ThreadTaskRunner::PostDelayedTask(std::function<void()> task,
+ uint32_t delay_ms) {
+ task_runner_->PostDelayedTask(std::move(task), delay_ms);
+}
-namespace protozero {
+void ThreadTaskRunner::AddFileDescriptorWatch(
+ PlatformHandle handle,
+ std::function<void()> watch_task) {
+ task_runner_->AddFileDescriptorWatch(handle, std::move(watch_task));
+}
-StaticBufferDelegate::~StaticBufferDelegate() = default;
+void ThreadTaskRunner::RemoveFileDescriptorWatch(PlatformHandle handle) {
+ task_runner_->RemoveFileDescriptorWatch(handle);
+}
-ContiguousMemoryRange StaticBufferDelegate::GetNewBuffer() {
- if (get_new_buffer_called_once_) {
- // This is the 2nd time GetNewBuffer is called. The estimate is wrong. We
- // shouldn't try to grow the buffer after the initial call.
- PERFETTO_FATAL("Static buffer too small");
- }
- get_new_buffer_called_once_ = true;
- return range_;
+bool ThreadTaskRunner::RunsTasksOnCurrentThread() const {
+ return task_runner_->RunsTasksOnCurrentThread();
}
-} // namespace protozero
-// gen_amalgamated begin source: src/protozero/virtual_destructors.cc
+} // namespace base
+} // namespace perfetto
+// gen_amalgamated begin source: src/base/unix_task_runner.cc
/*
- * Copyright (C) 2019 The Android Open Source Project
+ * 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.
@@ -15508,2405 +15496,2692 @@ ContiguousMemoryRange StaticBufferDelegate::GetNewBuffer() {
* limitations under the License.
*/
-// gen_amalgamated expanded: #include "perfetto/protozero/cpp_message_obj.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/message_handle.h"
+// gen_amalgamated expanded: #include "perfetto/base/build_config.h"
-namespace protozero {
+// gen_amalgamated expanded: #include "perfetto/ext/base/platform.h"
+// gen_amalgamated expanded: #include "perfetto/ext/base/unix_task_runner.h"
-CppMessageObj::~CppMessageObj() = default;
-MessageFinalizationListener::~MessageFinalizationListener() = default;
+#include <errno.h>
+#include <stdlib.h>
-} // namespace protozero
-// gen_amalgamated begin source: gen/protos/perfetto/protovm/vm_program.gen.cc
-// gen_amalgamated expanded: #include "perfetto/protozero/gen_field_helpers.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/message.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/packed_repeated_fields.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/proto_decoder.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/scattered_heap_buffer.h"
-// DO NOT EDIT. Autogenerated by Perfetto cppgen_plugin
-#if defined(__GNUC__) || defined(__clang__)
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wfloat-equal"
+#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
+#include <windows.h>
+
+#include <synchapi.h>
+#else
+#include <unistd.h>
#endif
-// gen_amalgamated expanded: #include "protos/perfetto/protovm/vm_program.gen.h"
-namespace perfetto {
-namespace protos {
-namespace gen {
+#include <algorithm>
+#include <limits>
-VmOpDel::VmOpDel() = default;
-VmOpDel::~VmOpDel() = default;
-VmOpDel::VmOpDel(const VmOpDel&) = default;
-VmOpDel& VmOpDel::operator=(const VmOpDel&) = default;
-VmOpDel::VmOpDel(VmOpDel&&) noexcept = default;
-VmOpDel& VmOpDel::operator=(VmOpDel&&) = default;
+// gen_amalgamated expanded: #include "perfetto/ext/base/watchdog.h"
-bool VmOpDel::operator==(const VmOpDel& other) const {
- return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_);
+namespace perfetto {
+namespace base {
+
+UnixTaskRunner::UnixTaskRunner() {
+ AddFileDescriptorWatch(event_.fd(), [] {
+ // Not reached -- see PostFileDescriptorWatches().
+ PERFETTO_DFATAL("Should be unreachable.");
+ });
}
-bool VmOpDel::ParseFromArray(const void* raw, size_t size) {
- unknown_fields_.clear();
- bool packed_error = false;
+UnixTaskRunner::~UnixTaskRunner() = default;
- ::protozero::ProtoDecoder dec(raw, size);
- for (auto field = dec.ReadField(); field.valid(); field = dec.ReadField()) {
- if (field.id() < _has_field_.size()) {
- _has_field_.set(field.id());
- }
- switch (field.id()) {
- default:
- field.SerializeAndAppendTo(&unknown_fields_);
- break;
+void UnixTaskRunner::WakeUp() {
+ event_.Notify();
+}
+
+void UnixTaskRunner::Run() {
+ PERFETTO_DCHECK_THREAD(thread_checker_);
+ created_thread_id_.store(GetThreadId(), std::memory_order_relaxed);
+ {
+ std::lock_guard<base::MaybeRtMutex> lock(lock_);
+ quit_ = false;
+ }
+ for (;;) {
+ int poll_timeout_ms;
+ {
+ std::lock_guard<base::MaybeRtMutex> lock(lock_);
+ if (quit_)
+ return;
+ poll_timeout_ms = GetDelayMsToNextTaskLocked();
+ UpdateWatchTasksLocked();
}
+
+#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
+ DWORD timeout =
+ poll_timeout_ms >= 0 ? static_cast<DWORD>(poll_timeout_ms) : INFINITE;
+ DWORD ret =
+ WaitForMultipleObjects(static_cast<DWORD>(poll_fds_.size()),
+ &poll_fds_[0], /*bWaitAll=*/false, timeout);
+ // Unlike poll(2), WaitForMultipleObjects() returns only *one* handle in the
+ // set, even when >1 is signalled. In order to avoid starvation,
+ // PostFileDescriptorWatches() will WaitForSingleObject() each other handle
+ // to ensure fairness. |ret| here is passed just to avoid an extra
+ // WaitForSingleObject() for the one handle that WaitForMultipleObject()
+ // returned.
+ PostFileDescriptorWatches(ret);
+#else
+ platform::BeforeMaybeBlockingSyscall();
+ int ret = PERFETTO_EINTR(poll(
+ &poll_fds_[0], static_cast<nfds_t>(poll_fds_.size()), poll_timeout_ms));
+ platform::AfterMaybeBlockingSyscall();
+ PERFETTO_CHECK(ret >= 0);
+ PostFileDescriptorWatches(0 /*ignored*/);
+#endif
+
+ // To avoid starvation we always interleave all types of tasks -- immediate,
+ // delayed and file descriptor watches.
+ RunImmediateAndDelayedTask();
}
- return !packed_error && !dec.bytes_left();
}
-std::string VmOpDel::SerializeAsString() const {
- ::protozero::internal::gen_helpers::MessageSerializer msg;
- Serialize(msg.get());
- return msg.SerializeAsString();
+void UnixTaskRunner::Quit() {
+ std::lock_guard<base::MaybeRtMutex> lock(lock_);
+ quit_ = true;
+ WakeUp();
}
-std::vector<uint8_t> VmOpDel::SerializeAsArray() const {
- ::protozero::internal::gen_helpers::MessageSerializer msg;
- Serialize(msg.get());
- return msg.SerializeAsArray();
+bool UnixTaskRunner::QuitCalled() {
+ std::lock_guard<base::MaybeRtMutex> lock(lock_);
+ return quit_;
}
-void VmOpDel::Serialize(::protozero::Message* msg) const {
- protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
+bool UnixTaskRunner::IsIdleForTesting() {
+ std::lock_guard<base::MaybeRtMutex> lock(lock_);
+ return immediate_tasks_.empty();
}
-
-VmOpSet::VmOpSet() = default;
-VmOpSet::~VmOpSet() = default;
-VmOpSet::VmOpSet(const VmOpSet&) = default;
-VmOpSet& VmOpSet::operator=(const VmOpSet&) = default;
-VmOpSet::VmOpSet(VmOpSet&&) noexcept = default;
-VmOpSet& VmOpSet::operator=(VmOpSet&&) = default;
-
-bool VmOpSet::operator==(const VmOpSet& other) const {
- return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_);
+void UnixTaskRunner::AdvanceTimeForTesting(uint32_t ms) {
+ std::lock_guard<base::MaybeRtMutex> lock(lock_);
+ advanced_time_for_testing_ += TimeMillis(ms);
}
-bool VmOpSet::ParseFromArray(const void* raw, size_t size) {
- unknown_fields_.clear();
- bool packed_error = false;
+void UnixTaskRunner::UpdateWatchTasksLocked() {
+ PERFETTO_DCHECK_THREAD(thread_checker_);
+#if !PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
+ if (!watch_tasks_changed_)
+ return;
+ watch_tasks_changed_ = false;
+#endif
+ poll_fds_.clear();
+ for (auto& it : watch_tasks_) {
+ PlatformHandle handle = it.first;
+ WatchTask& watch_task = it.second;
+#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
+ if (!watch_task.pending)
+ poll_fds_.push_back(handle);
+#else
+ watch_task.poll_fd_index = poll_fds_.size();
+ poll_fds_.push_back({handle, POLLIN | POLLHUP, 0});
+#endif
+ }
+}
- ::protozero::ProtoDecoder dec(raw, size);
- for (auto field = dec.ReadField(); field.valid(); field = dec.ReadField()) {
- if (field.id() < _has_field_.size()) {
- _has_field_.set(field.id());
+void UnixTaskRunner::RunImmediateAndDelayedTask() {
+ // If locking overhead becomes an issue, add a separate work queue.
+ std::function<void()> immediate_task;
+ std::function<void()> delayed_task;
+ TimeMillis now = GetWallTimeMs();
+ {
+ std::lock_guard<base::MaybeRtMutex> lock(lock_);
+ if (!immediate_tasks_.empty()) {
+ immediate_task = std::move(immediate_tasks_.front());
+ immediate_tasks_.pop_front();
}
- switch (field.id()) {
- default:
- field.SerializeAndAppendTo(&unknown_fields_);
- break;
+ if (!delayed_tasks_.empty()) {
+ auto it = delayed_tasks_.begin();
+ if (now + advanced_time_for_testing_ >= it->first) {
+ delayed_task = std::move(it->second);
+ delayed_tasks_.erase(it);
+ }
}
}
- return !packed_error && !dec.bytes_left();
-}
-
-std::string VmOpSet::SerializeAsString() const {
- ::protozero::internal::gen_helpers::MessageSerializer msg;
- Serialize(msg.get());
- return msg.SerializeAsString();
-}
-std::vector<uint8_t> VmOpSet::SerializeAsArray() const {
- ::protozero::internal::gen_helpers::MessageSerializer msg;
- Serialize(msg.get());
- return msg.SerializeAsArray();
+ errno = 0;
+ if (immediate_task)
+ RunTaskWithWatchdogGuard(immediate_task);
+ errno = 0;
+ if (delayed_task)
+ RunTaskWithWatchdogGuard(delayed_task);
}
-void VmOpSet::Serialize(::protozero::Message* msg) const {
- protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
-}
+void UnixTaskRunner::PostFileDescriptorWatches(uint64_t windows_wait_result) {
+ PERFETTO_DCHECK_THREAD(thread_checker_);
+ for (size_t i = 0; i < poll_fds_.size(); i++) {
+#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
+ const PlatformHandle handle = poll_fds_[i];
+ // |windows_wait_result| is the result of WaitForMultipleObjects() call. If
+ // one of the objects was signalled, it will have a value between
+ // [0, poll_fds_.size()].
+ if (i != windows_wait_result &&
+ WaitForSingleObject(handle, 0) != WAIT_OBJECT_0) {
+ continue;
+ }
+#else
+ base::ignore_result(windows_wait_result);
+ const PlatformHandle handle = poll_fds_[i].fd;
+ if (!(poll_fds_[i].revents & (POLLIN | POLLHUP)))
+ continue;
+ poll_fds_[i].revents = 0;
+#endif
+ // The wake-up event is handled inline to avoid an infinite recursion of
+ // posted tasks.
+ if (handle == event_.fd()) {
+ event_.Clear();
+ continue;
+ }
-VmOpMerge::VmOpMerge() = default;
-VmOpMerge::~VmOpMerge() = default;
-VmOpMerge::VmOpMerge(const VmOpMerge&) = default;
-VmOpMerge& VmOpMerge::operator=(const VmOpMerge&) = default;
-VmOpMerge::VmOpMerge(VmOpMerge&&) noexcept = default;
-VmOpMerge& VmOpMerge::operator=(VmOpMerge&&) = default;
+ // Binding to |this| is safe since we are the only object executing the
+ // task.
+ PostTask(std::bind(&UnixTaskRunner::RunFileDescriptorWatch, this, handle));
-bool VmOpMerge::operator==(const VmOpMerge& other) const {
- return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
- && ::protozero::internal::gen_helpers::EqualsField(skip_submessages_, other.skip_submessages_)
- && ::protozero::internal::gen_helpers::EqualsField(del_if_src_empty_, other.del_if_src_empty_);
+ // Flag the task as pending.
+#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
+ // On Windows this is done by marking the WatchTask entry as pending. This
+ // is more expensive than Linux as requires rebuilding the |poll_fds_|
+ // vector on each call. There doesn't seem to be a good alternative though.
+ auto it = watch_tasks_.find(handle);
+ PERFETTO_CHECK(it != watch_tasks_.end());
+ PERFETTO_DCHECK(!it->second.pending);
+ it->second.pending = true;
+#else
+ // On UNIX systems instead, we just make the fd negative while its task is
+ // pending. This makes poll(2) ignore the fd.
+ PERFETTO_DCHECK(poll_fds_[i].fd >= 0);
+ poll_fds_[i].fd = -poll_fds_[i].fd;
+#endif
+ }
}
-bool VmOpMerge::ParseFromArray(const void* raw, size_t size) {
- unknown_fields_.clear();
- bool packed_error = false;
+void UnixTaskRunner::RunFileDescriptorWatch(PlatformHandle fd) {
+ std::function<void()> task;
+ {
+ std::lock_guard<base::MaybeRtMutex> lock(lock_);
+ auto it = watch_tasks_.find(fd);
+ if (it == watch_tasks_.end())
+ return;
+ WatchTask& watch_task = it->second;
- ::protozero::ProtoDecoder dec(raw, size);
- for (auto field = dec.ReadField(); field.valid(); field = dec.ReadField()) {
- if (field.id() < _has_field_.size()) {
- _has_field_.set(field.id());
- }
- switch (field.id()) {
- case 1 /* skip_submessages */:
- field.get(&skip_submessages_);
- break;
- case 2 /* del_if_src_empty */:
- field.get(&del_if_src_empty_);
- break;
- default:
- field.SerializeAndAppendTo(&unknown_fields_);
- break;
- }
- }
- return !packed_error && !dec.bytes_left();
-}
+ // Make poll(2) pay attention to the fd again. Since another thread may have
+ // updated this watch we need to refresh the set first.
+ UpdateWatchTasksLocked();
-std::string VmOpMerge::SerializeAsString() const {
- ::protozero::internal::gen_helpers::MessageSerializer msg;
- Serialize(msg.get());
- return msg.SerializeAsString();
+#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
+ // On Windows we manually track the presence of outstanding tasks for the
+ // watch. The UpdateWatchTasksLocked() in the Run() loop will re-add the
+ // task to the |poll_fds_| vector.
+ PERFETTO_DCHECK(watch_task.pending);
+ watch_task.pending = false;
+#else
+ size_t fd_index = watch_task.poll_fd_index;
+ PERFETTO_DCHECK(fd_index < poll_fds_.size());
+ PERFETTO_DCHECK(::abs(poll_fds_[fd_index].fd) == fd);
+ poll_fds_[fd_index].fd = fd;
+#endif
+ task = watch_task.callback;
+ }
+ errno = 0;
+ RunTaskWithWatchdogGuard(task);
}
-std::vector<uint8_t> VmOpMerge::SerializeAsArray() const {
- ::protozero::internal::gen_helpers::MessageSerializer msg;
- Serialize(msg.get());
- return msg.SerializeAsArray();
+int UnixTaskRunner::GetDelayMsToNextTaskLocked() const {
+ PERFETTO_DCHECK_THREAD(thread_checker_);
+ if (!immediate_tasks_.empty())
+ return 0;
+ if (!delayed_tasks_.empty()) {
+ TimeMillis diff = delayed_tasks_.begin()->first - GetWallTimeMs() -
+ advanced_time_for_testing_;
+ return std::max(0, static_cast<int>(diff.count()));
+ }
+ return -1;
}
-void VmOpMerge::Serialize(::protozero::Message* msg) const {
- // Field 1: skip_submessages
- if (_has_field_[1]) {
- ::protozero::internal::gen_helpers::SerializeTinyVarInt(1, skip_submessages_, msg);
+void UnixTaskRunner::PostTask(std::function<void()> task) {
+ bool was_empty;
+ {
+ std::lock_guard<base::MaybeRtMutex> lock(lock_);
+ was_empty = immediate_tasks_.empty();
+ immediate_tasks_.push_back(std::move(task));
}
+ if (was_empty)
+ WakeUp();
+}
- // Field 2: del_if_src_empty
- if (_has_field_[2]) {
- ::protozero::internal::gen_helpers::SerializeTinyVarInt(2, del_if_src_empty_, msg);
+void UnixTaskRunner::PostDelayedTask(std::function<void()> task,
+ uint32_t delay_ms) {
+ TimeMillis runtime = GetWallTimeMs() + TimeMillis(delay_ms);
+ {
+ std::lock_guard<base::MaybeRtMutex> lock(lock_);
+ delayed_tasks_.insert(
+ std::make_pair(runtime + advanced_time_for_testing_, std::move(task)));
}
-
- protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
+ WakeUp();
}
-
-VmOpRegLoad::VmOpRegLoad() = default;
-VmOpRegLoad::~VmOpRegLoad() = default;
-VmOpRegLoad::VmOpRegLoad(const VmOpRegLoad&) = default;
-VmOpRegLoad& VmOpRegLoad::operator=(const VmOpRegLoad&) = default;
-VmOpRegLoad::VmOpRegLoad(VmOpRegLoad&&) noexcept = default;
-VmOpRegLoad& VmOpRegLoad::operator=(VmOpRegLoad&&) = default;
-
-bool VmOpRegLoad::operator==(const VmOpRegLoad& other) const {
- return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
- && ::protozero::internal::gen_helpers::EqualsField(cursor_, other.cursor_)
- && ::protozero::internal::gen_helpers::EqualsField(dst_register_, other.dst_register_);
-}
-
-bool VmOpRegLoad::ParseFromArray(const void* raw, size_t size) {
- unknown_fields_.clear();
- bool packed_error = false;
-
- ::protozero::ProtoDecoder dec(raw, size);
- for (auto field = dec.ReadField(); field.valid(); field = dec.ReadField()) {
- if (field.id() < _has_field_.size()) {
- _has_field_.set(field.id());
- }
- switch (field.id()) {
- case 1 /* cursor */:
- field.get(&cursor_);
- break;
- case 2 /* dst_register */:
- field.get(&dst_register_);
- break;
- default:
- field.SerializeAndAppendTo(&unknown_fields_);
- break;
- }
+void UnixTaskRunner::AddFileDescriptorWatch(PlatformHandle fd,
+ std::function<void()> task) {
+ PERFETTO_DCHECK(PlatformHandleChecker::IsValid(fd));
+ {
+ std::lock_guard<base::MaybeRtMutex> lock(lock_);
+ PERFETTO_DCHECK(!watch_tasks_.count(fd));
+ WatchTask& watch_task = watch_tasks_[fd];
+ watch_task.callback = std::move(task);
+#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
+ watch_task.pending = false;
+#else
+ watch_task.poll_fd_index = SIZE_MAX;
+#endif
+ watch_tasks_changed_ = true;
}
- return !packed_error && !dec.bytes_left();
+ WakeUp();
}
-std::string VmOpRegLoad::SerializeAsString() const {
- ::protozero::internal::gen_helpers::MessageSerializer msg;
- Serialize(msg.get());
- return msg.SerializeAsString();
+void UnixTaskRunner::RemoveFileDescriptorWatch(PlatformHandle fd) {
+ PERFETTO_DCHECK(PlatformHandleChecker::IsValid(fd));
+ {
+ std::lock_guard<base::MaybeRtMutex> lock(lock_);
+ PERFETTO_DCHECK(watch_tasks_.count(fd));
+ watch_tasks_.erase(fd);
+ watch_tasks_changed_ = true;
+ }
+ // No need to schedule a wake-up for this.
}
-std::vector<uint8_t> VmOpRegLoad::SerializeAsArray() const {
- ::protozero::internal::gen_helpers::MessageSerializer msg;
- Serialize(msg.get());
- return msg.SerializeAsArray();
+bool UnixTaskRunner::RunsTasksOnCurrentThread() const {
+ return GetThreadId() == created_thread_id_.load(std::memory_order_relaxed);
}
-void VmOpRegLoad::Serialize(::protozero::Message* msg) const {
- // Field 1: cursor
- if (_has_field_[1]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(1, cursor_, msg);
- }
-
- // Field 2: dst_register
- if (_has_field_[2]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(2, dst_register_, msg);
- }
+} // namespace base
+} // namespace perfetto
+// gen_amalgamated begin source: src/base/subprocess.cc
+// gen_amalgamated begin header: include/perfetto/ext/base/subprocess.h
+/*
+ * 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.
+ */
- protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
-}
+#ifndef INCLUDE_PERFETTO_EXT_BASE_SUBPROCESS_H_
+#define INCLUDE_PERFETTO_EXT_BASE_SUBPROCESS_H_
+#include <condition_variable>
+#include <functional>
+#include <initializer_list>
+#include <memory>
+#include <mutex>
+#include <optional>
+#include <string>
+#include <thread>
+#include <vector>
-VmOpSelect::VmOpSelect() = default;
-VmOpSelect::~VmOpSelect() = default;
-VmOpSelect::VmOpSelect(const VmOpSelect&) = default;
-VmOpSelect& VmOpSelect::operator=(const VmOpSelect&) = default;
-VmOpSelect::VmOpSelect(VmOpSelect&&) noexcept = default;
-VmOpSelect& VmOpSelect::operator=(VmOpSelect&&) = default;
+// gen_amalgamated expanded: #include "perfetto/base/build_config.h"
+// gen_amalgamated expanded: #include "perfetto/base/logging.h"
+// gen_amalgamated expanded: #include "perfetto/base/platform_handle.h"
+// gen_amalgamated expanded: #include "perfetto/base/proc_utils.h"
+// gen_amalgamated expanded: #include "perfetto/ext/base/event_fd.h"
+// gen_amalgamated expanded: #include "perfetto/ext/base/pipe.h"
+// gen_amalgamated expanded: #include "perfetto/ext/base/scoped_file.h"
-bool VmOpSelect::operator==(const VmOpSelect& other) const {
- return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
- && ::protozero::internal::gen_helpers::EqualsField(cursor_, other.cursor_)
- && ::protozero::internal::gen_helpers::EqualsField(relative_path_, other.relative_path_)
- && ::protozero::internal::gen_helpers::EqualsField(create_if_not_exist_, other.create_if_not_exist_);
-}
+namespace perfetto {
+namespace base {
-int VmOpSelect::relative_path_size() const { return static_cast<int>(relative_path_.size()); }
-void VmOpSelect::clear_relative_path() { relative_path_.clear(); }
-VmOpSelect_PathComponent* VmOpSelect::add_relative_path() { relative_path_.emplace_back(); return &relative_path_.back(); }
-bool VmOpSelect::ParseFromArray(const void* raw, size_t size) {
- relative_path_.clear();
- unknown_fields_.clear();
- bool packed_error = false;
+// Handles creation and lifecycle management of subprocesses, taking care of
+// all subtleties involved in handling processes on UNIX.
+// This class allows to deal with macro two use-cases:
+// 1) fork() + exec() equivalent: for spawning a brand new process image.
+// This happens when |args.exec_cmd| is not empty.
+// This is safe to use even in a multi-threaded environment.
+// 2) fork(): for spawning a process and running a function.
+// This happens when |args.posix_entrypoint_for_testing| is not empty.
+// This is intended only for tests as it is extremely subtle.
+// This mode must be used with extreme care. Before the entrypoint is
+// invoked all file descriptors other than stdin/out/err and the ones
+// specified in |args.preserve_fds| will be closed, to avoid each process
+// retaining a dupe of other subprocesses pipes. This however means that
+// any non trivial calls (including logging) must be avoided as they might
+// refer to FDs that are now closed. The entrypoint should really be used
+// just to signal a pipe or similar for synchronizing sequencing in tests.
- ::protozero::ProtoDecoder dec(raw, size);
- for (auto field = dec.ReadField(); field.valid(); field = dec.ReadField()) {
- if (field.id() < _has_field_.size()) {
- _has_field_.set(field.id());
- }
- switch (field.id()) {
- case 1 /* cursor */:
- field.get(&cursor_);
- break;
- case 2 /* relative_path */:
- relative_path_.emplace_back();
- relative_path_.back().ParseFromArray(field.data(), field.size());
- break;
- case 3 /* create_if_not_exist */:
- field.get(&create_if_not_exist_);
- break;
- default:
- field.SerializeAndAppendTo(&unknown_fields_);
- break;
- }
- }
- return !packed_error && !dec.bytes_left();
-}
+//
+// This class allows to control stdin/out/err pipe redirection and takes care
+// of keeping all the pipes pumped (stdin) / drained (stdout/err), in a similar
+// fashion of python's subprocess.Communicate()
+// stdin: is always piped and closed once the |args.input| buffer is written.
+// stdout/err can be either:
+// - dup()ed onto the parent process stdout/err.
+// - redirected onto /dev/null.
+// - piped onto a buffer (see output() method). There is only one output
+// buffer in total. If both stdout and stderr are set to kBuffer mode, they
+// will be merged onto the same. There doesn't seem any use case where they
+// are needed distinctly.
+//
+// Some caveats worth mentioning:
+// - It always waitpid()s, to avoid leaving zombies around. If the process is
+// not terminated by the time the destructor is reached, the dtor will
+// send a SIGKILL and wait for the termination.
+// - After fork()-ing it will close all file descriptors, preserving only
+// stdin/out/err and the fds listed in |args.preserve_fds|.
+// - On Linux/Android, the child process will be SIGKILL-ed if the calling
+// thread exists, even if the Subprocess is std::move()-d onto another thread.
+// This happens by virtue PR_SET_PDEATHSIG, which is used to avoid that
+// child processes are leaked in the case of a crash of the parent (frequent
+// in tests). However, the child process might still be leaked if execing
+// a setuid/setgid binary (see man 2 prctl).
+//
+// Usage:
+// base::Subprocess p({"/bin/cat", "-"});
+// (or equivalently:
+// base::Subprocess p;
+// p.args.exec_cmd.push_back("/bin/cat");
+// p.args.exec_cmd.push_back("-");
+// )
+// p.args.stdout_mode = base::Subprocess::kBuffer;
+// p.args.stderr_mode = base::Subprocess::kInherit;
+// p.args.input = "stdin contents";
+// p.Call();
+// (or equivalently:
+// p.Start();
+// p.Wait();
+// )
+// EXPECT_EQ(p.status(), base::Subprocess::kTerminated);
+// EXPECT_EQ(p.returncode(), 0);
+class Subprocess {
+ public:
+ enum Status {
+ kNotStarted = 0, // Before calling Start() or Call().
+ kRunning, // After calling Start(), before Wait().
+ kTerminated, // The subprocess terminated, either successfully or not.
+ // This includes crashes or other signals on UNIX.
+ };
-std::string VmOpSelect::SerializeAsString() const {
- ::protozero::internal::gen_helpers::MessageSerializer msg;
- Serialize(msg.get());
- return msg.SerializeAsString();
-}
+ enum class OutputMode {
+ kInherit = 0, // Inherit's the caller process stdout/stderr.
+ kDevNull, // dup() onto /dev/null.
+ kBuffer, // dup() onto a pipe and move it into the output() buffer.
+ kFd, // dup() onto the passed args.fd.
+ };
-std::vector<uint8_t> VmOpSelect::SerializeAsArray() const {
- ::protozero::internal::gen_helpers::MessageSerializer msg;
- Serialize(msg.get());
- return msg.SerializeAsArray();
-}
+ enum class InputMode {
+ kBuffer = 0, // dup() onto a pipe and write args.input on it.
+ kDevNull, // dup() onto /dev/null.
+ };
-void VmOpSelect::Serialize(::protozero::Message* msg) const {
- // Field 1: cursor
- if (_has_field_[1]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(1, cursor_, msg);
- }
+ // Input arguments for configuring the subprocess behavior.
+ struct Args {
+ Args(std::initializer_list<std::string> _cmd = {}) : exec_cmd(_cmd) {}
+ Args(Args&&) noexcept;
+ Args& operator=(Args&&);
+ // If non-empty this will cause an exec() when Start()/Call() are called.
+ std::vector<std::string> exec_cmd;
- // Field 2: relative_path
- for (auto& it : relative_path_) {
- it.Serialize(msg->BeginNestedMessage<::protozero::Message>(2));
- }
+#if !PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
+ // If non-empty, it changes the argv[0] argument passed to exec. If
+ // unset, argv[0] == exec_cmd[0]. This is to handle cases like:
+ // exec_cmd = {"/proc/self/exec"}, argv0: "my_custom_test_override".
+ std::string posix_argv0_override_for_testing;
- // Field 3: create_if_not_exist
- if (_has_field_[3]) {
- ::protozero::internal::gen_helpers::SerializeTinyVarInt(3, create_if_not_exist_, msg);
- }
+ // If non-empty this will be invoked on the fork()-ed child process, after
+ // stdin/out/err has been redirected and all other file descriptor are
+ // closed. It is valid to specify both |exec_cmd| AND
+ // |posix_entrypoint_for_testing|. In this case the latter will be invoked
+ // just before the exec() call, but after having closed all fds % stdin/o/e.
+ // This is for synchronization barriers in tests.
+ std::function<void()> posix_entrypoint_for_testing;
- protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
-}
+ // When set, will will move the process to the given process group. If set
+ // and zero, it will create a new process group. Effectively this calls
+ // setpgid(0 /*self_pid*/, posix_proc_group_id).
+ // This can be used to avoid that subprocesses receive CTRL-C from the
+ // terminal, while still living in the same session.
+ std::optional<pid_t> posix_proc_group_id{};
+#endif
+ // If non-empty, replaces the environment passed to exec().
+ std::vector<std::string> env;
-VmOpSelect_PathComponent::VmOpSelect_PathComponent() = default;
-VmOpSelect_PathComponent::~VmOpSelect_PathComponent() = default;
-VmOpSelect_PathComponent::VmOpSelect_PathComponent(const VmOpSelect_PathComponent&) = default;
-VmOpSelect_PathComponent& VmOpSelect_PathComponent::operator=(const VmOpSelect_PathComponent&) = default;
-VmOpSelect_PathComponent::VmOpSelect_PathComponent(VmOpSelect_PathComponent&&) noexcept = default;
-VmOpSelect_PathComponent& VmOpSelect_PathComponent::operator=(VmOpSelect_PathComponent&&) = default;
+ // The file descriptors in this list will not be closed.
+ std::vector<int> preserve_fds;
-bool VmOpSelect_PathComponent::operator==(const VmOpSelect_PathComponent& other) const {
- return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
- && ::protozero::internal::gen_helpers::EqualsField(field_id_, other.field_id_)
- && ::protozero::internal::gen_helpers::EqualsField(array_index_, other.array_index_)
- && ::protozero::internal::gen_helpers::EqualsField(map_key_field_id_, other.map_key_field_id_)
- && ::protozero::internal::gen_helpers::EqualsField(is_repeated_, other.is_repeated_)
- && ::protozero::internal::gen_helpers::EqualsField(register_to_match_, other.register_to_match_)
- && ::protozero::internal::gen_helpers::EqualsField(store_foreach_index_into_register_, other.store_foreach_index_into_register_);
-}
+ // The data to push in the child process stdin, if input_mode ==
+ // InputMode::kBuffer.
+ std::string input;
-bool VmOpSelect_PathComponent::ParseFromArray(const void* raw, size_t size) {
- unknown_fields_.clear();
- bool packed_error = false;
+ InputMode stdin_mode = InputMode::kBuffer;
+ OutputMode stdout_mode = OutputMode::kInherit;
+ OutputMode stderr_mode = OutputMode::kInherit;
- ::protozero::ProtoDecoder dec(raw, size);
- for (auto field = dec.ReadField(); field.valid(); field = dec.ReadField()) {
- if (field.id() < _has_field_.size()) {
- _has_field_.set(field.id());
- }
- switch (field.id()) {
- case 1 /* field_id */:
- field.get(&field_id_);
- break;
- case 2 /* array_index */:
- field.get(&array_index_);
- break;
- case 3 /* map_key_field_id */:
- field.get(&map_key_field_id_);
- break;
- case 5 /* is_repeated */:
- field.get(&is_repeated_);
- break;
- case 6 /* register_to_match */:
- field.get(®ister_to_match_);
- break;
- case 7 /* store_foreach_index_into_register */:
- field.get(&store_foreach_index_into_register_);
- break;
- default:
- field.SerializeAndAppendTo(&unknown_fields_);
- break;
- }
- }
- return !packed_error && !dec.bytes_left();
-}
+ base::ScopedPlatformHandle out_fd;
-std::string VmOpSelect_PathComponent::SerializeAsString() const {
- ::protozero::internal::gen_helpers::MessageSerializer msg;
- Serialize(msg.get());
- return msg.SerializeAsString();
-}
+ // Returns " ".join(exec_cmd), quoting arguments.
+ std::string GetCmdString() const;
+ };
-std::vector<uint8_t> VmOpSelect_PathComponent::SerializeAsArray() const {
- ::protozero::internal::gen_helpers::MessageSerializer msg;
- Serialize(msg.get());
- return msg.SerializeAsArray();
-}
+ struct ResourceUsage {
+ uint32_t cpu_utime_ms = 0;
+ uint32_t cpu_stime_ms = 0;
+ uint32_t max_rss_kb = 0;
+ uint32_t min_page_faults = 0;
+ uint32_t maj_page_faults = 0;
+ uint32_t vol_ctx_switch = 0;
+ uint32_t invol_ctx_switch = 0;
-void VmOpSelect_PathComponent::Serialize(::protozero::Message* msg) const {
- // Field 1: field_id
- if (_has_field_[1]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(1, field_id_, msg);
- }
+ uint32_t cpu_time_ms() const { return cpu_utime_ms + cpu_stime_ms; }
+ };
- // Field 2: array_index
- if (_has_field_[2]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(2, array_index_, msg);
- }
+ explicit Subprocess(std::initializer_list<std::string> exec_cmd = {});
+ Subprocess(Subprocess&&) noexcept;
+ Subprocess& operator=(Subprocess&&);
+ ~Subprocess(); // It will KillAndWaitForTermination() if still alive.
- // Field 3: map_key_field_id
- if (_has_field_[3]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(3, map_key_field_id_, msg);
- }
+ // Starts the subprocess but doesn't wait for its termination. The caller
+ // is expected to either call Wait() or Poll() after this call.
+ void Start();
- // Field 5: is_repeated
- if (_has_field_[5]) {
- ::protozero::internal::gen_helpers::SerializeTinyVarInt(5, is_repeated_, msg);
- }
+ // Wait for process termination. Can be called more than once.
+ // Args:
+ // |timeout_ms| = 0: wait indefinitely.
+ // |timeout_ms| > 0: wait for at most |timeout_ms|.
+ // Returns:
+ // True: The process terminated. See status() and returncode().
+ // False: Timeout reached, the process is still running. In this case the
+ // process will be left in the kRunning state.
+ bool Wait(int timeout_ms = 0);
- // Field 6: register_to_match
- if (_has_field_[6]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(6, register_to_match_, msg);
- }
+ // Equivalent of Start() + Wait();
+ // Returns true if the process exited cleanly with return code 0. False in
+ // any othe case.
+ bool Call(int timeout_ms = 0);
- // Field 7: store_foreach_index_into_register
- if (_has_field_[7]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(7, store_foreach_index_into_register_, msg);
- }
+ Status Poll();
- protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
-}
+ // Kills the process (SIGKILL if not specified) but doesn't wait for its
+ // termination.
+ void Kill(int sig_num = 0);
+ // Sends a signal (SIGKILL if not specified) and wait for process termination.
+ void KillAndWaitForTermination(int sig_num = 0);
-VmInstruction::VmInstruction() = default;
-VmInstruction::~VmInstruction() = default;
-VmInstruction::VmInstruction(const VmInstruction&) = default;
-VmInstruction& VmInstruction::operator=(const VmInstruction&) = default;
-VmInstruction::VmInstruction(VmInstruction&&) noexcept = default;
-VmInstruction& VmInstruction::operator=(VmInstruction&&) = default;
+ PlatformProcessId pid() const { return s_->pid; }
-bool VmInstruction::operator==(const VmInstruction& other) const {
- return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
- && ::protozero::internal::gen_helpers::EqualsField(select_, other.select_)
- && ::protozero::internal::gen_helpers::EqualsField(reg_load_, other.reg_load_)
- && ::protozero::internal::gen_helpers::EqualsField(merge_, other.merge_)
- && ::protozero::internal::gen_helpers::EqualsField(set_, other.set_)
- && ::protozero::internal::gen_helpers::EqualsField(del_, other.del_)
- && ::protozero::internal::gen_helpers::EqualsField(abort_level_, other.abort_level_)
- && ::protozero::internal::gen_helpers::EqualsField(nested_instructions_, other.nested_instructions_);
-}
+ // The accessors below are updated only after a call to Poll(), Wait() or
+ // KillAndWaitForTermination().
+ // In most cases you want to call Poll() rather than these accessors.
-int VmInstruction::nested_instructions_size() const { return static_cast<int>(nested_instructions_.size()); }
-void VmInstruction::clear_nested_instructions() { nested_instructions_.clear(); }
-VmInstruction* VmInstruction::add_nested_instructions() { nested_instructions_.emplace_back(); return &nested_instructions_.back(); }
-bool VmInstruction::ParseFromArray(const void* raw, size_t size) {
- nested_instructions_.clear();
- unknown_fields_.clear();
- bool packed_error = false;
+ Status status() const { return s_->status; }
+ int returncode() const { return s_->returncode; }
+ bool timed_out() const { return s_->timed_out; }
- ::protozero::ProtoDecoder dec(raw, size);
- for (auto field = dec.ReadField(); field.valid(); field = dec.ReadField()) {
- if (field.id() < _has_field_.size()) {
- _has_field_.set(field.id());
- }
- switch (field.id()) {
- case 1 /* select */:
- (*select_).ParseFromArray(field.data(), field.size());
- break;
- case 2 /* reg_load */:
- (*reg_load_).ParseFromArray(field.data(), field.size());
- break;
- case 3 /* merge */:
- (*merge_).ParseFromArray(field.data(), field.size());
- break;
- case 4 /* set */:
- (*set_).ParseFromArray(field.data(), field.size());
- break;
- case 5 /* del */:
- (*del_).ParseFromArray(field.data(), field.size());
- break;
- case 6 /* abort_level */:
- field.get(&abort_level_);
- break;
- case 7 /* nested_instructions */:
- nested_instructions_.emplace_back();
- nested_instructions_.back().ParseFromArray(field.data(), field.size());
- break;
- default:
- field.SerializeAndAppendTo(&unknown_fields_);
- break;
- }
- }
- return !packed_error && !dec.bytes_left();
-}
+ // This contains both stdout and stderr (if the corresponding _mode ==
+ // OutputMode::kBuffer). It's non-const so the caller can std::move() it.
+ std::string& output() { return s_->output; }
+ const std::string& output() const { return s_->output; }
-std::string VmInstruction::SerializeAsString() const {
- ::protozero::internal::gen_helpers::MessageSerializer msg;
- Serialize(msg.get());
- return msg.SerializeAsString();
-}
+ const ResourceUsage& posix_rusage() const { return *s_->rusage; }
-std::vector<uint8_t> VmInstruction::SerializeAsArray() const {
- ::protozero::internal::gen_helpers::MessageSerializer msg;
- Serialize(msg.get());
- return msg.SerializeAsArray();
-}
+ Args args;
-void VmInstruction::Serialize(::protozero::Message* msg) const {
- // Field 1: select
- if (_has_field_[1]) {
- (*select_).Serialize(msg->BeginNestedMessage<::protozero::Message>(1));
- }
+ private:
+ // The signal/exit code used when killing the process in case of a timeout.
+ static const int kTimeoutSignal;
- // Field 2: reg_load
- if (_has_field_[2]) {
- (*reg_load_).Serialize(msg->BeginNestedMessage<::protozero::Message>(2));
- }
+ Subprocess(const Subprocess&) = delete;
+ Subprocess& operator=(const Subprocess&) = delete;
- // Field 3: merge
- if (_has_field_[3]) {
- (*merge_).Serialize(msg->BeginNestedMessage<::protozero::Message>(3));
- }
+ // This is to deal robustly with the move operators, without having to
+ // manually maintain member-wise move instructions.
+ struct MovableState {
+ base::Pipe stdin_pipe;
+ base::Pipe stdouterr_pipe;
+ PlatformProcessId pid;
+ Status status = kNotStarted;
+ int returncode = -1;
+ std::string output; // Stdin+stderr. Only when OutputMode::kBuffer.
+ std::unique_ptr<ResourceUsage> rusage{new ResourceUsage()};
+ bool timed_out = false;
+#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
+ std::thread stdouterr_thread;
+ std::thread stdin_thread;
+ ScopedPlatformHandle win_proc_handle;
+ ScopedPlatformHandle win_thread_handle;
- // Field 4: set
- if (_has_field_[4]) {
- (*set_).Serialize(msg->BeginNestedMessage<::protozero::Message>(4));
- }
+ base::EventFd stdouterr_done_event;
+ std::mutex mutex; // Protects locked_outerr_buf and the two pipes.
+ std::string locked_outerr_buf;
+#else
+ base::Pipe exit_status_pipe;
+ size_t input_written = 0;
+ std::thread waitpid_thread;
+#endif
+ };
- // Field 5: del
- if (_has_field_[5]) {
- (*del_).Serialize(msg->BeginNestedMessage<::protozero::Message>(5));
- }
+#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
+ static void StdinThread(MovableState*, const std::string& input);
+ static void StdoutErrThread(MovableState*);
+#else
+ void TryPushStdin();
+ void TryReadStdoutAndErr();
+ void TryReadExitStatus();
+ bool PollInternal(int poll_timeout_ms);
+#endif
- // Field 6: abort_level
- if (_has_field_[6]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(6, abort_level_, msg);
- }
+ std::unique_ptr<MovableState> s_;
+};
- // Field 7: nested_instructions
- for (auto& it : nested_instructions_) {
- it.Serialize(msg->BeginNestedMessage<::protozero::Message>(7));
- }
+} // namespace base
+} // namespace perfetto
- protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
-}
+#endif // INCLUDE_PERFETTO_EXT_BASE_SUBPROCESS_H_
+/*
+ * 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.
+ */
+// gen_amalgamated expanded: #include "perfetto/ext/base/subprocess.h"
-VmProgram::VmProgram() = default;
-VmProgram::~VmProgram() = default;
-VmProgram::VmProgram(const VmProgram&) = default;
-VmProgram& VmProgram::operator=(const VmProgram&) = default;
-VmProgram::VmProgram(VmProgram&&) noexcept = default;
-VmProgram& VmProgram::operator=(VmProgram&&) = default;
+#include <tuple>
-bool VmProgram::operator==(const VmProgram& other) const {
- return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
- && ::protozero::internal::gen_helpers::EqualsField(version_, other.version_)
- && ::protozero::internal::gen_helpers::EqualsField(instructions_, other.instructions_);
-}
+// This file contains only the common bits (ctors / dtors / move operators).
+// The rest lives in subprocess_posix.cc and subprocess_windows.cc.
-int VmProgram::instructions_size() const { return static_cast<int>(instructions_.size()); }
-void VmProgram::clear_instructions() { instructions_.clear(); }
-VmInstruction* VmProgram::add_instructions() { instructions_.emplace_back(); return &instructions_.back(); }
-bool VmProgram::ParseFromArray(const void* raw, size_t size) {
- instructions_.clear();
- unknown_fields_.clear();
- bool packed_error = false;
+namespace perfetto {
+namespace base {
- ::protozero::ProtoDecoder dec(raw, size);
- for (auto field = dec.ReadField(); field.valid(); field = dec.ReadField()) {
- if (field.id() < _has_field_.size()) {
- _has_field_.set(field.id());
- }
- switch (field.id()) {
- case 1 /* version */:
- field.get(&version_);
- break;
- case 2 /* instructions */:
- instructions_.emplace_back();
- instructions_.back().ParseFromArray(field.data(), field.size());
- break;
- default:
- field.SerializeAndAppendTo(&unknown_fields_);
- break;
- }
- }
- return !packed_error && !dec.bytes_left();
+Subprocess::Args::Args(Args&&) noexcept = default;
+Subprocess::Args& Subprocess::Args::operator=(Args&&) = default;
+
+Subprocess::Subprocess(std::initializer_list<std::string> a)
+ : args(a), s_(new MovableState()) {}
+
+Subprocess::Subprocess(Subprocess&& other) noexcept {
+ static_assert(sizeof(Subprocess) ==
+ sizeof(std::tuple<std::unique_ptr<MovableState>, Args>),
+ "base::Subprocess' move ctor needs updating");
+ s_ = std::move(other.s_);
+ args = std::move(other.args);
+
+ // Reset the state of the moved-from object.
+ other.s_.reset(new MovableState());
+ other.~Subprocess();
+ new (&other) Subprocess();
}
-std::string VmProgram::SerializeAsString() const {
- ::protozero::internal::gen_helpers::MessageSerializer msg;
- Serialize(msg.get());
- return msg.SerializeAsString();
+Subprocess& Subprocess::operator=(Subprocess&& other) {
+ this->~Subprocess();
+ new (this) Subprocess(std::move(other));
+ return *this;
}
-std::vector<uint8_t> VmProgram::SerializeAsArray() const {
- ::protozero::internal::gen_helpers::MessageSerializer msg;
- Serialize(msg.get());
- return msg.SerializeAsArray();
+Subprocess::~Subprocess() {
+ if (s_->status == kRunning)
+ KillAndWaitForTermination();
}
-void VmProgram::Serialize(::protozero::Message* msg) const {
- // Field 1: version
- if (_has_field_[1]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(1, version_, msg);
- }
+bool Subprocess::Call(int timeout_ms) {
+ PERFETTO_CHECK(s_->status == kNotStarted);
+ Start();
- // Field 2: instructions
- for (auto& it : instructions_) {
- it.Serialize(msg->BeginNestedMessage<::protozero::Message>(2));
+ if (!Wait(timeout_ms)) {
+ s_->timed_out = true;
+ KillAndWaitForTermination(kTimeoutSignal);
}
+ PERFETTO_DCHECK(s_->status != kRunning);
+ return s_->status == kTerminated && s_->returncode == 0;
+}
- protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
+std::string Subprocess::Args::GetCmdString() const {
+ std::string str;
+ for (size_t i = 0; i < exec_cmd.size(); i++) {
+ str += i > 0 ? " \"" : "";
+ str += exec_cmd[i];
+ str += i > 0 ? "\"" : "";
+ }
+ return str;
}
+} // namespace base
} // namespace perfetto
-} // namespace protos
-} // namespace gen
-#if defined(__GNUC__) || defined(__clang__)
-#pragma GCC diagnostic pop
-#endif
-// gen_amalgamated begin source: gen/protos/perfetto/common/android_energy_consumer_descriptor.gen.cc
-// gen_amalgamated expanded: #include "perfetto/protozero/gen_field_helpers.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/message.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/packed_repeated_fields.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/proto_decoder.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/scattered_heap_buffer.h"
-// DO NOT EDIT. Autogenerated by Perfetto cppgen_plugin
-#if defined(__GNUC__) || defined(__clang__)
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wfloat-equal"
-#endif
-// gen_amalgamated expanded: #include "protos/perfetto/common/android_energy_consumer_descriptor.gen.h"
+// gen_amalgamated begin source: src/base/subprocess_posix.cc
+/*
+ * 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.
+ */
-namespace perfetto {
-namespace protos {
-namespace gen {
+// gen_amalgamated expanded: #include "perfetto/ext/base/subprocess.h"
-AndroidEnergyConsumerDescriptor::AndroidEnergyConsumerDescriptor() = default;
-AndroidEnergyConsumerDescriptor::~AndroidEnergyConsumerDescriptor() = default;
-AndroidEnergyConsumerDescriptor::AndroidEnergyConsumerDescriptor(const AndroidEnergyConsumerDescriptor&) = default;
-AndroidEnergyConsumerDescriptor& AndroidEnergyConsumerDescriptor::operator=(const AndroidEnergyConsumerDescriptor&) = default;
-AndroidEnergyConsumerDescriptor::AndroidEnergyConsumerDescriptor(AndroidEnergyConsumerDescriptor&&) noexcept = default;
-AndroidEnergyConsumerDescriptor& AndroidEnergyConsumerDescriptor::operator=(AndroidEnergyConsumerDescriptor&&) = default;
+// gen_amalgamated expanded: #include "perfetto/base/build_config.h"
-bool AndroidEnergyConsumerDescriptor::operator==(const AndroidEnergyConsumerDescriptor& other) const {
- return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
- && ::protozero::internal::gen_helpers::EqualsField(energy_consumers_, other.energy_consumers_);
-}
+#if PERFETTO_BUILDFLAG(PERFETTO_OS_LINUX) || \
+ PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID) || \
+ PERFETTO_BUILDFLAG(PERFETTO_OS_FREEBSD) || \
+ PERFETTO_BUILDFLAG(PERFETTO_OS_APPLE)
-int AndroidEnergyConsumerDescriptor::energy_consumers_size() const { return static_cast<int>(energy_consumers_.size()); }
-void AndroidEnergyConsumerDescriptor::clear_energy_consumers() { energy_consumers_.clear(); }
-AndroidEnergyConsumer* AndroidEnergyConsumerDescriptor::add_energy_consumers() { energy_consumers_.emplace_back(); return &energy_consumers_.back(); }
-bool AndroidEnergyConsumerDescriptor::ParseFromArray(const void* raw, size_t size) {
- energy_consumers_.clear();
- unknown_fields_.clear();
- bool packed_error = false;
+#include <fcntl.h>
+#include <poll.h>
+#include <signal.h>
+#include <stdio.h>
+#include <sys/resource.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
- ::protozero::ProtoDecoder dec(raw, size);
- for (auto field = dec.ReadField(); field.valid(); field = dec.ReadField()) {
- if (field.id() < _has_field_.size()) {
- _has_field_.set(field.id());
- }
- switch (field.id()) {
- case 1 /* energy_consumers */:
- energy_consumers_.emplace_back();
- energy_consumers_.back().ParseFromArray(field.data(), field.size());
- break;
- default:
- field.SerializeAndAppendTo(&unknown_fields_);
- break;
- }
- }
- return !packed_error && !dec.bytes_left();
-}
+#include <algorithm>
+#include <thread>
+#include <tuple>
-std::string AndroidEnergyConsumerDescriptor::SerializeAsString() const {
- ::protozero::internal::gen_helpers::MessageSerializer msg;
- Serialize(msg.get());
- return msg.SerializeAsString();
-}
+#if PERFETTO_BUILDFLAG(PERFETTO_OS_LINUX_BUT_NOT_QNX) || \
+ PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID)
+#include <sys/prctl.h>
+#endif
-std::vector<uint8_t> AndroidEnergyConsumerDescriptor::SerializeAsArray() const {
- ::protozero::internal::gen_helpers::MessageSerializer msg;
- Serialize(msg.get());
- return msg.SerializeAsArray();
-}
+// gen_amalgamated expanded: #include "perfetto/base/logging.h"
+// gen_amalgamated expanded: #include "perfetto/base/time.h"
+// gen_amalgamated expanded: #include "perfetto/ext/base/utils.h"
-void AndroidEnergyConsumerDescriptor::Serialize(::protozero::Message* msg) const {
- // Field 1: energy_consumers
- for (auto& it : energy_consumers_) {
- it.Serialize(msg->BeginNestedMessage<::protozero::Message>(1));
- }
+// In MacOS this is not defined in any header.
+extern "C" char** environ;
- protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
-}
+namespace perfetto {
+namespace base {
+namespace {
-AndroidEnergyConsumer::AndroidEnergyConsumer() = default;
-AndroidEnergyConsumer::~AndroidEnergyConsumer() = default;
-AndroidEnergyConsumer::AndroidEnergyConsumer(const AndroidEnergyConsumer&) = default;
-AndroidEnergyConsumer& AndroidEnergyConsumer::operator=(const AndroidEnergyConsumer&) = default;
-AndroidEnergyConsumer::AndroidEnergyConsumer(AndroidEnergyConsumer&&) noexcept = default;
-AndroidEnergyConsumer& AndroidEnergyConsumer::operator=(AndroidEnergyConsumer&&) = default;
+struct ChildProcessArgs {
+ Subprocess::Args* create_args;
+ const char* exec_cmd = nullptr;
+ std::vector<char*> argv;
+ std::vector<char*> env;
+ int stdin_pipe_rd = -1;
+ int stdouterr_pipe_wr = -1;
+};
-bool AndroidEnergyConsumer::operator==(const AndroidEnergyConsumer& other) const {
- return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
- && ::protozero::internal::gen_helpers::EqualsField(energy_consumer_id_, other.energy_consumer_id_)
- && ::protozero::internal::gen_helpers::EqualsField(ordinal_, other.ordinal_)
- && ::protozero::internal::gen_helpers::EqualsField(type_, other.type_)
- && ::protozero::internal::gen_helpers::EqualsField(name_, other.name_);
-}
+// Don't add any dynamic allocation in this function. This will be invoked
+// under a fork(), potentially in a state where the allocator lock is held.
+void __attribute__((noreturn)) ChildProcess(ChildProcessArgs* args) {
+#if PERFETTO_BUILDFLAG(PERFETTO_OS_LINUX_BUT_NOT_QNX) || \
+ PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID)
+ // In no case we want a child process to outlive its parent process. This is
+ // relevant for tests, so that a test failure/crash doesn't leave child
+ // processes around that get reparented to init.
+ prctl(PR_SET_PDEATHSIG, SIGKILL);
+#endif
-bool AndroidEnergyConsumer::ParseFromArray(const void* raw, size_t size) {
- unknown_fields_.clear();
- bool packed_error = false;
+ auto die = [args](const char* err) __attribute__((noreturn)) {
+ base::ignore_result(write(args->stdouterr_pipe_wr, err, strlen(err)));
+ base::ignore_result(write(args->stdouterr_pipe_wr, "\n", 1));
+ // From https://www.gnu.org/software/libc/manual/html_node/Exit-Status.html
+ // "In particular, the value 128 is used to indicate failure to execute
+ // another program in a subprocess. This convention is not universally
+ // obeyed, but it is a good idea to follow it in your programs."
+ _exit(128);
+ };
- ::protozero::ProtoDecoder dec(raw, size);
- for (auto field = dec.ReadField(); field.valid(); field = dec.ReadField()) {
- if (field.id() < _has_field_.size()) {
- _has_field_.set(field.id());
- }
- switch (field.id()) {
- case 1 /* energy_consumer_id */:
- field.get(&energy_consumer_id_);
- break;
- case 2 /* ordinal */:
- field.get(&ordinal_);
- break;
- case 3 /* type */:
- ::protozero::internal::gen_helpers::DeserializeString(field, &type_);
- break;
- case 4 /* name */:
- ::protozero::internal::gen_helpers::DeserializeString(field, &name_);
- break;
- default:
- field.SerializeAndAppendTo(&unknown_fields_);
- break;
+ if (args->create_args->posix_proc_group_id.has_value()) {
+ if (setpgid(0 /*self*/, args->create_args->posix_proc_group_id.value())) {
+ die("setpgid() failed");
}
}
- return !packed_error && !dec.bytes_left();
-}
-std::string AndroidEnergyConsumer::SerializeAsString() const {
- ::protozero::internal::gen_helpers::MessageSerializer msg;
- Serialize(msg.get());
- return msg.SerializeAsString();
-}
+ auto set_fd_close_on_exec = [&die](int fd, bool close_on_exec) {
+ int flags = fcntl(fd, F_GETFD, 0);
+ if (flags < 0)
+ die("fcntl(F_GETFD) failed");
+ flags = close_on_exec ? (flags | FD_CLOEXEC) : (flags & ~FD_CLOEXEC);
+ if (fcntl(fd, F_SETFD, flags) < 0)
+ die("fcntl(F_SETFD) failed");
+ };
-std::vector<uint8_t> AndroidEnergyConsumer::SerializeAsArray() const {
- ::protozero::internal::gen_helpers::MessageSerializer msg;
- Serialize(msg.get());
- return msg.SerializeAsArray();
-}
+ if (getppid() == 1)
+ die("terminating because parent process died");
-void AndroidEnergyConsumer::Serialize(::protozero::Message* msg) const {
- // Field 1: energy_consumer_id
- if (_has_field_[1]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(1, energy_consumer_id_, msg);
+ switch (args->create_args->stdin_mode) {
+ case Subprocess::InputMode::kBuffer:
+ if (dup2(args->stdin_pipe_rd, STDIN_FILENO) == -1)
+ die("Failed to dup2(STDIN)");
+ close(args->stdin_pipe_rd);
+ break;
+ case Subprocess::InputMode::kDevNull:
+ if (dup2(open("/dev/null", O_RDONLY), STDIN_FILENO) == -1)
+ die("Failed to dup2(STDOUT)");
+ break;
}
- // Field 2: ordinal
- if (_has_field_[2]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(2, ordinal_, msg);
+ switch (args->create_args->stdout_mode) {
+ case Subprocess::OutputMode::kInherit:
+ break;
+ case Subprocess::OutputMode::kDevNull: {
+ if (dup2(open("/dev/null", O_RDWR), STDOUT_FILENO) == -1)
+ die("Failed to dup2(STDOUT)");
+ break;
+ }
+ case Subprocess::OutputMode::kBuffer:
+ if (dup2(args->stdouterr_pipe_wr, STDOUT_FILENO) == -1)
+ die("Failed to dup2(STDOUT)");
+ break;
+ case Subprocess::OutputMode::kFd:
+ if (dup2(*args->create_args->out_fd, STDOUT_FILENO) == -1)
+ die("Failed to dup2(STDOUT)");
+ break;
}
- // Field 3: type
- if (_has_field_[3]) {
- ::protozero::internal::gen_helpers::SerializeString(3, type_, msg);
+ switch (args->create_args->stderr_mode) {
+ case Subprocess::OutputMode::kInherit:
+ break;
+ case Subprocess::OutputMode::kDevNull: {
+ if (dup2(open("/dev/null", O_RDWR), STDERR_FILENO) == -1)
+ die("Failed to dup2(STDERR)");
+ break;
+ }
+ case Subprocess::OutputMode::kBuffer:
+ if (dup2(args->stdouterr_pipe_wr, STDERR_FILENO) == -1)
+ die("Failed to dup2(STDERR)");
+ break;
+ case Subprocess::OutputMode::kFd:
+ if (dup2(*args->create_args->out_fd, STDERR_FILENO) == -1)
+ die("Failed to dup2(STDERR)");
+ break;
}
- // Field 4: name
- if (_has_field_[4]) {
- ::protozero::internal::gen_helpers::SerializeString(4, name_, msg);
+ // Close all FDs % stdin/out/err and the ones that the client explicitly
+ // asked to retain. The reason for this is twofold:
+ // 1. For exec-only (i.e. entrypoint == empty) cases: it avoids leaking FDs
+ // that didn't get marked as O_CLOEXEC by accident.
+ // 2. In fork() mode (entrypoint not empty) avoids retaining a dup of eventfds
+ // that would prevent the parent process to receive EOFs (tests usually use
+ // pipes as a synchronization mechanism between subprocesses).
+ const auto& preserve_fds = args->create_args->preserve_fds;
+ for (int i = 0; i < 512; i++) {
+ if (i != STDIN_FILENO && i != STDERR_FILENO && i != STDOUT_FILENO &&
+ i != args->stdouterr_pipe_wr &&
+ !std::count(preserve_fds.begin(), preserve_fds.end(), i)) {
+ close(i);
+ }
}
- protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
-}
+ // Clears O_CLOEXEC from stdin/out/err and the |preserve_fds| list. These are
+ // the only FDs that we want to be preserved after the exec().
+ set_fd_close_on_exec(STDIN_FILENO, false);
+ set_fd_close_on_exec(STDOUT_FILENO, false);
+ set_fd_close_on_exec(STDERR_FILENO, false);
-} // namespace perfetto
-} // namespace protos
-} // namespace gen
-#if defined(__GNUC__) || defined(__clang__)
-#pragma GCC diagnostic pop
-#endif
-// gen_amalgamated begin source: gen/protos/perfetto/common/android_log_constants.gen.cc
-// gen_amalgamated expanded: #include "perfetto/protozero/gen_field_helpers.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/message.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/packed_repeated_fields.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/proto_decoder.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/scattered_heap_buffer.h"
-// DO NOT EDIT. Autogenerated by Perfetto cppgen_plugin
-#if defined(__GNUC__) || defined(__clang__)
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wfloat-equal"
-#endif
-// gen_amalgamated expanded: #include "protos/perfetto/common/android_log_constants.gen.h"
+ for (auto fd : preserve_fds)
+ set_fd_close_on_exec(fd, false);
-namespace perfetto {
-namespace protos {
-namespace gen {
-} // namespace perfetto
-} // namespace protos
-} // namespace gen
-#if defined(__GNUC__) || defined(__clang__)
-#pragma GCC diagnostic pop
-#endif
-// gen_amalgamated begin source: gen/protos/perfetto/common/builtin_clock.gen.cc
-// gen_amalgamated expanded: #include "perfetto/protozero/gen_field_helpers.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/message.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/packed_repeated_fields.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/proto_decoder.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/scattered_heap_buffer.h"
-// DO NOT EDIT. Autogenerated by Perfetto cppgen_plugin
-#if defined(__GNUC__) || defined(__clang__)
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wfloat-equal"
-#endif
-// gen_amalgamated expanded: #include "protos/perfetto/common/builtin_clock.gen.h"
+ // If the caller specified a std::function entrypoint, run that first.
+ if (args->create_args->posix_entrypoint_for_testing)
+ args->create_args->posix_entrypoint_for_testing();
-namespace perfetto {
-namespace protos {
-namespace gen {
-} // namespace perfetto
-} // namespace protos
-} // namespace gen
-#if defined(__GNUC__) || defined(__clang__)
-#pragma GCC diagnostic pop
-#endif
-// gen_amalgamated begin source: gen/protos/perfetto/common/commit_data_request.gen.cc
-// gen_amalgamated expanded: #include "perfetto/protozero/gen_field_helpers.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/message.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/packed_repeated_fields.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/proto_decoder.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/scattered_heap_buffer.h"
-// DO NOT EDIT. Autogenerated by Perfetto cppgen_plugin
-#if defined(__GNUC__) || defined(__clang__)
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wfloat-equal"
-#endif
-// gen_amalgamated expanded: #include "protos/perfetto/common/commit_data_request.gen.h"
-
-namespace perfetto {
-namespace protos {
-namespace gen {
+ // If the caller specified only an entrypoint, without any args, exit now.
+ // Otherwise proceed with the exec() below.
+ if (!args->exec_cmd)
+ _exit(0);
-CommitDataRequest::CommitDataRequest() = default;
-CommitDataRequest::~CommitDataRequest() = default;
-CommitDataRequest::CommitDataRequest(const CommitDataRequest&) = default;
-CommitDataRequest& CommitDataRequest::operator=(const CommitDataRequest&) = default;
-CommitDataRequest::CommitDataRequest(CommitDataRequest&&) noexcept = default;
-CommitDataRequest& CommitDataRequest::operator=(CommitDataRequest&&) = default;
+ // If |args[0]| is a path use execv() (which takes a path), otherwise use
+ // exevp(), which uses the shell and follows PATH.
+ if (strchr(args->exec_cmd, '/')) {
+ char** env = args->env.empty() ? environ : args->env.data();
+ execve(args->exec_cmd, args->argv.data(), env);
+ } else {
+ // There is no execvpe() on Mac.
+ if (!args->env.empty())
+ die("A full path is required for |exec_cmd| when setting |env|");
+ execvp(args->exec_cmd, args->argv.data());
+ }
-bool CommitDataRequest::operator==(const CommitDataRequest& other) const {
- return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
- && ::protozero::internal::gen_helpers::EqualsField(chunks_to_move_, other.chunks_to_move_)
- && ::protozero::internal::gen_helpers::EqualsField(chunks_to_patch_, other.chunks_to_patch_)
- && ::protozero::internal::gen_helpers::EqualsField(flush_request_id_, other.flush_request_id_);
+ // Reached only if execv fails.
+ die("execve() failed");
}
-int CommitDataRequest::chunks_to_move_size() const { return static_cast<int>(chunks_to_move_.size()); }
-void CommitDataRequest::clear_chunks_to_move() { chunks_to_move_.clear(); }
-CommitDataRequest_ChunksToMove* CommitDataRequest::add_chunks_to_move() { chunks_to_move_.emplace_back(); return &chunks_to_move_.back(); }
-int CommitDataRequest::chunks_to_patch_size() const { return static_cast<int>(chunks_to_patch_.size()); }
-void CommitDataRequest::clear_chunks_to_patch() { chunks_to_patch_.clear(); }
-CommitDataRequest_ChunkToPatch* CommitDataRequest::add_chunks_to_patch() { chunks_to_patch_.emplace_back(); return &chunks_to_patch_.back(); }
-bool CommitDataRequest::ParseFromArray(const void* raw, size_t size) {
- chunks_to_move_.clear();
- chunks_to_patch_.clear();
- unknown_fields_.clear();
- bool packed_error = false;
+} // namespace
- ::protozero::ProtoDecoder dec(raw, size);
- for (auto field = dec.ReadField(); field.valid(); field = dec.ReadField()) {
- if (field.id() < _has_field_.size()) {
- _has_field_.set(field.id());
- }
- switch (field.id()) {
- case 1 /* chunks_to_move */:
- chunks_to_move_.emplace_back();
- chunks_to_move_.back().ParseFromArray(field.data(), field.size());
- break;
- case 2 /* chunks_to_patch */:
- chunks_to_patch_.emplace_back();
- chunks_to_patch_.back().ParseFromArray(field.data(), field.size());
- break;
- case 3 /* flush_request_id */:
- field.get(&flush_request_id_);
- break;
- default:
- field.SerializeAndAppendTo(&unknown_fields_);
- break;
- }
- }
- return !packed_error && !dec.bytes_left();
-}
+// static
+const int Subprocess::kTimeoutSignal = SIGKILL;
-std::string CommitDataRequest::SerializeAsString() const {
- ::protozero::internal::gen_helpers::MessageSerializer msg;
- Serialize(msg.get());
- return msg.SerializeAsString();
-}
+void Subprocess::Start() {
+ ChildProcessArgs proc_args;
+ proc_args.create_args = &args;
-std::vector<uint8_t> CommitDataRequest::SerializeAsArray() const {
- ::protozero::internal::gen_helpers::MessageSerializer msg;
- Serialize(msg.get());
- return msg.SerializeAsArray();
-}
+ // Setup argv.
+ if (!args.exec_cmd.empty()) {
+ proc_args.exec_cmd = args.exec_cmd[0].c_str();
+ for (const std::string& arg : args.exec_cmd)
+ proc_args.argv.push_back(const_cast<char*>(arg.c_str()));
+ proc_args.argv.push_back(nullptr);
-void CommitDataRequest::Serialize(::protozero::Message* msg) const {
- // Field 1: chunks_to_move
- for (auto& it : chunks_to_move_) {
- it.Serialize(msg->BeginNestedMessage<::protozero::Message>(1));
+ if (!args.posix_argv0_override_for_testing.empty()) {
+ proc_args.argv[0] =
+ const_cast<char*>(args.posix_argv0_override_for_testing.c_str());
+ }
}
- // Field 2: chunks_to_patch
- for (auto& it : chunks_to_patch_) {
- it.Serialize(msg->BeginNestedMessage<::protozero::Message>(2));
+ // Setup env.
+ if (!args.env.empty()) {
+ for (const std::string& str : args.env)
+ proc_args.env.push_back(const_cast<char*>(str.c_str()));
+ proc_args.env.push_back(nullptr);
}
- // Field 3: flush_request_id
- if (_has_field_[3]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(3, flush_request_id_, msg);
+ // Setup the pipes for stdin/err redirection.
+ if (args.stdin_mode == InputMode::kBuffer) {
+ s_->stdin_pipe = base::Pipe::Create(base::Pipe::kWrNonBlock);
+ proc_args.stdin_pipe_rd = *s_->stdin_pipe.rd;
}
+ s_->stdouterr_pipe = base::Pipe::Create(base::Pipe::kRdNonBlock);
+ proc_args.stdouterr_pipe_wr = *s_->stdouterr_pipe.wr;
- protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
-}
-
+ // Spawn the child process that will exec().
+ s_->pid = fork();
+ PERFETTO_CHECK(s_->pid >= 0);
+ if (s_->pid == 0) {
+ // Close the parent-ends of the pipes.
+ s_->stdin_pipe.wr.reset();
+ s_->stdouterr_pipe.rd.reset();
+ ChildProcess(&proc_args);
+ // ChildProcess() doesn't return, not even in case of failures.
+ PERFETTO_FATAL("not reached");
+ }
-CommitDataRequest_ChunkToPatch::CommitDataRequest_ChunkToPatch() = default;
-CommitDataRequest_ChunkToPatch::~CommitDataRequest_ChunkToPatch() = default;
-CommitDataRequest_ChunkToPatch::CommitDataRequest_ChunkToPatch(const CommitDataRequest_ChunkToPatch&) = default;
-CommitDataRequest_ChunkToPatch& CommitDataRequest_ChunkToPatch::operator=(const CommitDataRequest_ChunkToPatch&) = default;
-CommitDataRequest_ChunkToPatch::CommitDataRequest_ChunkToPatch(CommitDataRequest_ChunkToPatch&&) noexcept = default;
-CommitDataRequest_ChunkToPatch& CommitDataRequest_ChunkToPatch::operator=(CommitDataRequest_ChunkToPatch&&) = default;
+ s_->status = kRunning;
-bool CommitDataRequest_ChunkToPatch::operator==(const CommitDataRequest_ChunkToPatch& other) const {
- return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
- && ::protozero::internal::gen_helpers::EqualsField(target_buffer_, other.target_buffer_)
- && ::protozero::internal::gen_helpers::EqualsField(writer_id_, other.writer_id_)
- && ::protozero::internal::gen_helpers::EqualsField(chunk_id_, other.chunk_id_)
- && ::protozero::internal::gen_helpers::EqualsField(patches_, other.patches_)
- && ::protozero::internal::gen_helpers::EqualsField(has_more_patches_, other.has_more_patches_);
-}
+ // Close the child-end of the pipes.
+ // Deliberately NOT closing the s_->stdin_pipe.rd. This is to avoid crashing
+ // with a SIGPIPE if the process exits without consuming its stdin, while
+ // the parent tries to write() on the other end of the stdin pipe.
+ s_->stdouterr_pipe.wr.reset();
+ proc_args.create_args->out_fd.reset();
-int CommitDataRequest_ChunkToPatch::patches_size() const { return static_cast<int>(patches_.size()); }
-void CommitDataRequest_ChunkToPatch::clear_patches() { patches_.clear(); }
-CommitDataRequest_ChunkToPatch_Patch* CommitDataRequest_ChunkToPatch::add_patches() { patches_.emplace_back(); return &patches_.back(); }
-bool CommitDataRequest_ChunkToPatch::ParseFromArray(const void* raw, size_t size) {
- patches_.clear();
- unknown_fields_.clear();
- bool packed_error = false;
+ // Spawn a thread that is blocked on waitpid() and writes the termination
+ // status onto a pipe. The problem here is that waipid() doesn't have a
+ // timeout option and can't be passed to poll(). The alternative would be
+ // using a SIGCHLD handler, but anecdotally signal handlers introduce more
+ // problems than what they solve.
+ s_->exit_status_pipe = base::Pipe::Create(base::Pipe::kRdNonBlock);
- ::protozero::ProtoDecoder dec(raw, size);
- for (auto field = dec.ReadField(); field.valid(); field = dec.ReadField()) {
- if (field.id() < _has_field_.size()) {
- _has_field_.set(field.id());
- }
- switch (field.id()) {
- case 1 /* target_buffer */:
- field.get(&target_buffer_);
- break;
- case 2 /* writer_id */:
- field.get(&writer_id_);
- break;
- case 3 /* chunk_id */:
- field.get(&chunk_id_);
- break;
- case 4 /* patches */:
- patches_.emplace_back();
- patches_.back().ParseFromArray(field.data(), field.size());
- break;
- case 5 /* has_more_patches */:
- field.get(&has_more_patches_);
- break;
- default:
- field.SerializeAndAppendTo(&unknown_fields_);
- break;
- }
- }
- return !packed_error && !dec.bytes_left();
-}
+ // Both ends of the pipe are closed after the thread.join().
+ int pid = s_->pid;
+ int exit_status_pipe_wr = s_->exit_status_pipe.wr.release();
+ auto* rusage = s_->rusage.get();
+ s_->waitpid_thread = std::thread([pid, exit_status_pipe_wr, rusage] {
+ int pid_stat = -1;
+ struct rusage usg{};
+ int wait_res = PERFETTO_EINTR(wait4(pid, &pid_stat, 0, &usg));
+ PERFETTO_CHECK(wait_res == pid);
-std::string CommitDataRequest_ChunkToPatch::SerializeAsString() const {
- ::protozero::internal::gen_helpers::MessageSerializer msg;
- Serialize(msg.get());
- return msg.SerializeAsString();
-}
+ auto tv_to_ms = [](const struct timeval& tv) {
+ return static_cast<uint32_t>(tv.tv_sec * 1000 + tv.tv_usec / 1000);
+ };
+ rusage->cpu_utime_ms = tv_to_ms(usg.ru_utime);
+ rusage->cpu_stime_ms = tv_to_ms(usg.ru_stime);
+ rusage->max_rss_kb = static_cast<uint32_t>(usg.ru_maxrss) / 1000;
+ rusage->min_page_faults = static_cast<uint32_t>(usg.ru_minflt);
+ rusage->maj_page_faults = static_cast<uint32_t>(usg.ru_majflt);
+ rusage->vol_ctx_switch = static_cast<uint32_t>(usg.ru_nvcsw);
+ rusage->invol_ctx_switch = static_cast<uint32_t>(usg.ru_nivcsw);
-std::vector<uint8_t> CommitDataRequest_ChunkToPatch::SerializeAsArray() const {
- ::protozero::internal::gen_helpers::MessageSerializer msg;
- Serialize(msg.get());
- return msg.SerializeAsArray();
+ base::ignore_result(PERFETTO_EINTR(
+ write(exit_status_pipe_wr, &pid_stat, sizeof(pid_stat))));
+ PERFETTO_CHECK(close(exit_status_pipe_wr) == 0 || errno == EINTR);
+ });
}
-void CommitDataRequest_ChunkToPatch::Serialize(::protozero::Message* msg) const {
- // Field 1: target_buffer
- if (_has_field_[1]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(1, target_buffer_, msg);
- }
-
- // Field 2: writer_id
- if (_has_field_[2]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(2, writer_id_, msg);
+Subprocess::Status Subprocess::Poll() {
+ if (s_->status != kRunning)
+ return s_->status; // Nothing to poll.
+ while (PollInternal(0 /* don't block*/)) {
}
+ return s_->status;
+}
- // Field 3: chunk_id
- if (_has_field_[3]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(3, chunk_id_, msg);
+// |timeout_ms| semantic:
+// -1: Block indefinitely.
+// 0: Don't block, return immediately.
+// >0: Block for at most X ms.
+// Returns:
+// True: Read at least one fd (so there might be more queued).
+// False: if all fds reached quiescent (no data to read/write).
+bool Subprocess::PollInternal(int poll_timeout_ms) {
+ struct pollfd fds[3]{};
+ size_t num_fds = 0;
+ if (s_->exit_status_pipe.rd) {
+ fds[num_fds].fd = *s_->exit_status_pipe.rd;
+ fds[num_fds].events = POLLIN;
+ num_fds++;
}
-
- // Field 4: patches
- for (auto& it : patches_) {
- it.Serialize(msg->BeginNestedMessage<::protozero::Message>(4));
+ if (s_->stdouterr_pipe.rd) {
+ fds[num_fds].fd = *s_->stdouterr_pipe.rd;
+ fds[num_fds].events = POLLIN;
+ num_fds++;
}
-
- // Field 5: has_more_patches
- if (_has_field_[5]) {
- ::protozero::internal::gen_helpers::SerializeTinyVarInt(5, has_more_patches_, msg);
+ if (s_->stdin_pipe.wr) {
+ fds[num_fds].fd = *s_->stdin_pipe.wr;
+ fds[num_fds].events = POLLOUT;
+ num_fds++;
}
- protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
-}
+ if (num_fds == 0)
+ return false;
+ auto nfds = static_cast<nfds_t>(num_fds);
+ int poll_res = PERFETTO_EINTR(poll(fds, nfds, poll_timeout_ms));
+ PERFETTO_CHECK(poll_res >= 0);
-CommitDataRequest_ChunkToPatch_Patch::CommitDataRequest_ChunkToPatch_Patch() = default;
-CommitDataRequest_ChunkToPatch_Patch::~CommitDataRequest_ChunkToPatch_Patch() = default;
-CommitDataRequest_ChunkToPatch_Patch::CommitDataRequest_ChunkToPatch_Patch(const CommitDataRequest_ChunkToPatch_Patch&) = default;
-CommitDataRequest_ChunkToPatch_Patch& CommitDataRequest_ChunkToPatch_Patch::operator=(const CommitDataRequest_ChunkToPatch_Patch&) = default;
-CommitDataRequest_ChunkToPatch_Patch::CommitDataRequest_ChunkToPatch_Patch(CommitDataRequest_ChunkToPatch_Patch&&) noexcept = default;
-CommitDataRequest_ChunkToPatch_Patch& CommitDataRequest_ChunkToPatch_Patch::operator=(CommitDataRequest_ChunkToPatch_Patch&&) = default;
+ TryReadStdoutAndErr();
+ TryPushStdin();
+ TryReadExitStatus();
-bool CommitDataRequest_ChunkToPatch_Patch::operator==(const CommitDataRequest_ChunkToPatch_Patch& other) const {
- return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
- && ::protozero::internal::gen_helpers::EqualsField(offset_, other.offset_)
- && ::protozero::internal::gen_helpers::EqualsField(data_, other.data_);
+ return poll_res > 0;
}
-bool CommitDataRequest_ChunkToPatch_Patch::ParseFromArray(const void* raw, size_t size) {
- unknown_fields_.clear();
- bool packed_error = false;
+bool Subprocess::Wait(int timeout_ms) {
+ PERFETTO_CHECK(s_->status != kNotStarted);
- ::protozero::ProtoDecoder dec(raw, size);
- for (auto field = dec.ReadField(); field.valid(); field = dec.ReadField()) {
- if (field.id() < _has_field_.size()) {
- _has_field_.set(field.id());
- }
- switch (field.id()) {
- case 1 /* offset */:
- field.get(&offset_);
- break;
- case 2 /* data */:
- field.get(&data_);
- break;
- default:
- field.SerializeAndAppendTo(&unknown_fields_);
- break;
+ // Break out of the loop only after both conditions are satisfied:
+ // - All stdout/stderr data has been read (if kBuffer).
+ // - The process exited.
+ // Note that the two events can happen arbitrary order. After the process
+ // exits, there might be still data in the pipe buffer, which we want to
+ // read fully.
+ //
+ // Instead, don't wait on the stdin to be fully written. The child process
+ // might exit prematurely (or crash). If that happens, we can end up in a
+ // state where the write(stdin_pipe_.wr) will never unblock.
+
+ const int64_t t_start = base::GetWallTimeMs().count();
+ while (s_->exit_status_pipe.rd || s_->stdouterr_pipe.rd) {
+ int poll_timeout_ms = -1; // Block until a FD is ready.
+ if (timeout_ms > 0) {
+ const int64_t now = GetWallTimeMs().count();
+ poll_timeout_ms = timeout_ms - static_cast<int>(now - t_start);
+ if (poll_timeout_ms <= 0)
+ return false;
}
- }
- return !packed_error && !dec.bytes_left();
+ PollInternal(poll_timeout_ms);
+ } // while(...)
+ return true;
}
-std::string CommitDataRequest_ChunkToPatch_Patch::SerializeAsString() const {
- ::protozero::internal::gen_helpers::MessageSerializer msg;
- Serialize(msg.get());
- return msg.SerializeAsString();
-}
+void Subprocess::TryReadExitStatus() {
+ if (!s_->exit_status_pipe.rd)
+ return;
-std::vector<uint8_t> CommitDataRequest_ChunkToPatch_Patch::SerializeAsArray() const {
- ::protozero::internal::gen_helpers::MessageSerializer msg;
- Serialize(msg.get());
- return msg.SerializeAsArray();
-}
+ int pid_stat = -1;
+ int64_t rsize = PERFETTO_EINTR(
+ read(*s_->exit_status_pipe.rd, &pid_stat, sizeof(pid_stat)));
+ if (rsize < 0 && errno == EAGAIN)
+ return;
-void CommitDataRequest_ChunkToPatch_Patch::Serialize(::protozero::Message* msg) const {
- // Field 1: offset
- if (_has_field_[1]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(1, offset_, msg);
+ if (rsize > 0) {
+ PERFETTO_CHECK(rsize == sizeof(pid_stat));
+ } else if (rsize < 0) {
+ PERFETTO_PLOG("Subprocess read(s_->exit_status_pipe) failed");
}
+ s_->waitpid_thread.join();
+ s_->exit_status_pipe.rd.reset();
- // Field 2: data
- if (_has_field_[2]) {
- ::protozero::internal::gen_helpers::SerializeString(2, data_, msg);
+ s_->status = kTerminated;
+ if (WIFEXITED(pid_stat)) {
+ s_->returncode = WEXITSTATUS(pid_stat);
+ } else if (WIFSIGNALED(pid_stat)) {
+ s_->returncode = 128 + WTERMSIG(pid_stat); // Follow bash convention.
+ } else {
+ PERFETTO_FATAL("waitpid() returned an unexpected value (%d)", pid_stat);
}
-
- protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
}
+// If the stidn pipe is still open, push input data and close it at the end.
+void Subprocess::TryPushStdin() {
+ if (!s_->stdin_pipe.wr)
+ return;
-CommitDataRequest_ChunksToMove::CommitDataRequest_ChunksToMove() = default;
-CommitDataRequest_ChunksToMove::~CommitDataRequest_ChunksToMove() = default;
-CommitDataRequest_ChunksToMove::CommitDataRequest_ChunksToMove(const CommitDataRequest_ChunksToMove&) = default;
-CommitDataRequest_ChunksToMove& CommitDataRequest_ChunksToMove::operator=(const CommitDataRequest_ChunksToMove&) = default;
-CommitDataRequest_ChunksToMove::CommitDataRequest_ChunksToMove(CommitDataRequest_ChunksToMove&&) noexcept = default;
-CommitDataRequest_ChunksToMove& CommitDataRequest_ChunksToMove::operator=(CommitDataRequest_ChunksToMove&&) = default;
+ PERFETTO_DCHECK(args.input.empty() || s_->input_written < args.input.size());
+ if (!args.input.empty()) {
+ int64_t wsize =
+ PERFETTO_EINTR(write(*s_->stdin_pipe.wr, &args.input[s_->input_written],
+ args.input.size() - s_->input_written));
+ if (wsize < 0 && errno == EAGAIN)
+ return;
-bool CommitDataRequest_ChunksToMove::operator==(const CommitDataRequest_ChunksToMove& other) const {
- return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
- && ::protozero::internal::gen_helpers::EqualsField(page_, other.page_)
- && ::protozero::internal::gen_helpers::EqualsField(chunk_, other.chunk_)
- && ::protozero::internal::gen_helpers::EqualsField(target_buffer_, other.target_buffer_)
- && ::protozero::internal::gen_helpers::EqualsField(data_, other.data_)
- && ::protozero::internal::gen_helpers::EqualsField(chunk_incomplete_, other.chunk_incomplete_);
+ if (wsize >= 0) {
+ // Whether write() can return 0 is one of the greatest mysteries of UNIX.
+ // Just ignore it.
+ s_->input_written += static_cast<size_t>(wsize);
+ } else {
+ PERFETTO_PLOG("Subprocess write(stdin) failed");
+ s_->stdin_pipe.wr.reset();
+ }
+ }
+ PERFETTO_DCHECK(s_->input_written <= args.input.size());
+ if (s_->input_written == args.input.size())
+ s_->stdin_pipe.wr.reset(); // Close stdin.
}
-bool CommitDataRequest_ChunksToMove::ParseFromArray(const void* raw, size_t size) {
- unknown_fields_.clear();
- bool packed_error = false;
+void Subprocess::TryReadStdoutAndErr() {
+ if (!s_->stdouterr_pipe.rd)
+ return;
+ char buf[4096];
+ int64_t rsize =
+ PERFETTO_EINTR(read(*s_->stdouterr_pipe.rd, buf, sizeof(buf)));
+ if (rsize < 0 && errno == EAGAIN)
+ return;
- ::protozero::ProtoDecoder dec(raw, size);
- for (auto field = dec.ReadField(); field.valid(); field = dec.ReadField()) {
- if (field.id() < _has_field_.size()) {
- _has_field_.set(field.id());
- }
- switch (field.id()) {
- case 1 /* page */:
- field.get(&page_);
- break;
- case 2 /* chunk */:
- field.get(&chunk_);
- break;
- case 3 /* target_buffer */:
- field.get(&target_buffer_);
- break;
- case 4 /* data */:
- field.get(&data_);
- break;
- case 5 /* chunk_incomplete */:
- field.get(&chunk_incomplete_);
- break;
- default:
- field.SerializeAndAppendTo(&unknown_fields_);
- break;
- }
+ if (rsize > 0) {
+ s_->output.append(buf, static_cast<size_t>(rsize));
+ } else if (rsize == 0 /* EOF */) {
+ s_->stdouterr_pipe.rd.reset();
+ } else {
+ PERFETTO_PLOG("Subprocess read(stdout/err) failed");
+ s_->stdouterr_pipe.rd.reset();
}
- return !packed_error && !dec.bytes_left();
}
-std::string CommitDataRequest_ChunksToMove::SerializeAsString() const {
- ::protozero::internal::gen_helpers::MessageSerializer msg;
- Serialize(msg.get());
- return msg.SerializeAsString();
+void Subprocess::Kill(int sig_num) {
+ kill(s_->pid, sig_num ? sig_num : SIGKILL);
}
-std::vector<uint8_t> CommitDataRequest_ChunksToMove::SerializeAsArray() const {
- ::protozero::internal::gen_helpers::MessageSerializer msg;
- Serialize(msg.get());
- return msg.SerializeAsArray();
+void Subprocess::KillAndWaitForTermination(int sig_num) {
+ Kill(sig_num);
+ Wait();
+ // TryReadExitStatus must have joined the thread.
+ PERFETTO_DCHECK(!s_->waitpid_thread.joinable());
}
-void CommitDataRequest_ChunksToMove::Serialize(::protozero::Message* msg) const {
- // Field 1: page
- if (_has_field_[1]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(1, page_, msg);
- }
+} // namespace base
+} // namespace perfetto
- // Field 2: chunk
- if (_has_field_[2]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(2, chunk_, msg);
- }
+#endif // PERFETTO_OS_LINUX || PERFETTO_OS_ANDROID || PERFETTO_OS_APPLE
+// gen_amalgamated begin source: src/base/subprocess_windows.cc
+/*
+ * 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.
+ */
- // Field 3: target_buffer
- if (_has_field_[3]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(3, target_buffer_, msg);
- }
+// gen_amalgamated expanded: #include "perfetto/ext/base/subprocess.h"
- // Field 4: data
- if (_has_field_[4]) {
- ::protozero::internal::gen_helpers::SerializeString(4, data_, msg);
- }
+// gen_amalgamated expanded: #include "perfetto/base/build_config.h"
- // Field 5: chunk_incomplete
- if (_has_field_[5]) {
- ::protozero::internal::gen_helpers::SerializeTinyVarInt(5, chunk_incomplete_, msg);
- }
+#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
- protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
-}
+#include <stdio.h>
-} // namespace perfetto
-} // namespace protos
-} // namespace gen
-#if defined(__GNUC__) || defined(__clang__)
-#pragma GCC diagnostic pop
-#endif
-// gen_amalgamated begin source: gen/protos/perfetto/common/data_source_descriptor.gen.cc
-// gen_amalgamated expanded: #include "perfetto/protozero/gen_field_helpers.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/message.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/packed_repeated_fields.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/proto_decoder.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/scattered_heap_buffer.h"
-// DO NOT EDIT. Autogenerated by Perfetto cppgen_plugin
-#if defined(__GNUC__) || defined(__clang__)
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wfloat-equal"
-#endif
-// gen_amalgamated expanded: #include "protos/perfetto/common/data_source_descriptor.gen.h"
-// gen_amalgamated expanded: #include "protos/perfetto/protovm/vm_program.gen.h"
+#include <algorithm>
+#include <mutex>
+#include <tuple>
-namespace perfetto {
-namespace protos {
-namespace gen {
+#include <windows.h>
-DataSourceDescriptor::DataSourceDescriptor() = default;
-DataSourceDescriptor::~DataSourceDescriptor() = default;
-DataSourceDescriptor::DataSourceDescriptor(const DataSourceDescriptor&) = default;
-DataSourceDescriptor& DataSourceDescriptor::operator=(const DataSourceDescriptor&) = default;
-DataSourceDescriptor::DataSourceDescriptor(DataSourceDescriptor&&) noexcept = default;
-DataSourceDescriptor& DataSourceDescriptor::operator=(DataSourceDescriptor&&) = default;
+// gen_amalgamated expanded: #include "perfetto/base/logging.h"
+// gen_amalgamated expanded: #include "perfetto/base/time.h"
+// gen_amalgamated expanded: #include "perfetto/ext/base/pipe.h"
+// gen_amalgamated expanded: #include "perfetto/ext/base/utils.h"
-bool DataSourceDescriptor::operator==(const DataSourceDescriptor& other) const {
- return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
- && ::protozero::internal::gen_helpers::EqualsField(name_, other.name_)
- && ::protozero::internal::gen_helpers::EqualsField(id_, other.id_)
- && ::protozero::internal::gen_helpers::EqualsField(will_notify_on_stop_, other.will_notify_on_stop_)
- && ::protozero::internal::gen_helpers::EqualsField(will_notify_on_start_, other.will_notify_on_start_)
- && ::protozero::internal::gen_helpers::EqualsField(handles_incremental_state_clear_, other.handles_incremental_state_clear_)
- && ::protozero::internal::gen_helpers::EqualsField(no_flush_, other.no_flush_)
- && ::protozero::internal::gen_helpers::EqualsField(protovm_program_, other.protovm_program_)
- && ::protozero::internal::gen_helpers::EqualsField(gpu_counter_descriptor_, other.gpu_counter_descriptor_)
- && ::protozero::internal::gen_helpers::EqualsField(track_event_descriptor_, other.track_event_descriptor_)
- && ::protozero::internal::gen_helpers::EqualsField(ftrace_descriptor_, other.ftrace_descriptor_);
-}
+namespace perfetto {
+namespace base {
-bool DataSourceDescriptor::ParseFromArray(const void* raw, size_t size) {
- unknown_fields_.clear();
- bool packed_error = false;
+// static
+const int Subprocess::kTimeoutSignal = static_cast<int>(STATUS_TIMEOUT);
- ::protozero::ProtoDecoder dec(raw, size);
- for (auto field = dec.ReadField(); field.valid(); field = dec.ReadField()) {
- if (field.id() < _has_field_.size()) {
- _has_field_.set(field.id());
- }
- switch (field.id()) {
- case 1 /* name */:
- ::protozero::internal::gen_helpers::DeserializeString(field, &name_);
- break;
- case 7 /* id */:
- field.get(&id_);
- break;
- case 2 /* will_notify_on_stop */:
- field.get(&will_notify_on_stop_);
- break;
- case 3 /* will_notify_on_start */:
- field.get(&will_notify_on_start_);
- break;
- case 4 /* handles_incremental_state_clear */:
- field.get(&handles_incremental_state_clear_);
- break;
- case 9 /* no_flush */:
- field.get(&no_flush_);
- break;
- case 10 /* protovm_program */:
- (*protovm_program_).ParseFromArray(field.data(), field.size());
- break;
- case 5 /* gpu_counter_descriptor */:
- ::protozero::internal::gen_helpers::DeserializeString(field, &gpu_counter_descriptor_);
- break;
- case 6 /* track_event_descriptor */:
- ::protozero::internal::gen_helpers::DeserializeString(field, &track_event_descriptor_);
- break;
- case 8 /* ftrace_descriptor */:
- ::protozero::internal::gen_helpers::DeserializeString(field, &ftrace_descriptor_);
- break;
- default:
- field.SerializeAndAppendTo(&unknown_fields_);
- break;
- }
+void Subprocess::Start() {
+ if (args.exec_cmd.empty()) {
+ PERFETTO_ELOG("Subprocess.exec_cmd cannot be empty on Windows");
+ return;
}
- return !packed_error && !dec.bytes_left();
-}
-
-std::string DataSourceDescriptor::SerializeAsString() const {
- ::protozero::internal::gen_helpers::MessageSerializer msg;
- Serialize(msg.get());
- return msg.SerializeAsString();
-}
-
-std::vector<uint8_t> DataSourceDescriptor::SerializeAsArray() const {
- ::protozero::internal::gen_helpers::MessageSerializer msg;
- Serialize(msg.get());
- return msg.SerializeAsArray();
-}
-void DataSourceDescriptor::Serialize(::protozero::Message* msg) const {
- // Field 1: name
- if (_has_field_[1]) {
- ::protozero::internal::gen_helpers::SerializeString(1, name_, msg);
+ // Quote arguments but only when ambiguous. When quoting, CreateProcess()
+ // assumes that the command is an absolute path and does not search in the
+ // %PATH%. If non quoted, instead, CreateProcess() tries both. This is to
+ // allow Subprocess("cmd.exe", "/c", "shell command").
+ std::string cmd;
+ for (const auto& part : args.exec_cmd) {
+ if (part.find(" ") != std::string::npos) {
+ cmd += "\"" + part + "\" ";
+ } else {
+ cmd += part + " ";
+ }
}
+ // Remove trailing space.
+ if (!cmd.empty())
+ cmd.resize(cmd.size() - 1);
- // Field 7: id
- if (_has_field_[7]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(7, id_, msg);
+ if (args.stdin_mode == InputMode::kBuffer) {
+ s_->stdin_pipe = Pipe::Create();
+ // Allow the child process to inherit the other end of the pipe.
+ PERFETTO_CHECK(
+ ::SetHandleInformation(*s_->stdin_pipe.rd, HANDLE_FLAG_INHERIT, 1));
}
- // Field 2: will_notify_on_stop
- if (_has_field_[2]) {
- ::protozero::internal::gen_helpers::SerializeTinyVarInt(2, will_notify_on_stop_, msg);
+ if (args.stderr_mode == OutputMode::kBuffer ||
+ args.stdout_mode == OutputMode::kBuffer) {
+ s_->stdouterr_pipe = Pipe::Create();
+ PERFETTO_CHECK(
+ ::SetHandleInformation(*s_->stdouterr_pipe.wr, HANDLE_FLAG_INHERIT, 1));
}
- // Field 3: will_notify_on_start
- if (_has_field_[3]) {
- ::protozero::internal::gen_helpers::SerializeTinyVarInt(3, will_notify_on_start_, msg);
+ ScopedPlatformHandle nul_handle;
+ if (args.stderr_mode == OutputMode::kDevNull ||
+ args.stdout_mode == OutputMode::kDevNull) {
+ nul_handle.reset(::CreateFileA(
+ "NUL", GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE,
+ nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr));
+ PERFETTO_CHECK(::SetHandleInformation(*nul_handle, HANDLE_FLAG_INHERIT, 1));
}
- // Field 4: handles_incremental_state_clear
- if (_has_field_[4]) {
- ::protozero::internal::gen_helpers::SerializeTinyVarInt(4, handles_incremental_state_clear_, msg);
- }
+ PROCESS_INFORMATION proc_info{};
+ STARTUPINFOA start_info{};
+ start_info.cb = sizeof(STARTUPINFOA);
- // Field 9: no_flush
- if (_has_field_[9]) {
- ::protozero::internal::gen_helpers::SerializeTinyVarInt(9, no_flush_, msg);
+ if (args.stderr_mode == OutputMode::kInherit) {
+ start_info.hStdError = ::GetStdHandle(STD_ERROR_HANDLE);
+ } else if (args.stderr_mode == OutputMode::kBuffer) {
+ start_info.hStdError = *s_->stdouterr_pipe.wr;
+ } else if (args.stderr_mode == OutputMode::kDevNull) {
+ start_info.hStdError = *nul_handle;
+ } else if (args.stderr_mode == OutputMode::kFd) {
+ PERFETTO_CHECK(
+ ::SetHandleInformation(*args.out_fd, HANDLE_FLAG_INHERIT, 1));
+ start_info.hStdError = *args.out_fd;
+ } else {
+ PERFETTO_CHECK(false);
}
- // Field 10: protovm_program
- if (_has_field_[10]) {
- (*protovm_program_).Serialize(msg->BeginNestedMessage<::protozero::Message>(10));
+ if (args.stdout_mode == OutputMode::kInherit) {
+ start_info.hStdOutput = ::GetStdHandle(STD_OUTPUT_HANDLE);
+ } else if (args.stdout_mode == OutputMode::kBuffer) {
+ start_info.hStdOutput = *s_->stdouterr_pipe.wr;
+ } else if (args.stdout_mode == OutputMode::kDevNull) {
+ start_info.hStdOutput = *nul_handle;
+ } else if (args.stdout_mode == OutputMode::kFd) {
+ PERFETTO_CHECK(
+ ::SetHandleInformation(*args.out_fd, HANDLE_FLAG_INHERIT, 1));
+ start_info.hStdOutput = *args.out_fd;
+ } else {
+ PERFETTO_CHECK(false);
}
- // Field 5: gpu_counter_descriptor
- if (_has_field_[5]) {
- msg->AppendString(5, gpu_counter_descriptor_);
+ if (args.stdin_mode == InputMode::kBuffer) {
+ start_info.hStdInput = *s_->stdin_pipe.rd;
+ } else if (args.stdin_mode == InputMode::kDevNull) {
+ start_info.hStdInput = *nul_handle;
}
- // Field 6: track_event_descriptor
- if (_has_field_[6]) {
- msg->AppendString(6, track_event_descriptor_);
- }
+ start_info.dwFlags |= STARTF_USESTDHANDLES;
- // Field 8: ftrace_descriptor
- if (_has_field_[8]) {
- msg->AppendString(8, ftrace_descriptor_);
- }
+ // Create the child process.
+ bool success =
+ ::CreateProcessA(nullptr, // App name. Needs to be null to use PATH.
+ &cmd[0], // Command line.
+ nullptr, // Process security attributes.
+ nullptr, // Primary thread security attributes.
+ true, // Handles are inherited.
+ 0, // Flags.
+ nullptr, // Use parent's environment.
+ nullptr, // Use parent's current directory.
+ &start_info, // STARTUPINFO pointer.
+ &proc_info); // Receives PROCESS_INFORMATION.
- protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
-}
+ // Close on our side the pipe ends that we passed to the child process.
+ s_->stdin_pipe.rd.reset();
+ s_->stdouterr_pipe.wr.reset();
+ args.out_fd.reset();
-} // namespace perfetto
-} // namespace protos
-} // namespace gen
-#if defined(__GNUC__) || defined(__clang__)
-#pragma GCC diagnostic pop
-#endif
-// gen_amalgamated begin source: gen/protos/perfetto/common/descriptor.gen.cc
-// gen_amalgamated expanded: #include "perfetto/protozero/gen_field_helpers.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/message.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/packed_repeated_fields.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/proto_decoder.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/scattered_heap_buffer.h"
-// DO NOT EDIT. Autogenerated by Perfetto cppgen_plugin
-#if defined(__GNUC__) || defined(__clang__)
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wfloat-equal"
-#endif
-// gen_amalgamated expanded: #include "protos/perfetto/common/descriptor.gen.h"
+ if (!success) {
+ s_->returncode = ERROR_FILE_NOT_FOUND;
+ s_->status = kTerminated;
+ s_->stdin_pipe.wr.reset();
+ s_->stdouterr_pipe.rd.reset();
+ PERFETTO_ELOG("CreateProcess failed: %lx, cmd: %s", GetLastError(),
+ &cmd[0]);
+ return;
+ }
-namespace perfetto {
-namespace protos {
-namespace gen {
+ s_->pid = proc_info.dwProcessId;
+ s_->win_proc_handle = ScopedPlatformHandle(proc_info.hProcess);
+ s_->win_thread_handle = ScopedPlatformHandle(proc_info.hThread);
+ s_->status = kRunning;
-OneofOptions::OneofOptions() = default;
-OneofOptions::~OneofOptions() = default;
-OneofOptions::OneofOptions(const OneofOptions&) = default;
-OneofOptions& OneofOptions::operator=(const OneofOptions&) = default;
-OneofOptions::OneofOptions(OneofOptions&&) noexcept = default;
-OneofOptions& OneofOptions::operator=(OneofOptions&&) = default;
+ MovableState* s = s_.get();
+ if (args.stdin_mode == InputMode::kBuffer) {
+ s_->stdin_thread = std::thread(&Subprocess::StdinThread, s, args.input);
+ }
-bool OneofOptions::operator==(const OneofOptions& other) const {
- return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_);
+ if (args.stderr_mode == OutputMode::kBuffer ||
+ args.stdout_mode == OutputMode::kBuffer) {
+ PERFETTO_DCHECK(s_->stdouterr_pipe.rd);
+ s_->stdouterr_thread = std::thread(&Subprocess::StdoutErrThread, s);
+ }
}
-bool OneofOptions::ParseFromArray(const void* raw, size_t size) {
- unknown_fields_.clear();
- bool packed_error = false;
-
- ::protozero::ProtoDecoder dec(raw, size);
- for (auto field = dec.ReadField(); field.valid(); field = dec.ReadField()) {
- if (field.id() < _has_field_.size()) {
- _has_field_.set(field.id());
- }
- switch (field.id()) {
- default:
- field.SerializeAndAppendTo(&unknown_fields_);
- break;
+// static
+void Subprocess::StdinThread(MovableState* s, const std::string& input) {
+ size_t input_written = 0;
+ while (input_written < input.size()) {
+ DWORD wsize = 0;
+ if (::WriteFile(*s->stdin_pipe.wr, input.data() + input_written,
+ static_cast<DWORD>(input.size() - input_written), &wsize,
+ nullptr)) {
+ input_written += wsize;
+ } else {
+ // ERROR_BROKEN_PIPE is WAI when the child just closes stdin and stops
+ // accepting input.
+ auto err = ::GetLastError();
+ if (err != ERROR_BROKEN_PIPE)
+ PERFETTO_PLOG("Subprocess WriteFile(stdin) failed %lx", err);
+ break;
}
- }
- return !packed_error && !dec.bytes_left();
+ } // while(...)
+ std::unique_lock<std::mutex> lock(s->mutex);
+ s->stdin_pipe.wr.reset();
}
-std::string OneofOptions::SerializeAsString() const {
- ::protozero::internal::gen_helpers::MessageSerializer msg;
- Serialize(msg.get());
- return msg.SerializeAsString();
-}
+// static
+void Subprocess::StdoutErrThread(MovableState* s) {
+ char buf[4096];
+ for (;;) {
+ DWORD rsize = 0;
+ bool res =
+ ::ReadFile(*s->stdouterr_pipe.rd, buf, sizeof(buf), &rsize, nullptr);
+ if (!res) {
+ auto err = GetLastError();
+ if (err != ERROR_BROKEN_PIPE)
+ PERFETTO_PLOG("Subprocess ReadFile(stdouterr) failed %lx", err);
+ }
-std::vector<uint8_t> OneofOptions::SerializeAsArray() const {
- ::protozero::internal::gen_helpers::MessageSerializer msg;
- Serialize(msg.get());
- return msg.SerializeAsArray();
+ if (rsize > 0) {
+ std::unique_lock<std::mutex> lock(s->mutex);
+ s->locked_outerr_buf.append(buf, static_cast<size_t>(rsize));
+ } else { // EOF or some error.
+ break;
+ }
+ } // For(..)
+
+ // Close the stdouterr_pipe. The main loop looks at the pipe closure to
+ // determine whether the stdout/err thread has completed.
+ {
+ std::unique_lock<std::mutex> lock(s->mutex);
+ s->stdouterr_pipe.rd.reset();
+ }
+ s->stdouterr_done_event.Notify();
}
-void OneofOptions::Serialize(::protozero::Message* msg) const {
- protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
+Subprocess::Status Subprocess::Poll() {
+ if (s_->status != kRunning)
+ return s_->status; // Nothing to poll.
+ Wait(1 /*ms*/);
+ return s_->status;
}
+bool Subprocess::Wait(int timeout_ms) {
+ PERFETTO_CHECK(s_->status != kNotStarted);
+ const bool wait_forever = timeout_ms == 0;
+ const int64_t wait_start_ms = base::GetWallTimeMs().count();
-EnumValueDescriptorProto::EnumValueDescriptorProto() = default;
-EnumValueDescriptorProto::~EnumValueDescriptorProto() = default;
-EnumValueDescriptorProto::EnumValueDescriptorProto(const EnumValueDescriptorProto&) = default;
-EnumValueDescriptorProto& EnumValueDescriptorProto::operator=(const EnumValueDescriptorProto&) = default;
-EnumValueDescriptorProto::EnumValueDescriptorProto(EnumValueDescriptorProto&&) noexcept = default;
-EnumValueDescriptorProto& EnumValueDescriptorProto::operator=(EnumValueDescriptorProto&&) = default;
+ // Break out of the loop only after both conditions are satisfied:
+ // - All stdout/stderr data has been read (if OutputMode::kBuffer).
+ // - The process exited.
+ // Note that the two events can happen arbitrary order. After the process
+ // exits, there might be still data in the pipe buffer, which we want to
+ // read fully.
+ // Note also that stdout/err might be "complete" before starting, if neither
+ // is operating in OutputMode::kBuffer mode. In that case we just want to wait
+ // for the process termination.
+ //
+ // Instead, don't wait on the stdin to be fully written. The child process
+ // might exit prematurely (or crash). If that happens, we can end up in a
+ // state where the write(stdin_pipe_.wr) will never unblock.
+ bool stdouterr_complete = false;
+ for (;;) {
+ HANDLE wait_handles[2]{};
+ DWORD num_handles = 0;
-bool EnumValueDescriptorProto::operator==(const EnumValueDescriptorProto& other) const {
- return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
- && ::protozero::internal::gen_helpers::EqualsField(name_, other.name_)
- && ::protozero::internal::gen_helpers::EqualsField(number_, other.number_);
-}
+ // Check if the process exited.
+ bool process_exited = !s_->win_proc_handle;
+ if (!process_exited) {
+ DWORD exit_code = STILL_ACTIVE;
+ PERFETTO_CHECK(::GetExitCodeProcess(*s_->win_proc_handle, &exit_code));
+ if (exit_code != STILL_ACTIVE) {
+ s_->returncode = static_cast<int>(exit_code);
+ s_->status = kTerminated;
+ s_->win_proc_handle.reset();
+ s_->win_thread_handle.reset();
+ process_exited = true;
+ }
+ } else {
+ PERFETTO_DCHECK(s_->status != kRunning);
+ }
+ if (!process_exited) {
+ wait_handles[num_handles++] = *s_->win_proc_handle;
+ }
-bool EnumValueDescriptorProto::ParseFromArray(const void* raw, size_t size) {
- unknown_fields_.clear();
- bool packed_error = false;
+ // Check if there is more output and if the stdout/err pipe has been closed.
+ {
+ std::unique_lock<std::mutex> lock(s_->mutex);
+ // Move the output from the internal buffer shared with the
+ // stdouterr_thread to the final buffer exposed to the client.
+ if (!s_->locked_outerr_buf.empty()) {
+ s_->output.append(std::move(s_->locked_outerr_buf));
+ s_->locked_outerr_buf.clear();
+ }
+ stdouterr_complete = !s_->stdouterr_pipe.rd;
+ if (!stdouterr_complete) {
+ wait_handles[num_handles++] = s_->stdouterr_done_event.fd();
+ }
+ } // lock(s_->mutex)
- ::protozero::ProtoDecoder dec(raw, size);
- for (auto field = dec.ReadField(); field.valid(); field = dec.ReadField()) {
- if (field.id() < _has_field_.size()) {
- _has_field_.set(field.id());
+ if (num_handles == 0) {
+ PERFETTO_DCHECK(process_exited && stdouterr_complete);
+ break;
}
- switch (field.id()) {
- case 1 /* name */:
- ::protozero::internal::gen_helpers::DeserializeString(field, &name_);
- break;
- case 2 /* number */:
- field.get(&number_);
- break;
- default:
- field.SerializeAndAppendTo(&unknown_fields_);
- break;
+
+ DWORD wait_ms; // Note: DWORD is unsigned.
+ if (wait_forever) {
+ wait_ms = INFINITE;
+ } else {
+ const int64_t now = GetWallTimeMs().count();
+ const int64_t wait_left_ms = timeout_ms - (now - wait_start_ms);
+ if (wait_left_ms <= 0)
+ return false; // Timed out
+ wait_ms = static_cast<DWORD>(wait_left_ms);
}
- }
- return !packed_error && !dec.bytes_left();
-}
-std::string EnumValueDescriptorProto::SerializeAsString() const {
- ::protozero::internal::gen_helpers::MessageSerializer msg;
- Serialize(msg.get());
- return msg.SerializeAsString();
-}
+ auto wait_res =
+ ::WaitForMultipleObjects(num_handles, wait_handles, false, wait_ms);
+ PERFETTO_CHECK(wait_res != WAIT_FAILED);
+ }
-std::vector<uint8_t> EnumValueDescriptorProto::SerializeAsArray() const {
- ::protozero::internal::gen_helpers::MessageSerializer msg;
- Serialize(msg.get());
- return msg.SerializeAsArray();
-}
+ PERFETTO_DCHECK(!s_->win_proc_handle);
+ PERFETTO_DCHECK(!s_->win_thread_handle);
-void EnumValueDescriptorProto::Serialize(::protozero::Message* msg) const {
- // Field 1: name
- if (_has_field_[1]) {
- ::protozero::internal::gen_helpers::SerializeString(1, name_, msg);
- }
+ if (s_->stdin_thread.joinable()) // Might not exist if CreateProcess failed.
+ s_->stdin_thread.join();
+ if (s_->stdouterr_thread.joinable())
+ s_->stdouterr_thread.join();
- // Field 2: number
- if (_has_field_[2]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(2, number_, msg);
- }
+ // The stdin pipe is closed by the dedicated stdin thread. However if that is
+ // not started (e.g. because of no redirection) force close it now. Needs to
+ // happen after the join() to be thread safe.
+ s_->stdin_pipe.wr.reset();
+ s_->stdouterr_pipe.rd.reset();
- protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
+ return true;
}
+void Subprocess::Kill(int exit_code) {
+ auto code = exit_code ? static_cast<DWORD>(exit_code) : STATUS_CONTROL_C_EXIT;
+ ::TerminateProcess(*s_->win_proc_handle, code);
+}
-EnumDescriptorProto::EnumDescriptorProto() = default;
-EnumDescriptorProto::~EnumDescriptorProto() = default;
-EnumDescriptorProto::EnumDescriptorProto(const EnumDescriptorProto&) = default;
-EnumDescriptorProto& EnumDescriptorProto::operator=(const EnumDescriptorProto&) = default;
-EnumDescriptorProto::EnumDescriptorProto(EnumDescriptorProto&&) noexcept = default;
-EnumDescriptorProto& EnumDescriptorProto::operator=(EnumDescriptorProto&&) = default;
-
-bool EnumDescriptorProto::operator==(const EnumDescriptorProto& other) const {
- return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
- && ::protozero::internal::gen_helpers::EqualsField(name_, other.name_)
- && ::protozero::internal::gen_helpers::EqualsField(value_, other.value_)
- && ::protozero::internal::gen_helpers::EqualsField(reserved_name_, other.reserved_name_);
+void Subprocess::KillAndWaitForTermination(int exit_code) {
+ Kill(exit_code);
+ Wait();
+ // TryReadExitStatus must have joined the threads.
+ PERFETTO_DCHECK(!s_->stdin_thread.joinable());
+ PERFETTO_DCHECK(!s_->stdouterr_thread.joinable());
}
-int EnumDescriptorProto::value_size() const { return static_cast<int>(value_.size()); }
-void EnumDescriptorProto::clear_value() { value_.clear(); }
-EnumValueDescriptorProto* EnumDescriptorProto::add_value() { value_.emplace_back(); return &value_.back(); }
-bool EnumDescriptorProto::ParseFromArray(const void* raw, size_t size) {
- value_.clear();
- reserved_name_.clear();
- unknown_fields_.clear();
- bool packed_error = false;
+} // namespace base
+} // namespace perfetto
- ::protozero::ProtoDecoder dec(raw, size);
- for (auto field = dec.ReadField(); field.valid(); field = dec.ReadField()) {
- if (field.id() < _has_field_.size()) {
- _has_field_.set(field.id());
+#endif // PERFETTO_OS_WIN
+// gen_amalgamated begin source: src/protozero/field.cc
+/*
+ * 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.
+ */
+
+// gen_amalgamated expanded: #include "perfetto/protozero/field.h"
+
+// gen_amalgamated expanded: #include "perfetto/base/compiler.h"
+// gen_amalgamated expanded: #include "perfetto/base/endian.h"
+// gen_amalgamated expanded: #include "perfetto/base/logging.h"
+
+namespace protozero {
+
+template <typename Container>
+void Field::SerializeAndAppendToInternal(Container* dst) const {
+ namespace pu = proto_utils;
+ size_t initial_size = dst->size();
+ dst->resize(initial_size + pu::kMaxSimpleFieldEncodedSize + size_);
+ uint8_t* start = reinterpret_cast<uint8_t*>(&(*dst)[initial_size]);
+ uint8_t* wptr = start;
+ switch (type_) {
+ case static_cast<int>(pu::ProtoWireType::kVarInt): {
+ wptr = pu::WriteVarInt(pu::MakeTagVarInt(id_), wptr);
+ wptr = pu::WriteVarInt(int_value_, wptr);
+ break;
}
- switch (field.id()) {
- case 1 /* name */:
- ::protozero::internal::gen_helpers::DeserializeString(field, &name_);
- break;
- case 2 /* value */:
- value_.emplace_back();
- value_.back().ParseFromArray(field.data(), field.size());
- break;
- case 5 /* reserved_name */:
- reserved_name_.emplace_back();
- ::protozero::internal::gen_helpers::DeserializeString(field, &reserved_name_.back());
- break;
- default:
- field.SerializeAndAppendTo(&unknown_fields_);
- break;
+ case static_cast<int>(pu::ProtoWireType::kFixed32): {
+ wptr = pu::WriteVarInt(pu::MakeTagFixed<uint32_t>(id_), wptr);
+ uint32_t value32 =
+ perfetto::base::HostToLE(static_cast<uint32_t>(int_value_));
+ memcpy(wptr, &value32, sizeof(value32));
+ wptr += sizeof(uint32_t);
+ break;
+ }
+ case static_cast<int>(pu::ProtoWireType::kFixed64): {
+ wptr = pu::WriteVarInt(pu::MakeTagFixed<uint64_t>(id_), wptr);
+ uint64_t value64 = perfetto::base::HostToLE(int_value_);
+ memcpy(wptr, &value64, sizeof(value64));
+ wptr += sizeof(uint64_t);
+ break;
+ }
+ case static_cast<int>(pu::ProtoWireType::kLengthDelimited): {
+ ConstBytes payload = as_bytes();
+ wptr = pu::WriteVarInt(pu::MakeTagLengthDelimited(id_), wptr);
+ wptr = pu::WriteVarInt(payload.size, wptr);
+ memcpy(wptr, payload.data, payload.size);
+ wptr += payload.size;
+ break;
}
+ default:
+ PERFETTO_FATAL("Unknown field type %d", type_);
}
- return !packed_error && !dec.bytes_left();
+ size_t written_size = static_cast<size_t>(wptr - start);
+ PERFETTO_DCHECK(written_size > 0 && written_size < pu::kMaxMessageLength);
+ PERFETTO_DCHECK(initial_size + written_size <= dst->size());
+ dst->resize(initial_size + written_size);
}
-std::string EnumDescriptorProto::SerializeAsString() const {
- ::protozero::internal::gen_helpers::MessageSerializer msg;
- Serialize(msg.get());
- return msg.SerializeAsString();
+void Field::SerializeAndAppendTo(std::string* dst) const {
+ SerializeAndAppendToInternal(dst);
}
-std::vector<uint8_t> EnumDescriptorProto::SerializeAsArray() const {
- ::protozero::internal::gen_helpers::MessageSerializer msg;
- Serialize(msg.get());
- return msg.SerializeAsArray();
+void Field::SerializeAndAppendTo(std::vector<uint8_t>* dst) const {
+ SerializeAndAppendToInternal(dst);
}
-void EnumDescriptorProto::Serialize(::protozero::Message* msg) const {
- // Field 1: name
- if (_has_field_[1]) {
- ::protozero::internal::gen_helpers::SerializeString(1, name_, msg);
- }
+} // namespace protozero
+// gen_amalgamated begin source: src/protozero/gen_field_helpers.cc
+/*
+ * 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.
+ */
- // Field 2: value
- for (auto& it : value_) {
- it.Serialize(msg->BeginNestedMessage<::protozero::Message>(2));
- }
+// gen_amalgamated expanded: #include "perfetto/protozero/gen_field_helpers.h"
- // Field 5: reserved_name
- for (auto& it : reserved_name_) {
- ::protozero::internal::gen_helpers::SerializeString(5, it, msg);
- }
+namespace protozero {
+namespace internal {
+namespace gen_helpers {
- protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
+void DeserializeString(const protozero::Field& field, std::string* dst) {
+ field.get(dst);
}
+template bool DeserializePackedRepeated<proto_utils::ProtoWireType::kVarInt,
+ uint64_t>(const protozero::Field& field,
+ std::vector<uint64_t>* dst);
-OneofDescriptorProto::OneofDescriptorProto() = default;
-OneofDescriptorProto::~OneofDescriptorProto() = default;
-OneofDescriptorProto::OneofDescriptorProto(const OneofDescriptorProto&) = default;
-OneofDescriptorProto& OneofDescriptorProto::operator=(const OneofDescriptorProto&) = default;
-OneofDescriptorProto::OneofDescriptorProto(OneofDescriptorProto&&) noexcept = default;
-OneofDescriptorProto& OneofDescriptorProto::operator=(OneofDescriptorProto&&) = default;
+template bool DeserializePackedRepeated<proto_utils::ProtoWireType::kVarInt,
+ int64_t>(const protozero::Field& field,
+ std::vector<int64_t>* dst);
-bool OneofDescriptorProto::operator==(const OneofDescriptorProto& other) const {
- return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
- && ::protozero::internal::gen_helpers::EqualsField(name_, other.name_)
- && ::protozero::internal::gen_helpers::EqualsField(options_, other.options_);
-}
+template bool DeserializePackedRepeated<proto_utils::ProtoWireType::kVarInt,
+ uint32_t>(const protozero::Field& field,
+ std::vector<uint32_t>* dst);
-bool OneofDescriptorProto::ParseFromArray(const void* raw, size_t size) {
- unknown_fields_.clear();
- bool packed_error = false;
+template bool DeserializePackedRepeated<proto_utils::ProtoWireType::kVarInt,
+ int32_t>(const protozero::Field& field,
+ std::vector<int32_t>* dst);
- ::protozero::ProtoDecoder dec(raw, size);
- for (auto field = dec.ReadField(); field.valid(); field = dec.ReadField()) {
- if (field.id() < _has_field_.size()) {
- _has_field_.set(field.id());
- }
- switch (field.id()) {
- case 1 /* name */:
- ::protozero::internal::gen_helpers::DeserializeString(field, &name_);
- break;
- case 2 /* options */:
- (*options_).ParseFromArray(field.data(), field.size());
- break;
- default:
- field.SerializeAndAppendTo(&unknown_fields_);
- break;
- }
- }
- return !packed_error && !dec.bytes_left();
+void SerializeTinyVarInt(uint32_t field_id, bool value, Message* msg) {
+ msg->AppendTinyVarInt(field_id, value);
}
-std::string OneofDescriptorProto::SerializeAsString() const {
- ::protozero::internal::gen_helpers::MessageSerializer msg;
- Serialize(msg.get());
- return msg.SerializeAsString();
-}
+template void SerializeExtendedVarInt<uint64_t>(uint32_t field_id,
+ uint64_t value,
+ Message* msg);
-std::vector<uint8_t> OneofDescriptorProto::SerializeAsArray() const {
- ::protozero::internal::gen_helpers::MessageSerializer msg;
- Serialize(msg.get());
- return msg.SerializeAsArray();
-}
+template void SerializeExtendedVarInt<uint32_t>(uint32_t field_id,
+ uint32_t value,
+ Message* msg);
-void OneofDescriptorProto::Serialize(::protozero::Message* msg) const {
- // Field 1: name
- if (_has_field_[1]) {
- ::protozero::internal::gen_helpers::SerializeString(1, name_, msg);
- }
+template void SerializeFixed<double>(uint32_t field_id,
+ double value,
+ Message* msg);
- // Field 2: options
- if (_has_field_[2]) {
- (*options_).Serialize(msg->BeginNestedMessage<::protozero::Message>(2));
- }
+template void SerializeFixed<float>(uint32_t field_id,
+ float value,
+ Message* msg);
- protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
-}
+template void SerializeFixed<uint64_t>(uint32_t field_id,
+ uint64_t value,
+ Message* msg);
+template void SerializeFixed<int64_t>(uint32_t field_id,
+ int64_t value,
+ Message* msg);
-FieldDescriptorProto::FieldDescriptorProto() = default;
-FieldDescriptorProto::~FieldDescriptorProto() = default;
-FieldDescriptorProto::FieldDescriptorProto(const FieldDescriptorProto&) = default;
-FieldDescriptorProto& FieldDescriptorProto::operator=(const FieldDescriptorProto&) = default;
-FieldDescriptorProto::FieldDescriptorProto(FieldDescriptorProto&&) noexcept = default;
-FieldDescriptorProto& FieldDescriptorProto::operator=(FieldDescriptorProto&&) = default;
+template void SerializeFixed<uint32_t>(uint32_t field_id,
+ uint32_t value,
+ Message* msg);
-bool FieldDescriptorProto::operator==(const FieldDescriptorProto& other) const {
- return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
- && ::protozero::internal::gen_helpers::EqualsField(name_, other.name_)
- && ::protozero::internal::gen_helpers::EqualsField(number_, other.number_)
- && ::protozero::internal::gen_helpers::EqualsField(label_, other.label_)
- && ::protozero::internal::gen_helpers::EqualsField(type_, other.type_)
- && ::protozero::internal::gen_helpers::EqualsField(type_name_, other.type_name_)
- && ::protozero::internal::gen_helpers::EqualsField(extendee_, other.extendee_)
- && ::protozero::internal::gen_helpers::EqualsField(default_value_, other.default_value_)
- && ::protozero::internal::gen_helpers::EqualsField(options_, other.options_)
- && ::protozero::internal::gen_helpers::EqualsField(oneof_index_, other.oneof_index_);
-}
+template void SerializeFixed<int32_t>(uint32_t field_id,
+ int32_t value,
+ Message* msg);
-bool FieldDescriptorProto::ParseFromArray(const void* raw, size_t size) {
- unknown_fields_.clear();
- bool packed_error = false;
+void SerializeString(uint32_t field_id,
+ const std::string& value,
+ Message* msg) {
+ msg->AppendString(field_id, value);
+}
- ::protozero::ProtoDecoder dec(raw, size);
- for (auto field = dec.ReadField(); field.valid(); field = dec.ReadField()) {
- if (field.id() < _has_field_.size()) {
- _has_field_.set(field.id());
- }
- switch (field.id()) {
- case 1 /* name */:
- ::protozero::internal::gen_helpers::DeserializeString(field, &name_);
- break;
- case 3 /* number */:
- field.get(&number_);
- break;
- case 4 /* label */:
- field.get(&label_);
- break;
- case 5 /* type */:
- field.get(&type_);
- break;
- case 6 /* type_name */:
- ::protozero::internal::gen_helpers::DeserializeString(field, &type_name_);
- break;
- case 2 /* extendee */:
- ::protozero::internal::gen_helpers::DeserializeString(field, &extendee_);
- break;
- case 7 /* default_value */:
- ::protozero::internal::gen_helpers::DeserializeString(field, &default_value_);
- break;
- case 8 /* options */:
- (*options_).ParseFromArray(field.data(), field.size());
- break;
- case 9 /* oneof_index */:
- field.get(&oneof_index_);
- break;
- default:
- field.SerializeAndAppendTo(&unknown_fields_);
- break;
- }
- }
- return !packed_error && !dec.bytes_left();
+void SerializeUnknownFields(const std::string& unknown_fields, Message* msg) {
+ msg->AppendRawProtoBytes(unknown_fields.data(), unknown_fields.size());
}
-std::string FieldDescriptorProto::SerializeAsString() const {
- ::protozero::internal::gen_helpers::MessageSerializer msg;
- Serialize(msg.get());
- return msg.SerializeAsString();
+MessageSerializer::MessageSerializer() = default;
+
+MessageSerializer::~MessageSerializer() = default;
+
+std::vector<uint8_t> MessageSerializer::SerializeAsArray() {
+ return msg_.SerializeAsArray();
}
-std::vector<uint8_t> FieldDescriptorProto::SerializeAsArray() const {
- ::protozero::internal::gen_helpers::MessageSerializer msg;
- Serialize(msg.get());
- return msg.SerializeAsArray();
+std::string MessageSerializer::SerializeAsString() {
+ return msg_.SerializeAsString();
}
-void FieldDescriptorProto::Serialize(::protozero::Message* msg) const {
- // Field 1: name
- if (_has_field_[1]) {
- ::protozero::internal::gen_helpers::SerializeString(1, name_, msg);
- }
+template bool EqualsField<std::string>(const std::string&, const std::string&);
- // Field 3: number
- if (_has_field_[3]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(3, number_, msg);
- }
+} // namespace gen_helpers
+} // namespace internal
+} // namespace protozero
+// gen_amalgamated begin source: src/protozero/message.cc
+/*
+ * 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.
+ */
- // Field 4: label
- if (_has_field_[4]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(4, label_, msg);
- }
+// gen_amalgamated expanded: #include "perfetto/protozero/message.h"
- // Field 5: type
- if (_has_field_[5]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(5, type_, msg);
- }
+#include <atomic>
+#include <type_traits>
- // Field 6: type_name
- if (_has_field_[6]) {
- ::protozero::internal::gen_helpers::SerializeString(6, type_name_, msg);
- }
+// gen_amalgamated expanded: #include "perfetto/base/compiler.h"
+// gen_amalgamated expanded: #include "perfetto/base/logging.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/message_arena.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/message_handle.h"
- // Field 2: extendee
- if (_has_field_[2]) {
- ::protozero::internal::gen_helpers::SerializeString(2, extendee_, msg);
- }
+namespace protozero {
- // Field 7: default_value
- if (_has_field_[7]) {
- ::protozero::internal::gen_helpers::SerializeString(7, default_value_, msg);
- }
+namespace {
- // Field 8: options
- if (_has_field_[8]) {
- (*options_).Serialize(msg->BeginNestedMessage<::protozero::Message>(8));
- }
+constexpr int kBytesToCompact = proto_utils::kMessageLengthFieldSize - 1u;
- // Field 9: oneof_index
- if (_has_field_[9]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(9, oneof_index_, msg);
- }
+#if PERFETTO_DCHECK_IS_ON()
+std::atomic<uint32_t> g_generation;
+#endif
- protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
-}
+} // namespace
+// Do NOT put any code in the constructor or use default initialization.
+// Use the Reset() method below instead.
-FieldOptions::FieldOptions() = default;
-FieldOptions::~FieldOptions() = default;
-FieldOptions::FieldOptions(const FieldOptions&) = default;
-FieldOptions& FieldOptions::operator=(const FieldOptions&) = default;
-FieldOptions::FieldOptions(FieldOptions&&) noexcept = default;
-FieldOptions& FieldOptions::operator=(FieldOptions&&) = default;
+// This method is called to initialize both root and nested messages.
+void Message::Reset(ScatteredStreamWriter* stream_writer,
+ MessageArena* arena,
+ Encoding encoding) {
+// Older versions of libstdcxx don't have is_trivially_constructible.
+#if !defined(__GLIBCXX__) || __GLIBCXX__ >= 20170516
+ static_assert(std::is_trivially_constructible<Message>::value,
+ "Message must be trivially constructible");
+#endif
-bool FieldOptions::operator==(const FieldOptions& other) const {
- return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
- && ::protozero::internal::gen_helpers::EqualsField(packed_, other.packed_)
- && ::protozero::internal::gen_helpers::EqualsField(uninterpreted_option_, other.uninterpreted_option_);
+ static_assert(std::is_trivially_destructible<Message>::value,
+ "Message must be trivially destructible");
+ stream_writer_ = stream_writer;
+ arena_ = arena;
+ size_ = 0;
+ size_field_ = nullptr;
+ nested_message_ = nullptr;
+ message_state_ = MessageState::kNotFinalized;
+ encoding_ = encoding;
+#if PERFETTO_DCHECK_IS_ON()
+ handle_ = nullptr;
+ generation_ = g_generation.fetch_add(1, std::memory_order_relaxed);
+#endif
}
-int FieldOptions::uninterpreted_option_size() const { return static_cast<int>(uninterpreted_option_.size()); }
-void FieldOptions::clear_uninterpreted_option() { uninterpreted_option_.clear(); }
-UninterpretedOption* FieldOptions::add_uninterpreted_option() { uninterpreted_option_.emplace_back(); return &uninterpreted_option_.back(); }
-bool FieldOptions::ParseFromArray(const void* raw, size_t size) {
- uninterpreted_option_.clear();
- unknown_fields_.clear();
- bool packed_error = false;
-
- ::protozero::ProtoDecoder dec(raw, size);
- for (auto field = dec.ReadField(); field.valid(); field = dec.ReadField()) {
- if (field.id() < _has_field_.size()) {
- _has_field_.set(field.id());
- }
- switch (field.id()) {
- case 2 /* packed */:
- field.get(&packed_);
- break;
- case 999 /* uninterpreted_option */:
- uninterpreted_option_.emplace_back();
- uninterpreted_option_.back().ParseFromArray(field.data(), field.size());
- break;
- default:
- field.SerializeAndAppendTo(&unknown_fields_);
- break;
- }
- }
- return !packed_error && !dec.bytes_left();
+void Message::AppendString(uint32_t field_id, const char* str) {
+ AppendBytes(field_id, str, strlen(str));
}
-std::string FieldOptions::SerializeAsString() const {
- ::protozero::internal::gen_helpers::MessageSerializer msg;
- Serialize(msg.get());
- return msg.SerializeAsString();
-}
+void Message::AppendBytes(uint32_t field_id, const void* src, size_t size) {
+ PERFETTO_DCHECK(field_id);
+ if (nested_message_)
+ EndNestedMessage();
-std::vector<uint8_t> FieldOptions::SerializeAsArray() const {
- ::protozero::internal::gen_helpers::MessageSerializer msg;
- Serialize(msg.get());
- return msg.SerializeAsArray();
+ PERFETTO_DCHECK(size < proto_utils::kMaxMessageLength);
+ // Write the proto preamble (field id, type and length of the field).
+ uint8_t buffer[proto_utils::kMaxSimpleFieldEncodedSize];
+ uint8_t* pos = buffer;
+ pos = proto_utils::WriteVarInt(proto_utils::MakeTagLengthDelimited(field_id),
+ pos);
+ pos = proto_utils::WriteVarInt(static_cast<uint32_t>(size), pos);
+ WriteToStream(buffer, pos);
+
+ const uint8_t* src_u8 = reinterpret_cast<const uint8_t*>(src);
+ WriteToStream(src_u8, src_u8 + size);
}
-void FieldOptions::Serialize(::protozero::Message* msg) const {
- // Field 2: packed
- if (_has_field_[2]) {
- ::protozero::internal::gen_helpers::SerializeTinyVarInt(2, packed_, msg);
- }
+size_t Message::AppendScatteredBytes(uint32_t field_id,
+ ContiguousMemoryRange* ranges,
+ size_t num_ranges) {
+ PERFETTO_DCHECK(field_id);
+ if (nested_message_)
+ EndNestedMessage();
- // Field 999: uninterpreted_option
- for (auto& it : uninterpreted_option_) {
- it.Serialize(msg->BeginNestedMessage<::protozero::Message>(999));
+ size_t size = 0;
+ for (size_t i = 0; i < num_ranges; ++i) {
+ size += ranges[i].size();
}
- protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
-}
+ PERFETTO_DCHECK(size < proto_utils::kMaxMessageLength);
+ uint8_t buffer[proto_utils::kMaxSimpleFieldEncodedSize];
+ uint8_t* pos = buffer;
+ pos = proto_utils::WriteVarInt(proto_utils::MakeTagLengthDelimited(field_id),
+ pos);
+ pos = proto_utils::WriteVarInt(static_cast<uint32_t>(size), pos);
+ WriteToStream(buffer, pos);
-UninterpretedOption::UninterpretedOption() = default;
-UninterpretedOption::~UninterpretedOption() = default;
-UninterpretedOption::UninterpretedOption(const UninterpretedOption&) = default;
-UninterpretedOption& UninterpretedOption::operator=(const UninterpretedOption&) = default;
-UninterpretedOption::UninterpretedOption(UninterpretedOption&&) noexcept = default;
-UninterpretedOption& UninterpretedOption::operator=(UninterpretedOption&&) = default;
+ for (size_t i = 0; i < num_ranges; ++i) {
+ auto& range = ranges[i];
+ WriteToStream(range.begin, range.end);
+ }
-bool UninterpretedOption::operator==(const UninterpretedOption& other) const {
- return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
- && ::protozero::internal::gen_helpers::EqualsField(name_, other.name_)
- && ::protozero::internal::gen_helpers::EqualsField(identifier_value_, other.identifier_value_)
- && ::protozero::internal::gen_helpers::EqualsField(positive_int_value_, other.positive_int_value_)
- && ::protozero::internal::gen_helpers::EqualsField(negative_int_value_, other.negative_int_value_)
- && ::protozero::internal::gen_helpers::EqualsField(double_value_, other.double_value_)
- && ::protozero::internal::gen_helpers::EqualsField(string_value_, other.string_value_)
- && ::protozero::internal::gen_helpers::EqualsField(aggregate_value_, other.aggregate_value_);
+ return size;
}
-int UninterpretedOption::name_size() const { return static_cast<int>(name_.size()); }
-void UninterpretedOption::clear_name() { name_.clear(); }
-UninterpretedOption_NamePart* UninterpretedOption::add_name() { name_.emplace_back(); return &name_.back(); }
-bool UninterpretedOption::ParseFromArray(const void* raw, size_t size) {
- name_.clear();
- unknown_fields_.clear();
- bool packed_error = false;
+uint32_t Message::Finalize() {
+ if (is_finalized())
+ return size_;
- ::protozero::ProtoDecoder dec(raw, size);
- for (auto field = dec.ReadField(); field.valid(); field = dec.ReadField()) {
- if (field.id() < _has_field_.size()) {
- _has_field_.set(field.id());
- }
- switch (field.id()) {
- case 2 /* name */:
- name_.emplace_back();
- name_.back().ParseFromArray(field.data(), field.size());
- break;
- case 3 /* identifier_value */:
- ::protozero::internal::gen_helpers::DeserializeString(field, &identifier_value_);
- break;
- case 4 /* positive_int_value */:
- field.get(&positive_int_value_);
- break;
- case 5 /* negative_int_value */:
- field.get(&negative_int_value_);
- break;
- case 6 /* double_value */:
- field.get(&double_value_);
- break;
- case 7 /* string_value */:
- field.get(&string_value_);
- break;
- case 8 /* aggregate_value */:
- ::protozero::internal::gen_helpers::DeserializeString(field, &aggregate_value_);
- break;
- default:
- field.SerializeAndAppendTo(&unknown_fields_);
- break;
+ if (nested_message_)
+ EndNestedMessage();
+
+ // Write the length of the nested message a posteriori, using a leading-zero
+ // redundant varint encoding. This can be nullptr for the root message, among
+ // many reasons, because the TraceWriterImpl delegate is keeping track of the
+ // root fragment size independently.
+ if (size_field_) {
+ PERFETTO_DCHECK(encoding_ == Encoding::kLengthDelimited);
+ PERFETTO_DCHECK(!is_finalized());
+ PERFETTO_DCHECK(size_ < proto_utils::kMaxMessageLength);
+ //
+ // Normally the size of a protozero message is written with 4 bytes just
+ // before the contents of the message itself:
+ //
+ // size message data
+ // [aa bb cc dd] [01 23 45 67 ...]
+ //
+ // We always reserve 4 bytes for the size, because the real size of the
+ // message isn't known until the call to Finalize(). This is possible
+ // because we can use leading zero redundant varint coding to expand any
+ // size smaller than 256 MiB to 4 bytes.
+ //
+ // However this is wasteful for short, frequently written messages, so the
+ // code below uses a 1 byte size field when possible. This is done by
+ // shifting the already-written data (which should still be in the cache)
+ // back by 3 bytes, resulting in this layout:
+ //
+ // size message data
+ // [aa] [01 23 45 67 ...]
+ //
+ // We can only do this optimization if the message is contained in a single
+ // chunk (since we can't modify previously committed chunks). We can check
+ // this by verifying that the size field is immediately before the message
+ // in memory and is fully contained by the current chunk.
+ //
+ if (PERFETTO_LIKELY(size_ <= proto_utils::kMaxOneByteMessageLength &&
+ size_field_ ==
+ stream_writer_->write_ptr() - size_ -
+ proto_utils::kMessageLengthFieldSize &&
+ size_field_ >= stream_writer_->cur_range().begin)) {
+ stream_writer_->Rewind(size_, kBytesToCompact);
+ PERFETTO_DCHECK(size_field_ == stream_writer_->write_ptr() - size_ - 1u);
+ *size_field_ = static_cast<uint8_t>(size_);
+ message_state_ = MessageState::kFinalizedWithCompaction;
+ } else {
+ proto_utils::WriteRedundantVarInt(size_, size_field_);
+ message_state_ = MessageState::kFinalized;
}
+ size_field_ = nullptr;
+ } else {
+ message_state_ = MessageState::kFinalized;
}
- return !packed_error && !dec.bytes_left();
-}
-std::string UninterpretedOption::SerializeAsString() const {
- ::protozero::internal::gen_helpers::MessageSerializer msg;
- Serialize(msg.get());
- return msg.SerializeAsString();
-}
+#if PERFETTO_DCHECK_IS_ON()
+ if (handle_)
+ handle_->reset_message();
+#endif
-std::vector<uint8_t> UninterpretedOption::SerializeAsArray() const {
- ::protozero::internal::gen_helpers::MessageSerializer msg;
- Serialize(msg.get());
- return msg.SerializeAsArray();
+ return size_;
}
-void UninterpretedOption::Serialize(::protozero::Message* msg) const {
- // Field 2: name
- for (auto& it : name_) {
- it.Serialize(msg->BeginNestedMessage<::protozero::Message>(2));
- }
+Message* Message::BeginNestedMessageInternal(uint32_t field_id) {
+ PERFETTO_DCHECK(field_id);
+ if (nested_message_)
+ EndNestedMessage();
- // Field 3: identifier_value
- if (_has_field_[3]) {
- ::protozero::internal::gen_helpers::SerializeString(3, identifier_value_, msg);
- }
+ // Write the proto preamble for the nested message.
+ const bool is_length_delimited = encoding_ == Encoding::kLengthDelimited;
+ const uint32_t tag = is_length_delimited
+ ? proto_utils::MakeTagLengthDelimited(field_id)
+ : proto_utils::MakeTagStartGroup(field_id);
+ uint8_t data[proto_utils::kMaxTagEncodedSize];
+ uint8_t* data_end = proto_utils::WriteVarInt(tag, data);
+ WriteToStream(data, data_end);
- // Field 4: positive_int_value
- if (_has_field_[4]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(4, positive_int_value_, msg);
- }
+ Message* message = arena_->NewMessage();
+ message->Reset(stream_writer_, arena_, encoding_);
- // Field 5: negative_int_value
- if (_has_field_[5]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(5, negative_int_value_, msg);
+ // A proto group child needs no length field. EndNestedMessage() ends it with
+ // a closing byte.
+ if (is_length_delimited) {
+ // The length of the nested message cannot be known upfront. So right now
+ // just reserve the bytes to encode the size after the nested message is
+ // done.
+ message->set_size_field(
+ stream_writer_->ReserveBytes(proto_utils::kMessageLengthFieldSize));
+ size_ += proto_utils::kMessageLengthFieldSize;
}
- // Field 6: double_value
- if (_has_field_[6]) {
- ::protozero::internal::gen_helpers::SerializeFixed(6, double_value_, msg);
- }
+ nested_message_ = message;
+ return message;
+}
- // Field 7: string_value
- if (_has_field_[7]) {
- ::protozero::internal::gen_helpers::SerializeString(7, string_value_, msg);
+void Message::EndNestedMessage() {
+ size_ += nested_message_->Finalize();
+ if (nested_message_->message_state_ ==
+ MessageState::kFinalizedWithCompaction) {
+ size_ -= kBytesToCompact;
}
- // Field 8: aggregate_value
- if (_has_field_[8]) {
- ::protozero::internal::gen_helpers::SerializeString(8, aggregate_value_, msg);
+ // Every write path of this message calls EndNestedMessage() first. So the
+ // closing byte follows the child's last byte, even if the child was
+ // finalized earlier.
+ if (encoding_ == Encoding::kProtoGroup) {
+ // Point at the constant. A local copy would make the compiler add a stack
+ // check to this function and to Finalize(), which inlines it.
+ const uint8_t* closing_byte = &proto_utils::kProtoGroupEndByte;
+ WriteToStream(closing_byte, closing_byte + 1);
}
- protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
+ arena_->DeleteLastMessage(nested_message_);
+ nested_message_ = nullptr;
}
+} // namespace protozero
+// gen_amalgamated begin source: src/protozero/message_arena.cc
+/*
+ * 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.
+ */
-UninterpretedOption_NamePart::UninterpretedOption_NamePart() = default;
-UninterpretedOption_NamePart::~UninterpretedOption_NamePart() = default;
-UninterpretedOption_NamePart::UninterpretedOption_NamePart(const UninterpretedOption_NamePart&) = default;
-UninterpretedOption_NamePart& UninterpretedOption_NamePart::operator=(const UninterpretedOption_NamePart&) = default;
-UninterpretedOption_NamePart::UninterpretedOption_NamePart(UninterpretedOption_NamePart&&) noexcept = default;
-UninterpretedOption_NamePart& UninterpretedOption_NamePart::operator=(UninterpretedOption_NamePart&&) = default;
+// gen_amalgamated expanded: #include "perfetto/protozero/message_arena.h"
-bool UninterpretedOption_NamePart::operator==(const UninterpretedOption_NamePart& other) const {
- return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
- && ::protozero::internal::gen_helpers::EqualsField(name_part_, other.name_part_)
- && ::protozero::internal::gen_helpers::EqualsField(is_extension_, other.is_extension_);
-}
+#include <atomic>
+#include <type_traits>
-bool UninterpretedOption_NamePart::ParseFromArray(const void* raw, size_t size) {
- unknown_fields_.clear();
- bool packed_error = false;
+// gen_amalgamated expanded: #include "perfetto/base/logging.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/message_handle.h"
- ::protozero::ProtoDecoder dec(raw, size);
- for (auto field = dec.ReadField(); field.valid(); field = dec.ReadField()) {
- if (field.id() < _has_field_.size()) {
- _has_field_.set(field.id());
- }
- switch (field.id()) {
- case 1 /* name_part */:
- ::protozero::internal::gen_helpers::DeserializeString(field, &name_part_);
- break;
- case 2 /* is_extension */:
- field.get(&is_extension_);
- break;
- default:
- field.SerializeAndAppendTo(&unknown_fields_);
- break;
- }
- }
- return !packed_error && !dec.bytes_left();
-}
+namespace protozero {
-std::string UninterpretedOption_NamePart::SerializeAsString() const {
- ::protozero::internal::gen_helpers::MessageSerializer msg;
- Serialize(msg.get());
- return msg.SerializeAsString();
+MessageArena::MessageArena() {
+ // The code below assumes that there is always at least one block.
+ blocks_.emplace_front();
}
-std::vector<uint8_t> UninterpretedOption_NamePart::SerializeAsArray() const {
- ::protozero::internal::gen_helpers::MessageSerializer msg;
- Serialize(msg.get());
- return msg.SerializeAsArray();
-}
+MessageArena::~MessageArena() = default;
-void UninterpretedOption_NamePart::Serialize(::protozero::Message* msg) const {
- // Field 1: name_part
- if (_has_field_[1]) {
- ::protozero::internal::gen_helpers::SerializeString(1, name_part_, msg);
- }
+Message* MessageArena::NewMessage() {
+ PERFETTO_DCHECK(!blocks_.empty()); // Should never become empty.
- // Field 2: is_extension
- if (_has_field_[2]) {
- ::protozero::internal::gen_helpers::SerializeTinyVarInt(2, is_extension_, msg);
+ Block* block = &blocks_.front();
+ if (PERFETTO_UNLIKELY(block->entries >= Block::kCapacity)) {
+ blocks_.emplace_front();
+ block = &blocks_.front();
}
-
- protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
+ const auto idx = block->entries++;
+ void* storage = block->storage[idx];
+ PERFETTO_ASAN_UNPOISON(storage, sizeof(Message));
+ return new (storage) Message();
}
+void MessageArena::DeleteLastMessageInternal() {
+ PERFETTO_DCHECK(!blocks_.empty()); // Should never be empty, see below.
+ Block* block = &blocks_.front();
+ PERFETTO_DCHECK(block->entries > 0);
-DescriptorProto::DescriptorProto() = default;
-DescriptorProto::~DescriptorProto() = default;
-DescriptorProto::DescriptorProto(const DescriptorProto&) = default;
-DescriptorProto& DescriptorProto::operator=(const DescriptorProto&) = default;
-DescriptorProto::DescriptorProto(DescriptorProto&&) noexcept = default;
-DescriptorProto& DescriptorProto::operator=(DescriptorProto&&) = default;
-
-bool DescriptorProto::operator==(const DescriptorProto& other) const {
- return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
- && ::protozero::internal::gen_helpers::EqualsField(name_, other.name_)
- && ::protozero::internal::gen_helpers::EqualsField(field_, other.field_)
- && ::protozero::internal::gen_helpers::EqualsField(extension_, other.extension_)
- && ::protozero::internal::gen_helpers::EqualsField(nested_type_, other.nested_type_)
- && ::protozero::internal::gen_helpers::EqualsField(enum_type_, other.enum_type_)
- && ::protozero::internal::gen_helpers::EqualsField(oneof_decl_, other.oneof_decl_)
- && ::protozero::internal::gen_helpers::EqualsField(reserved_range_, other.reserved_range_)
- && ::protozero::internal::gen_helpers::EqualsField(reserved_name_, other.reserved_name_);
-}
+ // This is the reason why there is no ~Message() call here.
+ // MessageArea::Reset() (see header) also relies on dtor being trivial.
+ static_assert(std::is_trivially_destructible<Message>::value,
+ "Message must be trivially destructible");
-int DescriptorProto::field_size() const { return static_cast<int>(field_.size()); }
-void DescriptorProto::clear_field() { field_.clear(); }
-FieldDescriptorProto* DescriptorProto::add_field() { field_.emplace_back(); return &field_.back(); }
-int DescriptorProto::extension_size() const { return static_cast<int>(extension_.size()); }
-void DescriptorProto::clear_extension() { extension_.clear(); }
-FieldDescriptorProto* DescriptorProto::add_extension() { extension_.emplace_back(); return &extension_.back(); }
-int DescriptorProto::nested_type_size() const { return static_cast<int>(nested_type_.size()); }
-void DescriptorProto::clear_nested_type() { nested_type_.clear(); }
-DescriptorProto* DescriptorProto::add_nested_type() { nested_type_.emplace_back(); return &nested_type_.back(); }
-int DescriptorProto::enum_type_size() const { return static_cast<int>(enum_type_.size()); }
-void DescriptorProto::clear_enum_type() { enum_type_.clear(); }
-EnumDescriptorProto* DescriptorProto::add_enum_type() { enum_type_.emplace_back(); return &enum_type_.back(); }
-int DescriptorProto::oneof_decl_size() const { return static_cast<int>(oneof_decl_.size()); }
-void DescriptorProto::clear_oneof_decl() { oneof_decl_.clear(); }
-OneofDescriptorProto* DescriptorProto::add_oneof_decl() { oneof_decl_.emplace_back(); return &oneof_decl_.back(); }
-int DescriptorProto::reserved_range_size() const { return static_cast<int>(reserved_range_.size()); }
-void DescriptorProto::clear_reserved_range() { reserved_range_.clear(); }
-DescriptorProto_ReservedRange* DescriptorProto::add_reserved_range() { reserved_range_.emplace_back(); return &reserved_range_.back(); }
-bool DescriptorProto::ParseFromArray(const void* raw, size_t size) {
- field_.clear();
- extension_.clear();
- nested_type_.clear();
- enum_type_.clear();
- oneof_decl_.clear();
- reserved_range_.clear();
- reserved_name_.clear();
- unknown_fields_.clear();
- bool packed_error = false;
+ --block->entries;
+ PERFETTO_ASAN_POISON(&block->storage[block->entries], sizeof(Message));
- ::protozero::ProtoDecoder dec(raw, size);
- for (auto field = dec.ReadField(); field.valid(); field = dec.ReadField()) {
- if (field.id() < _has_field_.size()) {
- _has_field_.set(field.id());
- }
- switch (field.id()) {
- case 1 /* name */:
- ::protozero::internal::gen_helpers::DeserializeString(field, &name_);
- break;
- case 2 /* field */:
- field_.emplace_back();
- field_.back().ParseFromArray(field.data(), field.size());
- break;
- case 6 /* extension */:
- extension_.emplace_back();
- extension_.back().ParseFromArray(field.data(), field.size());
- break;
- case 3 /* nested_type */:
- nested_type_.emplace_back();
- nested_type_.back().ParseFromArray(field.data(), field.size());
- break;
- case 4 /* enum_type */:
- enum_type_.emplace_back();
- enum_type_.back().ParseFromArray(field.data(), field.size());
- break;
- case 8 /* oneof_decl */:
- oneof_decl_.emplace_back();
- oneof_decl_.back().ParseFromArray(field.data(), field.size());
- break;
- case 9 /* reserved_range */:
- reserved_range_.emplace_back();
- reserved_range_.back().ParseFromArray(field.data(), field.size());
- break;
- case 10 /* reserved_name */:
- reserved_name_.emplace_back();
- ::protozero::internal::gen_helpers::DeserializeString(field, &reserved_name_.back());
- break;
- default:
- field.SerializeAndAppendTo(&unknown_fields_);
- break;
- }
+ // Don't remove the first block to avoid malloc/free calls when the root
+ // message is reset. Hitting the allocator all the times is a waste of time.
+ if (block->entries == 0 && std::next(blocks_.cbegin()) != blocks_.cend()) {
+ blocks_.pop_front();
}
- return !packed_error && !dec.bytes_left();
}
-std::string DescriptorProto::SerializeAsString() const {
- ::protozero::internal::gen_helpers::MessageSerializer msg;
- Serialize(msg.get());
- return msg.SerializeAsString();
+} // namespace protozero
+// gen_amalgamated begin source: src/protozero/packed_repeated_fields.cc
+/*
+ * 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.
+ */
+
+// gen_amalgamated expanded: #include "perfetto/protozero/packed_repeated_fields.h"
+
+// gen_amalgamated expanded: #include "perfetto/ext/base/utils.h"
+
+namespace protozero {
+
+void PackedBufferBase::GrowSlowpath() {
+ size_t write_off = static_cast<size_t>(write_ptr_ - storage_begin_);
+ size_t old_size = static_cast<size_t>(storage_end_ - storage_begin_);
+ size_t new_size = old_size < 65536 ? (old_size * 2) : (old_size * 3 / 2);
+ new_size = perfetto::base::AlignUp<4096>(new_size);
+ std::unique_ptr<uint8_t[]> new_buf(new uint8_t[new_size]);
+ memcpy(new_buf.get(), storage_begin_, old_size);
+ heap_buf_ = std::move(new_buf);
+ storage_begin_ = heap_buf_.get();
+ storage_end_ = storage_begin_ + new_size;
+ write_ptr_ = storage_begin_ + write_off;
}
-std::vector<uint8_t> DescriptorProto::SerializeAsArray() const {
- ::protozero::internal::gen_helpers::MessageSerializer msg;
- Serialize(msg.get());
- return msg.SerializeAsArray();
+void PackedBufferBase::Reset() {
+ heap_buf_.reset();
+ storage_begin_ = reinterpret_cast<uint8_t*>(&stack_buf_[0]);
+ storage_end_ = reinterpret_cast<uint8_t*>(&stack_buf_[kOnStackStorageSize]);
+ write_ptr_ = storage_begin_;
}
-void DescriptorProto::Serialize(::protozero::Message* msg) const {
- // Field 1: name
- if (_has_field_[1]) {
- ::protozero::internal::gen_helpers::SerializeString(1, name_, msg);
- }
+} // namespace protozero
+// gen_amalgamated begin source: src/protozero/proto_decoder.cc
+/*
+ * 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.
+ */
- // Field 2: field
- for (auto& it : field_) {
- it.Serialize(msg->BeginNestedMessage<::protozero::Message>(2));
- }
+// gen_amalgamated expanded: #include "perfetto/protozero/proto_decoder.h"
- // Field 6: extension
- for (auto& it : extension_) {
- it.Serialize(msg->BeginNestedMessage<::protozero::Message>(6));
- }
+#include <string.h>
- // Field 3: nested_type
- for (auto& it : nested_type_) {
- it.Serialize(msg->BeginNestedMessage<::protozero::Message>(3));
- }
+#include <cinttypes>
+#include <limits>
+#include <memory>
- // Field 4: enum_type
- for (auto& it : enum_type_) {
- it.Serialize(msg->BeginNestedMessage<::protozero::Message>(4));
- }
+// gen_amalgamated expanded: #include "perfetto/base/compiler.h"
+// gen_amalgamated expanded: #include "perfetto/base/logging.h"
+// gen_amalgamated expanded: #include "perfetto/ext/base/utils.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/proto_utils.h"
+// gen_amalgamated expanded: #include "perfetto/public/compiler.h"
- // Field 8: oneof_decl
- for (auto& it : oneof_decl_) {
- it.Serialize(msg->BeginNestedMessage<::protozero::Message>(8));
- }
+namespace protozero {
- // Field 9: reserved_range
- for (auto& it : reserved_range_) {
- it.Serialize(msg->BeginNestedMessage<::protozero::Message>(9));
- }
+using namespace proto_utils;
- // Field 10: reserved_name
- for (auto& it : reserved_name_) {
- ::protozero::internal::gen_helpers::SerializeString(10, it, msg);
- }
+const Field TypedProtoDecoderBase::kInvalidField{};
- protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
-}
+namespace {
+struct ParseFieldResult {
+ enum ParseResult { kAbort, kSkip, kOk };
+ ParseResult parse_res;
+ const uint8_t* next;
+ Field field;
+};
-DescriptorProto_ReservedRange::DescriptorProto_ReservedRange() = default;
-DescriptorProto_ReservedRange::~DescriptorProto_ReservedRange() = default;
-DescriptorProto_ReservedRange::DescriptorProto_ReservedRange(const DescriptorProto_ReservedRange&) = default;
-DescriptorProto_ReservedRange& DescriptorProto_ReservedRange::operator=(const DescriptorProto_ReservedRange&) = default;
-DescriptorProto_ReservedRange::DescriptorProto_ReservedRange(DescriptorProto_ReservedRange&&) noexcept = default;
-DescriptorProto_ReservedRange& DescriptorProto_ReservedRange::operator=(DescriptorProto_ReservedRange&&) = default;
+// Parses one field and returns the field itself and a pointer to the next
+// field to parse. If parsing fails, the returned |next| == |buffer|.
+// Force-inlined so that, after inlining, the result struct is decomposed by
+// the compiler and does not round-trip through memory.
+PERFETTO_ALWAYS_INLINE ParseFieldResult
+ParseOneField(const uint8_t* const buffer, const uint8_t* const end) {
+ ParseFieldResult res{ParseFieldResult::kAbort, buffer, Field{}};
-bool DescriptorProto_ReservedRange::operator==(const DescriptorProto_ReservedRange& other) const {
- return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
- && ::protozero::internal::gen_helpers::EqualsField(start_, other.start_)
- && ::protozero::internal::gen_helpers::EqualsField(end_, other.end_);
-}
+ const uint8_t* pos = buffer;
-bool DescriptorProto_ReservedRange::ParseFromArray(const void* raw, size_t size) {
- unknown_fields_.clear();
- bool packed_error = false;
+ // If we've already hit the end, just return an invalid field.
+ if (PERFETTO_UNLIKELY(pos >= end))
+ return res;
- ::protozero::ProtoDecoder dec(raw, size);
- for (auto field = dec.ReadField(); field.valid(); field = dec.ReadField()) {
- if (field.id() < _has_field_.size()) {
- _has_field_.set(field.id());
- }
- switch (field.id()) {
- case 1 /* start */:
- field.get(&start_);
- break;
- case 2 /* end */:
- field.get(&end_);
- break;
- default:
- field.SerializeAndAppendTo(&unknown_fields_);
- break;
- }
+ uint64_t preamble = 0;
+ if (PERFETTO_LIKELY(*pos < 0x80)) { // Fastpath for fields with ID < 16.
+ preamble = *(pos++);
+ } else {
+ const uint8_t* next = ParseVarIntFast(pos, end, &preamble);
+ if (PERFETTO_UNLIKELY(!next))
+ return res;
+ pos = next;
}
- return !packed_error && !dec.bytes_left();
-}
-std::string DescriptorProto_ReservedRange::SerializeAsString() const {
- ::protozero::internal::gen_helpers::MessageSerializer msg;
- Serialize(msg.get());
- return msg.SerializeAsString();
-}
+ uint32_t field_id =
+ static_cast<uint32_t>(proto_utils::GetTagFieldId(preamble));
+ if (field_id == 0 || pos >= end)
+ return res;
-std::vector<uint8_t> DescriptorProto_ReservedRange::SerializeAsArray() const {
- ::protozero::internal::gen_helpers::MessageSerializer msg;
- Serialize(msg.get());
- return msg.SerializeAsArray();
-}
+ auto field_type =
+ static_cast<uint8_t>(proto_utils::GetTagFieldType(preamble));
+ const uint8_t* new_pos = pos;
+ uint64_t int_value = 0;
+ uint64_t size = 0;
-void DescriptorProto_ReservedRange::Serialize(::protozero::Message* msg) const {
- // Field 1: start
- if (_has_field_[1]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(1, start_, msg);
- }
+ // If-chain ordered by observed frequency: wire types within a message are
+ // near-constant, so these branches predict better than a switch jump.
+ if (PERFETTO_LIKELY(field_type ==
+ static_cast<uint8_t>(ProtoWireType::kVarInt))) {
+ new_pos = ParseVarIntFast(pos, end, &int_value);
- // Field 2: end
- if (_has_field_[2]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(2, end_, msg);
+ // new_pos being null means ParseVarIntFast could not fully parse the
+ // number. This is because we are out of space in the buffer. Set the id
+ // to zero and return but don't update the offset so a future read can
+ // read this field.
+ if (PERFETTO_UNLIKELY(!new_pos))
+ return res;
+ } else if (PERFETTO_LIKELY(
+ field_type ==
+ static_cast<uint8_t>(ProtoWireType::kLengthDelimited))) {
+ uint64_t payload_length;
+ new_pos = ParseVarIntFast(pos, end, &payload_length);
+ if (PERFETTO_UNLIKELY(!new_pos))
+ return res;
+
+ // ParseVarIntFast guarantees that |new_pos| <= |end| when it succeeds;
+ if (payload_length > static_cast<uint64_t>(end - new_pos))
+ return res;
+
+ const uintptr_t payload_start = reinterpret_cast<uintptr_t>(new_pos);
+ int_value = payload_start;
+ size = payload_length;
+ new_pos += payload_length;
+ } else if (field_type == static_cast<uint8_t>(ProtoWireType::kFixed64)) {
+ new_pos = pos + sizeof(uint64_t);
+ if (PERFETTO_UNLIKELY(new_pos > end))
+ return res;
+ memcpy(&int_value, pos, sizeof(uint64_t));
+ int_value = perfetto::base::LE64ToHost(int_value);
+ } else if (field_type == static_cast<uint8_t>(ProtoWireType::kFixed32)) {
+ new_pos = pos + sizeof(uint32_t);
+ if (PERFETTO_UNLIKELY(new_pos > end))
+ return res;
+ uint32_t value32;
+ memcpy(&value32, pos, sizeof(uint32_t));
+ int_value = perfetto::base::LE32ToHost(value32);
+ } else {
+ PERFETTO_DLOG("Invalid proto field type: %u", field_type);
+ return res;
}
- protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
-}
+ res.next = new_pos;
+ if (PERFETTO_UNLIKELY(field_id > Field::kMaxId)) {
+ PERFETTO_DLOG("Skipping field %" PRIu32 " because its id > %" PRIu32,
+ field_id, Field::kMaxId);
+ res.parse_res = ParseFieldResult::kSkip;
+ return res;
+ }
-FileDescriptorProto::FileDescriptorProto() = default;
-FileDescriptorProto::~FileDescriptorProto() = default;
-FileDescriptorProto::FileDescriptorProto(const FileDescriptorProto&) = default;
-FileDescriptorProto& FileDescriptorProto::operator=(const FileDescriptorProto&) = default;
-FileDescriptorProto::FileDescriptorProto(FileDescriptorProto&&) noexcept = default;
-FileDescriptorProto& FileDescriptorProto::operator=(FileDescriptorProto&&) = default;
+ if (PERFETTO_UNLIKELY(size > proto_utils::kMaxMessageLength)) {
+ PERFETTO_DLOG("Skipping field %" PRIu32 " because it's too big (%" PRIu64
+ " KB)",
+ field_id, size / 1024);
+ res.parse_res = ParseFieldResult::kSkip;
+ return res;
+ }
-bool FileDescriptorProto::operator==(const FileDescriptorProto& other) const {
- return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
- && ::protozero::internal::gen_helpers::EqualsField(name_, other.name_)
- && ::protozero::internal::gen_helpers::EqualsField(package_, other.package_)
- && ::protozero::internal::gen_helpers::EqualsField(dependency_, other.dependency_)
- && ::protozero::internal::gen_helpers::EqualsField(public_dependency_, other.public_dependency_)
- && ::protozero::internal::gen_helpers::EqualsField(weak_dependency_, other.weak_dependency_)
- && ::protozero::internal::gen_helpers::EqualsField(message_type_, other.message_type_)
- && ::protozero::internal::gen_helpers::EqualsField(enum_type_, other.enum_type_)
- && ::protozero::internal::gen_helpers::EqualsField(extension_, other.extension_);
+ res.parse_res = ParseFieldResult::kOk;
+ res.field.initialize(field_id, field_type, int_value,
+ static_cast<uint32_t>(size));
+ return res;
}
-int FileDescriptorProto::message_type_size() const { return static_cast<int>(message_type_.size()); }
-void FileDescriptorProto::clear_message_type() { message_type_.clear(); }
-DescriptorProto* FileDescriptorProto::add_message_type() { message_type_.emplace_back(); return &message_type_.back(); }
-int FileDescriptorProto::enum_type_size() const { return static_cast<int>(enum_type_.size()); }
-void FileDescriptorProto::clear_enum_type() { enum_type_.clear(); }
-EnumDescriptorProto* FileDescriptorProto::add_enum_type() { enum_type_.emplace_back(); return &enum_type_.back(); }
-int FileDescriptorProto::extension_size() const { return static_cast<int>(extension_.size()); }
-void FileDescriptorProto::clear_extension() { extension_.clear(); }
-FieldDescriptorProto* FileDescriptorProto::add_extension() { extension_.emplace_back(); return &extension_.back(); }
-bool FileDescriptorProto::ParseFromArray(const void* raw, size_t size) {
- dependency_.clear();
- public_dependency_.clear();
- weak_dependency_.clear();
- message_type_.clear();
- enum_type_.clear();
- extension_.clear();
- unknown_fields_.clear();
- bool packed_error = false;
+// Grows the selective-decoding spill area once the inline slots are
+// exhausted, moving the spilled fields to the heap. The append itself is
+// open-coded in the decode loop; see the comment there.
+PERFETTO_NO_INLINE void ExpandSpill(Field** spill,
+ uint32_t* spill_capacity,
+ uint32_t spill_size,
+ std::unique_ptr<Field[]>* heap_spill) {
+ // Double the capacity, with a floor so that an exhausted spill that somehow
+ // starts from zero capacity (e.g. a moved-from state) doesn't keep doubling
+ // zero. The floor matches SelectiveTypedProtoDecoder::kSpillStackCapacity.
+ const uint32_t new_capacity = std::max(*spill_capacity * 2, 16u);
+ PERFETTO_CHECK(new_capacity > spill_size);
+ std::unique_ptr<Field[]> new_storage(new Field[new_capacity]);
+ if (spill_size > 0)
+ memcpy(&new_storage[0], *spill, sizeof(Field) * spill_size);
+ *heap_spill = std::move(new_storage);
+ *spill = &(*heap_spill)[0];
+ *spill_capacity = new_capacity;
+}
- ::protozero::ProtoDecoder dec(raw, size);
- for (auto field = dec.ReadField(); field.valid(); field = dec.ReadField()) {
- if (field.id() < _has_field_.size()) {
- _has_field_.set(field.id());
- }
- switch (field.id()) {
- case 1 /* name */:
- ::protozero::internal::gen_helpers::DeserializeString(field, &name_);
- break;
- case 2 /* package */:
- ::protozero::internal::gen_helpers::DeserializeString(field, &package_);
- break;
- case 3 /* dependency */:
- dependency_.emplace_back();
- ::protozero::internal::gen_helpers::DeserializeString(field, &dependency_.back());
- break;
- case 10 /* public_dependency */:
- public_dependency_.emplace_back();
- field.get(&public_dependency_.back());
- break;
- case 11 /* weak_dependency */:
- weak_dependency_.emplace_back();
- field.get(&weak_dependency_.back());
- break;
- case 4 /* message_type */:
- message_type_.emplace_back();
- message_type_.back().ParseFromArray(field.data(), field.size());
- break;
- case 5 /* enum_type */:
- enum_type_.emplace_back();
- enum_type_.back().ParseFromArray(field.data(), field.size());
- break;
- case 7 /* extension */:
- extension_.emplace_back();
- extension_.back().ParseFromArray(field.data(), field.size());
- break;
- default:
- field.SerializeAndAppendTo(&unknown_fields_);
- break;
+} // namespace
+
+Field ProtoDecoder::FindField(uint32_t field_id) {
+ Field res{};
+ auto old_position = read_ptr_;
+ read_ptr_ = begin_;
+ for (auto f = ReadField(); f.valid(); f = ReadField()) {
+ if (f.id() == field_id) {
+ res = f;
+ break;
}
}
- return !packed_error && !dec.bytes_left();
+ read_ptr_ = old_position;
+ return res;
}
-std::string FileDescriptorProto::SerializeAsString() const {
- ::protozero::internal::gen_helpers::MessageSerializer msg;
- Serialize(msg.get());
- return msg.SerializeAsString();
+Field ProtoDecoder::ReadField() {
+ ParseFieldResult res;
+ do {
+ res = ParseOneField(read_ptr_, end_);
+ read_ptr_ = res.next;
+ } while (PERFETTO_UNLIKELY(res.parse_res == ParseFieldResult::kSkip));
+ return res.field;
}
-std::vector<uint8_t> FileDescriptorProto::SerializeAsArray() const {
- ::protozero::internal::gen_helpers::MessageSerializer msg;
- Serialize(msg.get());
- return msg.SerializeAsArray();
+void TypedProtoDecoderBase::ParseAllFields() {
+ ParseAllFieldsImpl<false>(nullptr, nullptr, nullptr, nullptr, nullptr);
}
-void FileDescriptorProto::Serialize(::protozero::Message* msg) const {
- // Field 1: name
- if (_has_field_[1]) {
- ::protozero::internal::gen_helpers::SerializeString(1, name_, msg);
- }
+void TypedProtoDecoderBase::ParseAllFieldsSelective(
+ const uint64_t* dense_mask,
+ Field** spill,
+ uint32_t* spill_capacity,
+ uint32_t* spill_size,
+ std::unique_ptr<Field[]>* heap_spill) {
+ PERFETTO_DCHECK(dense_mask && spill && spill_capacity && spill_size &&
+ heap_spill);
+ ParseAllFieldsImpl<true>(dense_mask, spill, spill_capacity, spill_size,
+ heap_spill);
+}
- // Field 2: package
- if (_has_field_[2]) {
- ::protozero::internal::gen_helpers::SerializeString(2, package_, msg);
- }
+// Force-inlined into the two thin entry points above: the plain
+// instantiation compiles to a loop with no trace of the mask support and
+// the wrappers' arguments fold away entirely.
+template <bool kSelective>
+PERFETTO_ALWAYS_INLINE void TypedProtoDecoderBase::ParseAllFieldsImpl(
+ const uint64_t* dense_mask,
+ Field** spill,
+ uint32_t* spill_capacity,
+ uint32_t* spill_size,
+ std::unique_ptr<Field[]>* heap_spill) {
+ const uint8_t* cur = begin_;
+ ParseFieldResult res;
+ for (;;) {
+ res = ParseOneField(cur, end_);
+ PERFETTO_DCHECK(res.parse_res != ParseFieldResult::kOk || res.next != cur);
+ cur = res.next;
+ if (PERFETTO_UNLIKELY(res.parse_res == ParseFieldResult::kSkip))
+ continue;
+ if (PERFETTO_UNLIKELY(res.parse_res == ParseFieldResult::kAbort))
+ break;
- // Field 3: dependency
- for (auto& it : dependency_) {
- ::protozero::internal::gen_helpers::SerializeString(3, it, msg);
- }
+ PERFETTO_DCHECK(res.parse_res == ParseFieldResult::kOk);
+ PERFETTO_DCHECK(res.field.valid());
+ auto field_id = res.field.id();
+ if constexpr (kSelective) {
+ // Selective decoding: only allowlisted in-range ids go to the dense
+ // storage; everything else (including ids beyond the in-tree range) is
+ // appended, in wire order, to the spill area. |num_fields_| is capped
+ // at the mask's extent by SelectiveTypedProtoDecoder, so this also
+ // bounds the mask read.
+ const bool dense =
+ field_id < num_fields_ &&
+ (dense_mask[field_id / 64] & (1ULL << (field_id % 64))) != 0;
+ if (!dense) {
+ // The spill append is open-coded from the field's scalar components:
+ // a function taking the whole Field (by value or reference) makes
+ // the compiler materialize the packed Field representation on every
+ // loop iteration, including for fields that are not spilled.
+ if (PERFETTO_UNLIKELY(*spill_size >= *spill_capacity))
+ ExpandSpill(spill, spill_capacity, *spill_size, heap_spill);
+ (*spill)[(*spill_size)++].initialize(
+ field_id, static_cast<uint8_t>(res.field.type()),
+ res.field.raw_int_value(), res.field.raw_size());
+ continue;
+ }
+ } else if (PERFETTO_UNLIKELY(field_id >= num_fields_)) {
+ // Fields with an id beyond the highest field id known in-tree at compile
+ // time are out-of-tree "extension" fields (e.g. carved out of
+ // TracePacket's `extensions 1000 to 1999` range). They are intentionally
+ // not stored here because fields_ is indexed directly by field id, and
+ // extension ids are sparse and potentially very high. Callers that need
+ // them should decode selectively and consume them from unknown_fields().
+ has_out_of_range_fields_ = true;
+ continue;
+ }
- // Field 10: public_dependency
- for (auto& it : public_dependency_) {
- ::protozero::internal::gen_helpers::SerializeVarInt(10, it, msg);
- }
+ // There are two reasons why we might want to expand the heap capacity:
+ // 1. We are writing a non-repeated field, which has an id >
+ // INITIAL_STACK_CAPACITY. In this case ExpandHeapStorage() ensures to
+ // allocate at least (num_fields_ + 1) slots.
+ // 2. We are writing a repeated field but ran out of capacity.
+ if (PERFETTO_UNLIKELY(field_id >= size_ || size_ >= capacity_))
+ ExpandHeapStorage();
- // Field 11: weak_dependency
- for (auto& it : weak_dependency_) {
- ::protozero::internal::gen_helpers::SerializeVarInt(11, it, msg);
- }
+ PERFETTO_DCHECK(field_id < size_);
+ Field* fld = &fields_[field_id];
+ if (PERFETTO_LIKELY(!HasField(field_id))) {
+ // This is the first time we see this field.
+ SetField(field_id);
+ *fld = std::move(res.field);
+ } else {
+ // Repeated field case.
+ // In this case we need to:
+ // 1. Append the last value of the field to end of the repeated field
+ // storage.
+ // 2. Replace the default instance at offset |field_id| with the current
+ // value. This is because in case of repeated field a call to Get(X) is
+ // supposed to return the last value of X, not the first one.
+ // This is so that the RepeatedFieldIterator will iterate in the right
+ // order, see comments on RepeatedFieldIterator.
+ if (num_fields_ > size_) {
+ ExpandHeapStorage();
+ fld = &fields_[field_id];
+ }
- // Field 4: message_type
- for (auto& it : message_type_) {
- it.Serialize(msg->BeginNestedMessage<::protozero::Message>(4));
+ PERFETTO_DCHECK(size_ < capacity_);
+ fields_[size_++] = *fld;
+ *fld = std::move(res.field);
+ }
}
+ read_ptr_ = res.next;
+}
- // Field 5: enum_type
- for (auto& it : enum_type_) {
- it.Serialize(msg->BeginNestedMessage<::protozero::Message>(5));
- }
+void TypedProtoDecoderBase::ExpandHeapStorage() {
+ // When we expand the heap we must ensure that we have at very last capacity
+ // to deal with all known fields plus at least one repeated field. We go +2048
+ // here based on observations on a large 4GB android trace. This is to avoid
+ // trivial re-allocations when dealing with repeated fields of a message that
+ // has > INITIAL_STACK_CAPACITY fields.
+ const uint32_t min_capacity = num_fields_ + 2048; // Any num >= +1 will do.
+ const uint32_t new_capacity = std::max(capacity_ * 2, min_capacity);
+ PERFETTO_CHECK(new_capacity > size_ && new_capacity > num_fields_);
+ std::unique_ptr<Field[]> new_storage(new Field[new_capacity]);
- // Field 7: extension
- for (auto& it : extension_) {
- it.Serialize(msg->BeginNestedMessage<::protozero::Message>(7));
- }
+ static_assert(std::is_trivially_constructible<Field>::value,
+ "Field must be trivially constructible");
+ static_assert(std::is_trivially_copyable<Field>::value,
+ "Field must be trivially copyable");
- protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
+ // There is no need to initialize the slots for known field IDs: reads of
+ // them are gated on the presence bitmap. There is also no need to initialize
+ // the repeated slots, because they are written linearly with no gaps and are
+ // always initialized before incrementing |size_|.
+ const uint32_t new_size = std::max(size_, num_fields_);
+ memcpy(&new_storage[0], fields_, sizeof(Field) * size_);
+
+ heap_storage_ = std::move(new_storage);
+ fields_ = &heap_storage_[0];
+ capacity_ = new_capacity;
+ size_ = new_size;
+}
+
+} // namespace protozero
+// gen_amalgamated begin source: src/protozero/scattered_heap_buffer.cc
+/*
+ * 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.
+ */
+
+// gen_amalgamated expanded: #include "perfetto/protozero/scattered_heap_buffer.h"
+
+#include <algorithm>
+
+namespace protozero {
+
+ScatteredHeapBuffer::Slice::Slice()
+ : buffer_(nullptr), size_(0u), unused_bytes_(0u) {}
+
+ScatteredHeapBuffer::Slice::Slice(size_t size)
+ : buffer_(std::unique_ptr<uint8_t[]>(new uint8_t[size])),
+ size_(size),
+ unused_bytes_(size) {
+ PERFETTO_DCHECK(size);
+ Clear();
}
+ScatteredHeapBuffer::Slice::Slice(Slice&& slice) noexcept = default;
-FileDescriptorSet::FileDescriptorSet() = default;
-FileDescriptorSet::~FileDescriptorSet() = default;
-FileDescriptorSet::FileDescriptorSet(const FileDescriptorSet&) = default;
-FileDescriptorSet& FileDescriptorSet::operator=(const FileDescriptorSet&) = default;
-FileDescriptorSet::FileDescriptorSet(FileDescriptorSet&&) noexcept = default;
-FileDescriptorSet& FileDescriptorSet::operator=(FileDescriptorSet&&) = default;
+ScatteredHeapBuffer::Slice::~Slice() = default;
-bool FileDescriptorSet::operator==(const FileDescriptorSet& other) const {
- return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
- && ::protozero::internal::gen_helpers::EqualsField(file_, other.file_);
+ScatteredHeapBuffer::Slice& ScatteredHeapBuffer::Slice::operator=(Slice&&) =
+ default;
+
+void ScatteredHeapBuffer::Slice::Clear() {
+ unused_bytes_ = size_;
+#if PERFETTO_DCHECK_IS_ON()
+ memset(start(), 0xff, size_);
+#endif // PERFETTO_DCHECK_IS_ON()
}
-int FileDescriptorSet::file_size() const { return static_cast<int>(file_.size()); }
-void FileDescriptorSet::clear_file() { file_.clear(); }
-FileDescriptorProto* FileDescriptorSet::add_file() { file_.emplace_back(); return &file_.back(); }
-bool FileDescriptorSet::ParseFromArray(const void* raw, size_t size) {
- file_.clear();
- unknown_fields_.clear();
- bool packed_error = false;
+ScatteredHeapBuffer::ScatteredHeapBuffer(size_t initial_slice_size_bytes,
+ size_t maximum_slice_size_bytes)
+ : next_slice_size_(initial_slice_size_bytes),
+ maximum_slice_size_(maximum_slice_size_bytes) {
+ PERFETTO_DCHECK(next_slice_size_ && maximum_slice_size_);
+ PERFETTO_DCHECK(maximum_slice_size_ >= initial_slice_size_bytes);
+}
- ::protozero::ProtoDecoder dec(raw, size);
- for (auto field = dec.ReadField(); field.valid(); field = dec.ReadField()) {
- if (field.id() < _has_field_.size()) {
- _has_field_.set(field.id());
- }
- switch (field.id()) {
- case 1 /* file */:
- file_.emplace_back();
- file_.back().ParseFromArray(field.data(), field.size());
- break;
- default:
- field.SerializeAndAppendTo(&unknown_fields_);
- break;
- }
+ScatteredHeapBuffer::~ScatteredHeapBuffer() = default;
+
+protozero::ContiguousMemoryRange ScatteredHeapBuffer::GetNewBuffer() {
+ PERFETTO_CHECK(writer_);
+ AdjustUsedSizeOfCurrentSlice();
+
+ if (cached_slice_.start()) {
+ slices_.push_back(std::move(cached_slice_));
+ PERFETTO_DCHECK(!cached_slice_.start());
+ } else {
+ slices_.emplace_back(next_slice_size_);
}
- return !packed_error && !dec.bytes_left();
+ next_slice_size_ = std::min(maximum_slice_size_, next_slice_size_ * 2);
+ return slices_.back().GetTotalRange();
}
-std::string FileDescriptorSet::SerializeAsString() const {
- ::protozero::internal::gen_helpers::MessageSerializer msg;
- Serialize(msg.get());
- return msg.SerializeAsString();
+const std::vector<ScatteredHeapBuffer::Slice>&
+ScatteredHeapBuffer::GetSlices() {
+ AdjustUsedSizeOfCurrentSlice();
+ return slices_;
}
-std::vector<uint8_t> FileDescriptorSet::SerializeAsArray() const {
- ::protozero::internal::gen_helpers::MessageSerializer msg;
- Serialize(msg.get());
- return msg.SerializeAsArray();
+std::vector<ScatteredHeapBuffer::Slice> ScatteredHeapBuffer::TakeSlices() {
+ AdjustUsedSizeOfCurrentSlice();
+ std::vector<Slice> slices = std::move(slices_);
+ slices_.clear();
+ if (writer_)
+ writer_->Reset(protozero::ContiguousMemoryRange{});
+ return slices;
}
-void FileDescriptorSet::Serialize(::protozero::Message* msg) const {
- // Field 1: file
- for (auto& it : file_) {
- it.Serialize(msg->BeginNestedMessage<::protozero::Message>(1));
- }
+std::vector<uint8_t> ScatteredHeapBuffer::StitchSlices() {
+ size_t stitched_size = 0u;
+ const auto& slices = GetSlices();
+ for (const auto& slice : slices)
+ stitched_size += slice.size() - slice.unused_bytes();
- protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
+ std::vector<uint8_t> buffer;
+ buffer.reserve(stitched_size);
+ for (const auto& slice : slices) {
+ auto used_range = slice.GetUsedRange();
+ buffer.insert(buffer.end(), used_range.begin, used_range.end);
+ }
+ return buffer;
}
-} // namespace perfetto
-} // namespace protos
-} // namespace gen
-#if defined(__GNUC__) || defined(__clang__)
-#pragma GCC diagnostic pop
+std::pair<std::unique_ptr<uint8_t[]>, size_t>
+ScatteredHeapBuffer::StitchAsUniquePtr() {
+ size_t stitched_size = 0u;
+ const auto& slices = GetSlices();
+ for (const auto& slice : slices)
+ stitched_size += slice.size() - slice.unused_bytes();
+
+ std::unique_ptr<uint8_t[]> buffer(new uint8_t[stitched_size]);
+ uint8_t* ptr = buffer.get();
+ for (const auto& slice : slices) {
+ auto used_range = slice.GetUsedRange();
+ memcpy(ptr, used_range.begin, used_range.size());
+ ptr += used_range.size();
+ }
+
+ return std::make_pair(std::move(buffer), stitched_size);
+}
+
+std::vector<protozero::ContiguousMemoryRange> ScatteredHeapBuffer::GetRanges() {
+ std::vector<protozero::ContiguousMemoryRange> ranges;
+ for (const auto& slice : GetSlices())
+ ranges.push_back(slice.GetUsedRange());
+ return ranges;
+}
+
+void ScatteredHeapBuffer::AdjustUsedSizeOfCurrentSlice() {
+ if (!slices_.empty())
+ slices_.back().set_unused_bytes(writer_->bytes_available());
+}
+
+size_t ScatteredHeapBuffer::GetTotalSize() {
+ size_t total_size = 0;
+ for (auto& slice : slices_) {
+ total_size += slice.size();
+ }
+ return total_size;
+}
+
+void ScatteredHeapBuffer::Reset() {
+ if (slices_.empty())
+ return;
+ cached_slice_ = std::move(slices_.front());
+ cached_slice_.Clear();
+ slices_.clear();
+}
+
+} // namespace protozero
+// gen_amalgamated begin source: src/protozero/scattered_stream_null_delegate.cc
+/*
+ * 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.
+ */
+
+// gen_amalgamated expanded: #include "perfetto/protozero/scattered_stream_null_delegate.h"
+
+namespace protozero {
+
+// An implementation of ScatteredStreamWriter::Delegate which always returns
+// the same piece of memory.
+// This is used when we need to no-op the writers (e.g. during teardown or in
+// case of resource exhaustion), avoiding that the clients have to deal with
+// nullptr checks.
+ScatteredStreamWriterNullDelegate::ScatteredStreamWriterNullDelegate(
+ size_t chunk_size)
+ : chunk_size_(chunk_size),
+ chunk_(std::unique_ptr<uint8_t[]>(new uint8_t[chunk_size_])) {}
+
+ScatteredStreamWriterNullDelegate::~ScatteredStreamWriterNullDelegate() {}
+
+ContiguousMemoryRange ScatteredStreamWriterNullDelegate::GetNewBuffer() {
+ return {chunk_.get(), chunk_.get() + chunk_size_};
+}
+
+} // namespace protozero
+// gen_amalgamated begin source: src/protozero/scattered_stream_writer.cc
+/*
+ * 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.
+ */
+
+// gen_amalgamated expanded: #include "perfetto/protozero/scattered_stream_writer.h"
+
+#include <algorithm>
+
+// gen_amalgamated expanded: #include "perfetto/base/logging.h"
+
+namespace protozero {
+
+ScatteredStreamWriter::Delegate::~Delegate() {}
+
+uint8_t* ScatteredStreamWriter::Delegate::AnnotatePatch(uint8_t* patch_addr) {
+ // In most cases, a patch is transparent. The caller can write directly into
+ // `to_patch`, because its memory is not going away. TraceWriterImpl, however,
+ // requires a more complicated logic, because the chunks might be copied
+ // earlier.
+ return patch_addr;
+}
+
+ScatteredStreamWriter::ScatteredStreamWriter(Delegate* delegate)
+ : delegate_(delegate),
+ cur_range_({nullptr, nullptr}),
+ write_ptr_(nullptr) {}
+
+ScatteredStreamWriter::~ScatteredStreamWriter() {}
+
+void ScatteredStreamWriter::Reset(ContiguousMemoryRange range) {
+ written_previously_ += static_cast<uint64_t>(write_ptr_ - cur_range_.begin);
+ cur_range_ = range;
+ write_ptr_ = range.begin;
+ PERFETTO_DCHECK(!write_ptr_ || write_ptr_ < cur_range_.end);
+}
+
+void ScatteredStreamWriter::Extend() {
+ Reset(delegate_->GetNewBuffer());
+}
+
+void ScatteredStreamWriter::WriteBytesSlowPath(const uint8_t* src,
+ size_t size) {
+ size_t bytes_left = size;
+ while (bytes_left > 0) {
+ if (write_ptr_ >= cur_range_.end)
+ Extend();
+ const size_t burst_size = std::min(bytes_available(), bytes_left);
+ WriteBytesUnsafe(src, burst_size);
+ bytes_left -= burst_size;
+ src += burst_size;
+ }
+}
+
+// TODO(primiano): perf optimization: I suspect that at the end this will always
+// be called with |size| == 4, in which case we might just hardcode it.
+uint8_t* ScatteredStreamWriter::ReserveBytes(size_t size) {
+ PERFETTO_DCHECK(write_ptr_ <= cur_range_.end);
+ if (size > static_cast<size_t>(cur_range_.end - write_ptr_)) {
+ // Assume the reservations are always < Delegate::GetNewBuffer().size(),
+ // so that one single call to Extend() will definitely give enough headroom.
+ Extend();
+ PERFETTO_DCHECK(write_ptr_ <= cur_range_.end);
+ PERFETTO_DCHECK(size <= static_cast<size_t>(cur_range_.end - write_ptr_));
+ }
+ uint8_t* begin = write_ptr_;
+ write_ptr_ += size;
+#if PERFETTO_DCHECK_IS_ON()
+ // In the past, the service had a matching DCHECK in
+ // TraceBuffer::TryPatchChunkContents, which was assuming that service and all
+ // producers are built with matching DCHECK levels. This turned out to be a
+ // source of problems and was removed in b/197340286. This memset is useless
+ // these days and is here only to maintain ABI compatibility between producers
+ // that use a v20+ SDK and older versions of the service that were built in
+ // debug mode. At some point around 2023 it should be safe to remove it.
+ // (running a debug version of traced in production seems a bad idea
+ // regardless).
+ memset(begin, 0, size);
#endif
-// gen_amalgamated begin source: gen/protos/perfetto/common/ftrace_descriptor.gen.cc
+ return begin;
+}
+
+} // namespace protozero
+// gen_amalgamated begin source: src/protozero/static_buffer.cc
+/*
+ * 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.
+ */
+
+// gen_amalgamated expanded: #include "perfetto/protozero/static_buffer.h"
+
+// gen_amalgamated expanded: #include "perfetto/base/logging.h"
+
+namespace protozero {
+
+StaticBufferDelegate::~StaticBufferDelegate() = default;
+
+ContiguousMemoryRange StaticBufferDelegate::GetNewBuffer() {
+ if (get_new_buffer_called_once_) {
+ // This is the 2nd time GetNewBuffer is called. The estimate is wrong. We
+ // shouldn't try to grow the buffer after the initial call.
+ PERFETTO_FATAL("Static buffer too small");
+ }
+ get_new_buffer_called_once_ = true;
+ return range_;
+}
+
+} // namespace protozero
+// gen_amalgamated begin source: src/protozero/virtual_destructors.cc
+/*
+ * 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.
+ */
+
+// gen_amalgamated expanded: #include "perfetto/protozero/cpp_message_obj.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/message_handle.h"
+
+namespace protozero {
+
+CppMessageObj::~CppMessageObj() = default;
+MessageFinalizationListener::~MessageFinalizationListener() = default;
+
+} // namespace protozero
+// gen_amalgamated begin source: gen/protos/perfetto/protovm/vm_program.gen.cc
// gen_amalgamated expanded: #include "perfetto/protozero/gen_field_helpers.h"
// gen_amalgamated expanded: #include "perfetto/protozero/message.h"
// gen_amalgamated expanded: #include "perfetto/protozero/packed_repeated_fields.h"
@@ -17917,29 +18192,24 @@ void FileDescriptorSet::Serialize(::protozero::Message* msg) const {
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wfloat-equal"
#endif
-// gen_amalgamated expanded: #include "protos/perfetto/common/ftrace_descriptor.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/protovm/vm_program.gen.h"
namespace perfetto {
namespace protos {
namespace gen {
-FtraceDescriptor::FtraceDescriptor() = default;
-FtraceDescriptor::~FtraceDescriptor() = default;
-FtraceDescriptor::FtraceDescriptor(const FtraceDescriptor&) = default;
-FtraceDescriptor& FtraceDescriptor::operator=(const FtraceDescriptor&) = default;
-FtraceDescriptor::FtraceDescriptor(FtraceDescriptor&&) noexcept = default;
-FtraceDescriptor& FtraceDescriptor::operator=(FtraceDescriptor&&) = default;
+VmOpDel::VmOpDel() = default;
+VmOpDel::~VmOpDel() = default;
+VmOpDel::VmOpDel(const VmOpDel&) = default;
+VmOpDel& VmOpDel::operator=(const VmOpDel&) = default;
+VmOpDel::VmOpDel(VmOpDel&&) noexcept = default;
+VmOpDel& VmOpDel::operator=(VmOpDel&&) = default;
-bool FtraceDescriptor::operator==(const FtraceDescriptor& other) const {
- return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
- && ::protozero::internal::gen_helpers::EqualsField(atrace_categories_, other.atrace_categories_);
+bool VmOpDel::operator==(const VmOpDel& other) const {
+ return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_);
}
-int FtraceDescriptor::atrace_categories_size() const { return static_cast<int>(atrace_categories_.size()); }
-void FtraceDescriptor::clear_atrace_categories() { atrace_categories_.clear(); }
-FtraceDescriptor_AtraceCategory* FtraceDescriptor::add_atrace_categories() { atrace_categories_.emplace_back(); return &atrace_categories_.back(); }
-bool FtraceDescriptor::ParseFromArray(const void* raw, size_t size) {
- atrace_categories_.clear();
+bool VmOpDel::ParseFromArray(const void* raw, size_t size) {
unknown_fields_.clear();
bool packed_error = false;
@@ -17949,10 +18219,6 @@ bool FtraceDescriptor::ParseFromArray(const void* raw, size_t size) {
_has_field_.set(field.id());
}
switch (field.id()) {
- case 1 /* atrace_categories */:
- atrace_categories_.emplace_back();
- atrace_categories_.back().ParseFromArray(field.data(), field.size());
- break;
default:
field.SerializeAndAppendTo(&unknown_fields_);
break;
@@ -17961,42 +18227,35 @@ bool FtraceDescriptor::ParseFromArray(const void* raw, size_t size) {
return !packed_error && !dec.bytes_left();
}
-std::string FtraceDescriptor::SerializeAsString() const {
+std::string VmOpDel::SerializeAsString() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsString();
}
-std::vector<uint8_t> FtraceDescriptor::SerializeAsArray() const {
+std::vector<uint8_t> VmOpDel::SerializeAsArray() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsArray();
}
-void FtraceDescriptor::Serialize(::protozero::Message* msg) const {
- // Field 1: atrace_categories
- for (auto& it : atrace_categories_) {
- it.Serialize(msg->BeginNestedMessage<::protozero::Message>(1));
- }
-
+void VmOpDel::Serialize(::protozero::Message* msg) const {
protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
}
-FtraceDescriptor_AtraceCategory::FtraceDescriptor_AtraceCategory() = default;
-FtraceDescriptor_AtraceCategory::~FtraceDescriptor_AtraceCategory() = default;
-FtraceDescriptor_AtraceCategory::FtraceDescriptor_AtraceCategory(const FtraceDescriptor_AtraceCategory&) = default;
-FtraceDescriptor_AtraceCategory& FtraceDescriptor_AtraceCategory::operator=(const FtraceDescriptor_AtraceCategory&) = default;
-FtraceDescriptor_AtraceCategory::FtraceDescriptor_AtraceCategory(FtraceDescriptor_AtraceCategory&&) noexcept = default;
-FtraceDescriptor_AtraceCategory& FtraceDescriptor_AtraceCategory::operator=(FtraceDescriptor_AtraceCategory&&) = default;
+VmOpSet::VmOpSet() = default;
+VmOpSet::~VmOpSet() = default;
+VmOpSet::VmOpSet(const VmOpSet&) = default;
+VmOpSet& VmOpSet::operator=(const VmOpSet&) = default;
+VmOpSet::VmOpSet(VmOpSet&&) noexcept = default;
+VmOpSet& VmOpSet::operator=(VmOpSet&&) = default;
-bool FtraceDescriptor_AtraceCategory::operator==(const FtraceDescriptor_AtraceCategory& other) const {
- return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
- && ::protozero::internal::gen_helpers::EqualsField(name_, other.name_)
- && ::protozero::internal::gen_helpers::EqualsField(description_, other.description_);
+bool VmOpSet::operator==(const VmOpSet& other) const {
+ return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_);
}
-bool FtraceDescriptor_AtraceCategory::ParseFromArray(const void* raw, size_t size) {
+bool VmOpSet::ParseFromArray(const void* raw, size_t size) {
unknown_fields_.clear();
bool packed_error = false;
@@ -18006,12 +18265,6 @@ bool FtraceDescriptor_AtraceCategory::ParseFromArray(const void* raw, size_t siz
_has_field_.set(field.id());
}
switch (field.id()) {
- case 1 /* name */:
- ::protozero::internal::gen_helpers::DeserializeString(field, &name_);
- break;
- case 2 /* description */:
- ::protozero::internal::gen_helpers::DeserializeString(field, &description_);
- break;
default:
field.SerializeAndAppendTo(&unknown_fields_);
break;
@@ -18020,87 +18273,37 @@ bool FtraceDescriptor_AtraceCategory::ParseFromArray(const void* raw, size_t siz
return !packed_error && !dec.bytes_left();
}
-std::string FtraceDescriptor_AtraceCategory::SerializeAsString() const {
+std::string VmOpSet::SerializeAsString() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsString();
}
-std::vector<uint8_t> FtraceDescriptor_AtraceCategory::SerializeAsArray() const {
+std::vector<uint8_t> VmOpSet::SerializeAsArray() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsArray();
}
-void FtraceDescriptor_AtraceCategory::Serialize(::protozero::Message* msg) const {
- // Field 1: name
- if (_has_field_[1]) {
- ::protozero::internal::gen_helpers::SerializeString(1, name_, msg);
- }
-
- // Field 2: description
- if (_has_field_[2]) {
- ::protozero::internal::gen_helpers::SerializeString(2, description_, msg);
- }
-
+void VmOpSet::Serialize(::protozero::Message* msg) const {
protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
}
-} // namespace perfetto
-} // namespace protos
-} // namespace gen
-#if defined(__GNUC__) || defined(__clang__)
-#pragma GCC diagnostic pop
-#endif
-// gen_amalgamated begin source: gen/protos/perfetto/common/gpu_counter_descriptor.gen.cc
-// gen_amalgamated expanded: #include "perfetto/protozero/gen_field_helpers.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/message.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/packed_repeated_fields.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/proto_decoder.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/scattered_heap_buffer.h"
-// DO NOT EDIT. Autogenerated by Perfetto cppgen_plugin
-#if defined(__GNUC__) || defined(__clang__)
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wfloat-equal"
-#endif
-// gen_amalgamated expanded: #include "protos/perfetto/common/gpu_counter_descriptor.gen.h"
-
-namespace perfetto {
-namespace protos {
-namespace gen {
-GpuCounterDescriptor::GpuCounterDescriptor() = default;
-GpuCounterDescriptor::~GpuCounterDescriptor() = default;
-GpuCounterDescriptor::GpuCounterDescriptor(const GpuCounterDescriptor&) = default;
-GpuCounterDescriptor& GpuCounterDescriptor::operator=(const GpuCounterDescriptor&) = default;
-GpuCounterDescriptor::GpuCounterDescriptor(GpuCounterDescriptor&&) noexcept = default;
-GpuCounterDescriptor& GpuCounterDescriptor::operator=(GpuCounterDescriptor&&) = default;
+VmOpMerge::VmOpMerge() = default;
+VmOpMerge::~VmOpMerge() = default;
+VmOpMerge::VmOpMerge(const VmOpMerge&) = default;
+VmOpMerge& VmOpMerge::operator=(const VmOpMerge&) = default;
+VmOpMerge::VmOpMerge(VmOpMerge&&) noexcept = default;
+VmOpMerge& VmOpMerge::operator=(VmOpMerge&&) = default;
-bool GpuCounterDescriptor::operator==(const GpuCounterDescriptor& other) const {
+bool VmOpMerge::operator==(const VmOpMerge& other) const {
return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
- && ::protozero::internal::gen_helpers::EqualsField(specs_, other.specs_)
- && ::protozero::internal::gen_helpers::EqualsField(blocks_, other.blocks_)
- && ::protozero::internal::gen_helpers::EqualsField(counter_groups_, other.counter_groups_)
- && ::protozero::internal::gen_helpers::EqualsField(min_sampling_period_ns_, other.min_sampling_period_ns_)
- && ::protozero::internal::gen_helpers::EqualsField(max_sampling_period_ns_, other.max_sampling_period_ns_)
- && ::protozero::internal::gen_helpers::EqualsField(supports_instrumented_sampling_, other.supports_instrumented_sampling_)
- && ::protozero::internal::gen_helpers::EqualsField(supports_counter_names_, other.supports_counter_names_)
- && ::protozero::internal::gen_helpers::EqualsField(supports_counter_name_globs_, other.supports_counter_name_globs_);
+ && ::protozero::internal::gen_helpers::EqualsField(skip_submessages_, other.skip_submessages_)
+ && ::protozero::internal::gen_helpers::EqualsField(del_if_src_empty_, other.del_if_src_empty_);
}
-int GpuCounterDescriptor::specs_size() const { return static_cast<int>(specs_.size()); }
-void GpuCounterDescriptor::clear_specs() { specs_.clear(); }
-GpuCounterDescriptor_GpuCounterSpec* GpuCounterDescriptor::add_specs() { specs_.emplace_back(); return &specs_.back(); }
-int GpuCounterDescriptor::blocks_size() const { return static_cast<int>(blocks_.size()); }
-void GpuCounterDescriptor::clear_blocks() { blocks_.clear(); }
-GpuCounterDescriptor_GpuCounterBlock* GpuCounterDescriptor::add_blocks() { blocks_.emplace_back(); return &blocks_.back(); }
-int GpuCounterDescriptor::counter_groups_size() const { return static_cast<int>(counter_groups_.size()); }
-void GpuCounterDescriptor::clear_counter_groups() { counter_groups_.clear(); }
-GpuCounterDescriptor_GpuCounterGroupSpec* GpuCounterDescriptor::add_counter_groups() { counter_groups_.emplace_back(); return &counter_groups_.back(); }
-bool GpuCounterDescriptor::ParseFromArray(const void* raw, size_t size) {
- specs_.clear();
- blocks_.clear();
- counter_groups_.clear();
+bool VmOpMerge::ParseFromArray(const void* raw, size_t size) {
unknown_fields_.clear();
bool packed_error = false;
@@ -18110,32 +18313,11 @@ bool GpuCounterDescriptor::ParseFromArray(const void* raw, size_t size) {
_has_field_.set(field.id());
}
switch (field.id()) {
- case 1 /* specs */:
- specs_.emplace_back();
- specs_.back().ParseFromArray(field.data(), field.size());
- break;
- case 2 /* blocks */:
- blocks_.emplace_back();
- blocks_.back().ParseFromArray(field.data(), field.size());
- break;
- case 6 /* counter_groups */:
- counter_groups_.emplace_back();
- counter_groups_.back().ParseFromArray(field.data(), field.size());
- break;
- case 3 /* min_sampling_period_ns */:
- field.get(&min_sampling_period_ns_);
- break;
- case 4 /* max_sampling_period_ns */:
- field.get(&max_sampling_period_ns_);
- break;
- case 5 /* supports_instrumented_sampling */:
- field.get(&supports_instrumented_sampling_);
- break;
- case 7 /* supports_counter_names */:
- field.get(&supports_counter_names_);
+ case 1 /* skip_submessages */:
+ field.get(&skip_submessages_);
break;
- case 8 /* supports_counter_name_globs */:
- field.get(&supports_counter_name_globs_);
+ case 2 /* del_if_src_empty */:
+ field.get(&del_if_src_empty_);
break;
default:
field.SerializeAndAppendTo(&unknown_fields_);
@@ -18145,80 +18327,47 @@ bool GpuCounterDescriptor::ParseFromArray(const void* raw, size_t size) {
return !packed_error && !dec.bytes_left();
}
-std::string GpuCounterDescriptor::SerializeAsString() const {
+std::string VmOpMerge::SerializeAsString() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsString();
}
-std::vector<uint8_t> GpuCounterDescriptor::SerializeAsArray() const {
+std::vector<uint8_t> VmOpMerge::SerializeAsArray() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsArray();
}
-void GpuCounterDescriptor::Serialize(::protozero::Message* msg) const {
- // Field 1: specs
- for (auto& it : specs_) {
- it.Serialize(msg->BeginNestedMessage<::protozero::Message>(1));
- }
-
- // Field 2: blocks
- for (auto& it : blocks_) {
- it.Serialize(msg->BeginNestedMessage<::protozero::Message>(2));
- }
-
- // Field 6: counter_groups
- for (auto& it : counter_groups_) {
- it.Serialize(msg->BeginNestedMessage<::protozero::Message>(6));
- }
-
- // Field 3: min_sampling_period_ns
- if (_has_field_[3]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(3, min_sampling_period_ns_, msg);
- }
-
- // Field 4: max_sampling_period_ns
- if (_has_field_[4]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(4, max_sampling_period_ns_, msg);
- }
-
- // Field 5: supports_instrumented_sampling
- if (_has_field_[5]) {
- ::protozero::internal::gen_helpers::SerializeTinyVarInt(5, supports_instrumented_sampling_, msg);
- }
-
- // Field 7: supports_counter_names
- if (_has_field_[7]) {
- ::protozero::internal::gen_helpers::SerializeTinyVarInt(7, supports_counter_names_, msg);
+void VmOpMerge::Serialize(::protozero::Message* msg) const {
+ // Field 1: skip_submessages
+ if (_has_field_[1]) {
+ ::protozero::internal::gen_helpers::SerializeTinyVarInt(1, skip_submessages_, msg);
}
- // Field 8: supports_counter_name_globs
- if (_has_field_[8]) {
- ::protozero::internal::gen_helpers::SerializeTinyVarInt(8, supports_counter_name_globs_, msg);
+ // Field 2: del_if_src_empty
+ if (_has_field_[2]) {
+ ::protozero::internal::gen_helpers::SerializeTinyVarInt(2, del_if_src_empty_, msg);
}
protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
}
-GpuCounterDescriptor_GpuCounterGroupSpec::GpuCounterDescriptor_GpuCounterGroupSpec() = default;
-GpuCounterDescriptor_GpuCounterGroupSpec::~GpuCounterDescriptor_GpuCounterGroupSpec() = default;
-GpuCounterDescriptor_GpuCounterGroupSpec::GpuCounterDescriptor_GpuCounterGroupSpec(const GpuCounterDescriptor_GpuCounterGroupSpec&) = default;
-GpuCounterDescriptor_GpuCounterGroupSpec& GpuCounterDescriptor_GpuCounterGroupSpec::operator=(const GpuCounterDescriptor_GpuCounterGroupSpec&) = default;
-GpuCounterDescriptor_GpuCounterGroupSpec::GpuCounterDescriptor_GpuCounterGroupSpec(GpuCounterDescriptor_GpuCounterGroupSpec&&) noexcept = default;
-GpuCounterDescriptor_GpuCounterGroupSpec& GpuCounterDescriptor_GpuCounterGroupSpec::operator=(GpuCounterDescriptor_GpuCounterGroupSpec&&) = default;
+VmOpRegLoad::VmOpRegLoad() = default;
+VmOpRegLoad::~VmOpRegLoad() = default;
+VmOpRegLoad::VmOpRegLoad(const VmOpRegLoad&) = default;
+VmOpRegLoad& VmOpRegLoad::operator=(const VmOpRegLoad&) = default;
+VmOpRegLoad::VmOpRegLoad(VmOpRegLoad&&) noexcept = default;
+VmOpRegLoad& VmOpRegLoad::operator=(VmOpRegLoad&&) = default;
-bool GpuCounterDescriptor_GpuCounterGroupSpec::operator==(const GpuCounterDescriptor_GpuCounterGroupSpec& other) const {
+bool VmOpRegLoad::operator==(const VmOpRegLoad& other) const {
return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
- && ::protozero::internal::gen_helpers::EqualsField(group_id_, other.group_id_)
- && ::protozero::internal::gen_helpers::EqualsField(name_, other.name_)
- && ::protozero::internal::gen_helpers::EqualsField(description_, other.description_)
- && ::protozero::internal::gen_helpers::EqualsField(counter_ids_, other.counter_ids_);
+ && ::protozero::internal::gen_helpers::EqualsField(cursor_, other.cursor_)
+ && ::protozero::internal::gen_helpers::EqualsField(dst_register_, other.dst_register_);
}
-bool GpuCounterDescriptor_GpuCounterGroupSpec::ParseFromArray(const void* raw, size_t size) {
- counter_ids_.clear();
+bool VmOpRegLoad::ParseFromArray(const void* raw, size_t size) {
unknown_fields_.clear();
bool packed_error = false;
@@ -18228,18 +18377,11 @@ bool GpuCounterDescriptor_GpuCounterGroupSpec::ParseFromArray(const void* raw, s
_has_field_.set(field.id());
}
switch (field.id()) {
- case 1 /* group_id */:
- field.get(&group_id_);
- break;
- case 2 /* name */:
- ::protozero::internal::gen_helpers::DeserializeString(field, &name_);
- break;
- case 3 /* description */:
- ::protozero::internal::gen_helpers::DeserializeString(field, &description_);
+ case 1 /* cursor */:
+ field.get(&cursor_);
break;
- case 4 /* counter_ids */:
- counter_ids_.emplace_back();
- field.get(&counter_ids_.back());
+ case 2 /* dst_register */:
+ field.get(&dst_register_);
break;
default:
field.SerializeAndAppendTo(&unknown_fields_);
@@ -18249,61 +18391,129 @@ bool GpuCounterDescriptor_GpuCounterGroupSpec::ParseFromArray(const void* raw, s
return !packed_error && !dec.bytes_left();
}
-std::string GpuCounterDescriptor_GpuCounterGroupSpec::SerializeAsString() const {
+std::string VmOpRegLoad::SerializeAsString() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsString();
}
-std::vector<uint8_t> GpuCounterDescriptor_GpuCounterGroupSpec::SerializeAsArray() const {
+std::vector<uint8_t> VmOpRegLoad::SerializeAsArray() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsArray();
}
-void GpuCounterDescriptor_GpuCounterGroupSpec::Serialize(::protozero::Message* msg) const {
- // Field 1: group_id
+void VmOpRegLoad::Serialize(::protozero::Message* msg) const {
+ // Field 1: cursor
if (_has_field_[1]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(1, group_id_, msg);
+ ::protozero::internal::gen_helpers::SerializeVarInt(1, cursor_, msg);
}
- // Field 2: name
+ // Field 2: dst_register
if (_has_field_[2]) {
- ::protozero::internal::gen_helpers::SerializeString(2, name_, msg);
+ ::protozero::internal::gen_helpers::SerializeVarInt(2, dst_register_, msg);
}
- // Field 3: description
- if (_has_field_[3]) {
- ::protozero::internal::gen_helpers::SerializeString(3, description_, msg);
+ protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
+}
+
+
+VmOpSelect::VmOpSelect() = default;
+VmOpSelect::~VmOpSelect() = default;
+VmOpSelect::VmOpSelect(const VmOpSelect&) = default;
+VmOpSelect& VmOpSelect::operator=(const VmOpSelect&) = default;
+VmOpSelect::VmOpSelect(VmOpSelect&&) noexcept = default;
+VmOpSelect& VmOpSelect::operator=(VmOpSelect&&) = default;
+
+bool VmOpSelect::operator==(const VmOpSelect& other) const {
+ return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
+ && ::protozero::internal::gen_helpers::EqualsField(cursor_, other.cursor_)
+ && ::protozero::internal::gen_helpers::EqualsField(relative_path_, other.relative_path_)
+ && ::protozero::internal::gen_helpers::EqualsField(create_if_not_exist_, other.create_if_not_exist_);
+}
+
+int VmOpSelect::relative_path_size() const { return static_cast<int>(relative_path_.size()); }
+void VmOpSelect::clear_relative_path() { relative_path_.clear(); }
+VmOpSelect_PathComponent* VmOpSelect::add_relative_path() { relative_path_.emplace_back(); return &relative_path_.back(); }
+bool VmOpSelect::ParseFromArray(const void* raw, size_t size) {
+ relative_path_.clear();
+ unknown_fields_.clear();
+ bool packed_error = false;
+
+ ::protozero::ProtoDecoder dec(raw, size);
+ for (auto field = dec.ReadField(); field.valid(); field = dec.ReadField()) {
+ if (field.id() < _has_field_.size()) {
+ _has_field_.set(field.id());
+ }
+ switch (field.id()) {
+ case 1 /* cursor */:
+ field.get(&cursor_);
+ break;
+ case 2 /* relative_path */:
+ relative_path_.emplace_back();
+ relative_path_.back().ParseFromArray(field.data(), field.size());
+ break;
+ case 3 /* create_if_not_exist */:
+ field.get(&create_if_not_exist_);
+ break;
+ default:
+ field.SerializeAndAppendTo(&unknown_fields_);
+ break;
+ }
}
+ return !packed_error && !dec.bytes_left();
+}
- // Field 4: counter_ids
- for (auto& it : counter_ids_) {
- ::protozero::internal::gen_helpers::SerializeVarInt(4, it, msg);
+std::string VmOpSelect::SerializeAsString() const {
+ ::protozero::internal::gen_helpers::MessageSerializer msg;
+ Serialize(msg.get());
+ return msg.SerializeAsString();
+}
+
+std::vector<uint8_t> VmOpSelect::SerializeAsArray() const {
+ ::protozero::internal::gen_helpers::MessageSerializer msg;
+ Serialize(msg.get());
+ return msg.SerializeAsArray();
+}
+
+void VmOpSelect::Serialize(::protozero::Message* msg) const {
+ // Field 1: cursor
+ if (_has_field_[1]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(1, cursor_, msg);
+ }
+
+ // Field 2: relative_path
+ for (auto& it : relative_path_) {
+ it.Serialize(msg->BeginNestedMessage<::protozero::Message>(2));
+ }
+
+ // Field 3: create_if_not_exist
+ if (_has_field_[3]) {
+ ::protozero::internal::gen_helpers::SerializeTinyVarInt(3, create_if_not_exist_, msg);
}
protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
}
-GpuCounterDescriptor_GpuCounterBlock::GpuCounterDescriptor_GpuCounterBlock() = default;
-GpuCounterDescriptor_GpuCounterBlock::~GpuCounterDescriptor_GpuCounterBlock() = default;
-GpuCounterDescriptor_GpuCounterBlock::GpuCounterDescriptor_GpuCounterBlock(const GpuCounterDescriptor_GpuCounterBlock&) = default;
-GpuCounterDescriptor_GpuCounterBlock& GpuCounterDescriptor_GpuCounterBlock::operator=(const GpuCounterDescriptor_GpuCounterBlock&) = default;
-GpuCounterDescriptor_GpuCounterBlock::GpuCounterDescriptor_GpuCounterBlock(GpuCounterDescriptor_GpuCounterBlock&&) noexcept = default;
-GpuCounterDescriptor_GpuCounterBlock& GpuCounterDescriptor_GpuCounterBlock::operator=(GpuCounterDescriptor_GpuCounterBlock&&) = default;
+VmOpSelect_PathComponent::VmOpSelect_PathComponent() = default;
+VmOpSelect_PathComponent::~VmOpSelect_PathComponent() = default;
+VmOpSelect_PathComponent::VmOpSelect_PathComponent(const VmOpSelect_PathComponent&) = default;
+VmOpSelect_PathComponent& VmOpSelect_PathComponent::operator=(const VmOpSelect_PathComponent&) = default;
+VmOpSelect_PathComponent::VmOpSelect_PathComponent(VmOpSelect_PathComponent&&) noexcept = default;
+VmOpSelect_PathComponent& VmOpSelect_PathComponent::operator=(VmOpSelect_PathComponent&&) = default;
-bool GpuCounterDescriptor_GpuCounterBlock::operator==(const GpuCounterDescriptor_GpuCounterBlock& other) const {
+bool VmOpSelect_PathComponent::operator==(const VmOpSelect_PathComponent& other) const {
return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
- && ::protozero::internal::gen_helpers::EqualsField(block_id_, other.block_id_)
- && ::protozero::internal::gen_helpers::EqualsField(block_capacity_, other.block_capacity_)
- && ::protozero::internal::gen_helpers::EqualsField(name_, other.name_)
- && ::protozero::internal::gen_helpers::EqualsField(description_, other.description_)
- && ::protozero::internal::gen_helpers::EqualsField(counter_ids_, other.counter_ids_);
+ && ::protozero::internal::gen_helpers::EqualsField(field_id_, other.field_id_)
+ && ::protozero::internal::gen_helpers::EqualsField(array_index_, other.array_index_)
+ && ::protozero::internal::gen_helpers::EqualsField(map_key_field_id_, other.map_key_field_id_)
+ && ::protozero::internal::gen_helpers::EqualsField(is_repeated_, other.is_repeated_)
+ && ::protozero::internal::gen_helpers::EqualsField(register_to_match_, other.register_to_match_)
+ && ::protozero::internal::gen_helpers::EqualsField(store_foreach_index_into_register_, other.store_foreach_index_into_register_);
}
-bool GpuCounterDescriptor_GpuCounterBlock::ParseFromArray(const void* raw, size_t size) {
- counter_ids_.clear();
+bool VmOpSelect_PathComponent::ParseFromArray(const void* raw, size_t size) {
unknown_fields_.clear();
bool packed_error = false;
@@ -18313,21 +18523,23 @@ bool GpuCounterDescriptor_GpuCounterBlock::ParseFromArray(const void* raw, size_
_has_field_.set(field.id());
}
switch (field.id()) {
- case 1 /* block_id */:
- field.get(&block_id_);
+ case 1 /* field_id */:
+ field.get(&field_id_);
break;
- case 2 /* block_capacity */:
- field.get(&block_capacity_);
+ case 2 /* array_index */:
+ field.get(&array_index_);
break;
- case 3 /* name */:
- ::protozero::internal::gen_helpers::DeserializeString(field, &name_);
+ case 3 /* map_key_field_id */:
+ field.get(&map_key_field_id_);
break;
- case 4 /* description */:
- ::protozero::internal::gen_helpers::DeserializeString(field, &description_);
+ case 5 /* is_repeated */:
+ field.get(&is_repeated_);
break;
- case 5 /* counter_ids */:
- counter_ids_.emplace_back();
- field.get(&counter_ids_.back());
+ case 6 /* register_to_match */:
+ field.get(®ister_to_match_);
+ break;
+ case 7 /* store_foreach_index_into_register */:
+ field.get(&store_foreach_index_into_register_);
break;
default:
field.SerializeAndAppendTo(&unknown_fields_);
@@ -18337,73 +18549,76 @@ bool GpuCounterDescriptor_GpuCounterBlock::ParseFromArray(const void* raw, size_
return !packed_error && !dec.bytes_left();
}
-std::string GpuCounterDescriptor_GpuCounterBlock::SerializeAsString() const {
+std::string VmOpSelect_PathComponent::SerializeAsString() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsString();
}
-std::vector<uint8_t> GpuCounterDescriptor_GpuCounterBlock::SerializeAsArray() const {
+std::vector<uint8_t> VmOpSelect_PathComponent::SerializeAsArray() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsArray();
}
-void GpuCounterDescriptor_GpuCounterBlock::Serialize(::protozero::Message* msg) const {
- // Field 1: block_id
+void VmOpSelect_PathComponent::Serialize(::protozero::Message* msg) const {
+ // Field 1: field_id
if (_has_field_[1]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(1, block_id_, msg);
+ ::protozero::internal::gen_helpers::SerializeVarInt(1, field_id_, msg);
}
- // Field 2: block_capacity
+ // Field 2: array_index
if (_has_field_[2]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(2, block_capacity_, msg);
+ ::protozero::internal::gen_helpers::SerializeVarInt(2, array_index_, msg);
}
- // Field 3: name
+ // Field 3: map_key_field_id
if (_has_field_[3]) {
- ::protozero::internal::gen_helpers::SerializeString(3, name_, msg);
+ ::protozero::internal::gen_helpers::SerializeVarInt(3, map_key_field_id_, msg);
}
- // Field 4: description
- if (_has_field_[4]) {
- ::protozero::internal::gen_helpers::SerializeString(4, description_, msg);
+ // Field 5: is_repeated
+ if (_has_field_[5]) {
+ ::protozero::internal::gen_helpers::SerializeTinyVarInt(5, is_repeated_, msg);
}
- // Field 5: counter_ids
- for (auto& it : counter_ids_) {
- ::protozero::internal::gen_helpers::SerializeVarInt(5, it, msg);
+ // Field 6: register_to_match
+ if (_has_field_[6]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(6, register_to_match_, msg);
+ }
+
+ // Field 7: store_foreach_index_into_register
+ if (_has_field_[7]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(7, store_foreach_index_into_register_, msg);
}
protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
}
-GpuCounterDescriptor_GpuCounterSpec::GpuCounterDescriptor_GpuCounterSpec() = default;
-GpuCounterDescriptor_GpuCounterSpec::~GpuCounterDescriptor_GpuCounterSpec() = default;
-GpuCounterDescriptor_GpuCounterSpec::GpuCounterDescriptor_GpuCounterSpec(const GpuCounterDescriptor_GpuCounterSpec&) = default;
-GpuCounterDescriptor_GpuCounterSpec& GpuCounterDescriptor_GpuCounterSpec::operator=(const GpuCounterDescriptor_GpuCounterSpec&) = default;
-GpuCounterDescriptor_GpuCounterSpec::GpuCounterDescriptor_GpuCounterSpec(GpuCounterDescriptor_GpuCounterSpec&&) noexcept = default;
-GpuCounterDescriptor_GpuCounterSpec& GpuCounterDescriptor_GpuCounterSpec::operator=(GpuCounterDescriptor_GpuCounterSpec&&) = default;
+VmInstruction::VmInstruction() = default;
+VmInstruction::~VmInstruction() = default;
+VmInstruction::VmInstruction(const VmInstruction&) = default;
+VmInstruction& VmInstruction::operator=(const VmInstruction&) = default;
+VmInstruction::VmInstruction(VmInstruction&&) noexcept = default;
+VmInstruction& VmInstruction::operator=(VmInstruction&&) = default;
-bool GpuCounterDescriptor_GpuCounterSpec::operator==(const GpuCounterDescriptor_GpuCounterSpec& other) const {
+bool VmInstruction::operator==(const VmInstruction& other) const {
return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
- && ::protozero::internal::gen_helpers::EqualsField(counter_id_, other.counter_id_)
- && ::protozero::internal::gen_helpers::EqualsField(name_, other.name_)
- && ::protozero::internal::gen_helpers::EqualsField(description_, other.description_)
- && ::protozero::internal::gen_helpers::EqualsField(int_peak_value_, other.int_peak_value_)
- && ::protozero::internal::gen_helpers::EqualsField(double_peak_value_, other.double_peak_value_)
- && ::protozero::internal::gen_helpers::EqualsField(numerator_units_, other.numerator_units_)
- && ::protozero::internal::gen_helpers::EqualsField(denominator_units_, other.denominator_units_)
- && ::protozero::internal::gen_helpers::EqualsField(select_by_default_, other.select_by_default_)
- && ::protozero::internal::gen_helpers::EqualsField(groups_, other.groups_)
- && ::protozero::internal::gen_helpers::EqualsField(value_direction_, other.value_direction_);
+ && ::protozero::internal::gen_helpers::EqualsField(select_, other.select_)
+ && ::protozero::internal::gen_helpers::EqualsField(reg_load_, other.reg_load_)
+ && ::protozero::internal::gen_helpers::EqualsField(merge_, other.merge_)
+ && ::protozero::internal::gen_helpers::EqualsField(set_, other.set_)
+ && ::protozero::internal::gen_helpers::EqualsField(del_, other.del_)
+ && ::protozero::internal::gen_helpers::EqualsField(abort_level_, other.abort_level_)
+ && ::protozero::internal::gen_helpers::EqualsField(nested_instructions_, other.nested_instructions_);
}
-bool GpuCounterDescriptor_GpuCounterSpec::ParseFromArray(const void* raw, size_t size) {
- numerator_units_.clear();
- denominator_units_.clear();
- groups_.clear();
+int VmInstruction::nested_instructions_size() const { return static_cast<int>(nested_instructions_.size()); }
+void VmInstruction::clear_nested_instructions() { nested_instructions_.clear(); }
+VmInstruction* VmInstruction::add_nested_instructions() { nested_instructions_.emplace_back(); return &nested_instructions_.back(); }
+bool VmInstruction::ParseFromArray(const void* raw, size_t size) {
+ nested_instructions_.clear();
unknown_fields_.clear();
bool packed_error = false;
@@ -18413,38 +18628,27 @@ bool GpuCounterDescriptor_GpuCounterSpec::ParseFromArray(const void* raw, size_t
_has_field_.set(field.id());
}
switch (field.id()) {
- case 1 /* counter_id */:
- field.get(&counter_id_);
- break;
- case 2 /* name */:
- ::protozero::internal::gen_helpers::DeserializeString(field, &name_);
- break;
- case 3 /* description */:
- ::protozero::internal::gen_helpers::DeserializeString(field, &description_);
- break;
- case 5 /* int_peak_value */:
- field.get(&int_peak_value_);
+ case 1 /* select */:
+ (*select_).ParseFromArray(field.data(), field.size());
break;
- case 6 /* double_peak_value */:
- field.get(&double_peak_value_);
+ case 2 /* reg_load */:
+ (*reg_load_).ParseFromArray(field.data(), field.size());
break;
- case 7 /* numerator_units */:
- numerator_units_.emplace_back();
- field.get(&numerator_units_.back());
+ case 3 /* merge */:
+ (*merge_).ParseFromArray(field.data(), field.size());
break;
- case 8 /* denominator_units */:
- denominator_units_.emplace_back();
- field.get(&denominator_units_.back());
+ case 4 /* set */:
+ (*set_).ParseFromArray(field.data(), field.size());
break;
- case 9 /* select_by_default */:
- field.get(&select_by_default_);
+ case 5 /* del */:
+ (*del_).ParseFromArray(field.data(), field.size());
break;
- case 10 /* groups */:
- groups_.emplace_back();
- field.get(&groups_.back());
+ case 6 /* abort_level */:
+ field.get(&abort_level_);
break;
- case 11 /* value_direction */:
- field.get(&value_direction_);
+ case 7 /* nested_instructions */:
+ nested_instructions_.emplace_back();
+ nested_instructions_.back().ParseFromArray(field.data(), field.size());
break;
default:
field.SerializeAndAppendTo(&unknown_fields_);
@@ -18454,108 +18658,76 @@ bool GpuCounterDescriptor_GpuCounterSpec::ParseFromArray(const void* raw, size_t
return !packed_error && !dec.bytes_left();
}
-std::string GpuCounterDescriptor_GpuCounterSpec::SerializeAsString() const {
+std::string VmInstruction::SerializeAsString() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsString();
}
-std::vector<uint8_t> GpuCounterDescriptor_GpuCounterSpec::SerializeAsArray() const {
+std::vector<uint8_t> VmInstruction::SerializeAsArray() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsArray();
}
-void GpuCounterDescriptor_GpuCounterSpec::Serialize(::protozero::Message* msg) const {
- // Field 1: counter_id
+void VmInstruction::Serialize(::protozero::Message* msg) const {
+ // Field 1: select
if (_has_field_[1]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(1, counter_id_, msg);
+ (*select_).Serialize(msg->BeginNestedMessage<::protozero::Message>(1));
}
- // Field 2: name
+ // Field 2: reg_load
if (_has_field_[2]) {
- ::protozero::internal::gen_helpers::SerializeString(2, name_, msg);
+ (*reg_load_).Serialize(msg->BeginNestedMessage<::protozero::Message>(2));
}
- // Field 3: description
+ // Field 3: merge
if (_has_field_[3]) {
- ::protozero::internal::gen_helpers::SerializeString(3, description_, msg);
- }
-
- // Field 5: int_peak_value
- if (_has_field_[5]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(5, int_peak_value_, msg);
- }
-
- // Field 6: double_peak_value
- if (_has_field_[6]) {
- ::protozero::internal::gen_helpers::SerializeFixed(6, double_peak_value_, msg);
- }
-
- // Field 7: numerator_units
- for (auto& it : numerator_units_) {
- ::protozero::internal::gen_helpers::SerializeVarInt(7, it, msg);
+ (*merge_).Serialize(msg->BeginNestedMessage<::protozero::Message>(3));
}
- // Field 8: denominator_units
- for (auto& it : denominator_units_) {
- ::protozero::internal::gen_helpers::SerializeVarInt(8, it, msg);
+ // Field 4: set
+ if (_has_field_[4]) {
+ (*set_).Serialize(msg->BeginNestedMessage<::protozero::Message>(4));
}
- // Field 9: select_by_default
- if (_has_field_[9]) {
- ::protozero::internal::gen_helpers::SerializeTinyVarInt(9, select_by_default_, msg);
+ // Field 5: del
+ if (_has_field_[5]) {
+ (*del_).Serialize(msg->BeginNestedMessage<::protozero::Message>(5));
}
- // Field 10: groups
- for (auto& it : groups_) {
- ::protozero::internal::gen_helpers::SerializeVarInt(10, it, msg);
+ // Field 6: abort_level
+ if (_has_field_[6]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(6, abort_level_, msg);
}
- // Field 11: value_direction
- if (_has_field_[11]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(11, value_direction_, msg);
+ // Field 7: nested_instructions
+ for (auto& it : nested_instructions_) {
+ it.Serialize(msg->BeginNestedMessage<::protozero::Message>(7));
}
protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
}
-} // namespace perfetto
-} // namespace protos
-} // namespace gen
-#if defined(__GNUC__) || defined(__clang__)
-#pragma GCC diagnostic pop
-#endif
-// gen_amalgamated begin source: gen/protos/perfetto/common/interceptor_descriptor.gen.cc
-// gen_amalgamated expanded: #include "perfetto/protozero/gen_field_helpers.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/message.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/packed_repeated_fields.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/proto_decoder.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/scattered_heap_buffer.h"
-// DO NOT EDIT. Autogenerated by Perfetto cppgen_plugin
-#if defined(__GNUC__) || defined(__clang__)
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wfloat-equal"
-#endif
-// gen_amalgamated expanded: #include "protos/perfetto/common/interceptor_descriptor.gen.h"
-
-namespace perfetto {
-namespace protos {
-namespace gen {
-InterceptorDescriptor::InterceptorDescriptor() = default;
-InterceptorDescriptor::~InterceptorDescriptor() = default;
-InterceptorDescriptor::InterceptorDescriptor(const InterceptorDescriptor&) = default;
-InterceptorDescriptor& InterceptorDescriptor::operator=(const InterceptorDescriptor&) = default;
-InterceptorDescriptor::InterceptorDescriptor(InterceptorDescriptor&&) noexcept = default;
-InterceptorDescriptor& InterceptorDescriptor::operator=(InterceptorDescriptor&&) = default;
+VmProgram::VmProgram() = default;
+VmProgram::~VmProgram() = default;
+VmProgram::VmProgram(const VmProgram&) = default;
+VmProgram& VmProgram::operator=(const VmProgram&) = default;
+VmProgram::VmProgram(VmProgram&&) noexcept = default;
+VmProgram& VmProgram::operator=(VmProgram&&) = default;
-bool InterceptorDescriptor::operator==(const InterceptorDescriptor& other) const {
+bool VmProgram::operator==(const VmProgram& other) const {
return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
- && ::protozero::internal::gen_helpers::EqualsField(name_, other.name_);
+ && ::protozero::internal::gen_helpers::EqualsField(version_, other.version_)
+ && ::protozero::internal::gen_helpers::EqualsField(instructions_, other.instructions_);
}
-bool InterceptorDescriptor::ParseFromArray(const void* raw, size_t size) {
+int VmProgram::instructions_size() const { return static_cast<int>(instructions_.size()); }
+void VmProgram::clear_instructions() { instructions_.clear(); }
+VmInstruction* VmProgram::add_instructions() { instructions_.emplace_back(); return &instructions_.back(); }
+bool VmProgram::ParseFromArray(const void* raw, size_t size) {
+ instructions_.clear();
unknown_fields_.clear();
bool packed_error = false;
@@ -18565,8 +18737,12 @@ bool InterceptorDescriptor::ParseFromArray(const void* raw, size_t size) {
_has_field_.set(field.id());
}
switch (field.id()) {
- case 1 /* name */:
- ::protozero::internal::gen_helpers::DeserializeString(field, &name_);
+ case 1 /* version */:
+ field.get(&version_);
+ break;
+ case 2 /* instructions */:
+ instructions_.emplace_back();
+ instructions_.back().ParseFromArray(field.data(), field.size());
break;
default:
field.SerializeAndAppendTo(&unknown_fields_);
@@ -18576,22 +18752,27 @@ bool InterceptorDescriptor::ParseFromArray(const void* raw, size_t size) {
return !packed_error && !dec.bytes_left();
}
-std::string InterceptorDescriptor::SerializeAsString() const {
+std::string VmProgram::SerializeAsString() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsString();
}
-std::vector<uint8_t> InterceptorDescriptor::SerializeAsArray() const {
+std::vector<uint8_t> VmProgram::SerializeAsArray() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsArray();
}
-void InterceptorDescriptor::Serialize(::protozero::Message* msg) const {
- // Field 1: name
+void VmProgram::Serialize(::protozero::Message* msg) const {
+ // Field 1: version
if (_has_field_[1]) {
- ::protozero::internal::gen_helpers::SerializeString(1, name_, msg);
+ ::protozero::internal::gen_helpers::SerializeVarInt(1, version_, msg);
+ }
+
+ // Field 2: instructions
+ for (auto& it : instructions_) {
+ it.Serialize(msg->BeginNestedMessage<::protozero::Message>(2));
}
protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
@@ -18603,7 +18784,7 @@ void InterceptorDescriptor::Serialize(::protozero::Message* msg) const {
#if defined(__GNUC__) || defined(__clang__)
#pragma GCC diagnostic pop
#endif
-// gen_amalgamated begin source: gen/protos/perfetto/common/observable_events.gen.cc
+// gen_amalgamated begin source: gen/protos/perfetto/common/android_energy_consumer_descriptor.gen.cc
// gen_amalgamated expanded: #include "perfetto/protozero/gen_field_helpers.h"
// gen_amalgamated expanded: #include "perfetto/protozero/message.h"
// gen_amalgamated expanded: #include "perfetto/protozero/packed_repeated_fields.h"
@@ -18614,31 +18795,29 @@ void InterceptorDescriptor::Serialize(::protozero::Message* msg) const {
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wfloat-equal"
#endif
-// gen_amalgamated expanded: #include "protos/perfetto/common/observable_events.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/common/android_energy_consumer_descriptor.gen.h"
namespace perfetto {
namespace protos {
namespace gen {
-ObservableEvents::ObservableEvents() = default;
-ObservableEvents::~ObservableEvents() = default;
-ObservableEvents::ObservableEvents(const ObservableEvents&) = default;
-ObservableEvents& ObservableEvents::operator=(const ObservableEvents&) = default;
-ObservableEvents::ObservableEvents(ObservableEvents&&) noexcept = default;
-ObservableEvents& ObservableEvents::operator=(ObservableEvents&&) = default;
+AndroidEnergyConsumerDescriptor::AndroidEnergyConsumerDescriptor() = default;
+AndroidEnergyConsumerDescriptor::~AndroidEnergyConsumerDescriptor() = default;
+AndroidEnergyConsumerDescriptor::AndroidEnergyConsumerDescriptor(const AndroidEnergyConsumerDescriptor&) = default;
+AndroidEnergyConsumerDescriptor& AndroidEnergyConsumerDescriptor::operator=(const AndroidEnergyConsumerDescriptor&) = default;
+AndroidEnergyConsumerDescriptor::AndroidEnergyConsumerDescriptor(AndroidEnergyConsumerDescriptor&&) noexcept = default;
+AndroidEnergyConsumerDescriptor& AndroidEnergyConsumerDescriptor::operator=(AndroidEnergyConsumerDescriptor&&) = default;
-bool ObservableEvents::operator==(const ObservableEvents& other) const {
+bool AndroidEnergyConsumerDescriptor::operator==(const AndroidEnergyConsumerDescriptor& other) const {
return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
- && ::protozero::internal::gen_helpers::EqualsField(instance_state_changes_, other.instance_state_changes_)
- && ::protozero::internal::gen_helpers::EqualsField(all_data_sources_started_, other.all_data_sources_started_)
- && ::protozero::internal::gen_helpers::EqualsField(clone_trigger_hit_, other.clone_trigger_hit_);
+ && ::protozero::internal::gen_helpers::EqualsField(energy_consumers_, other.energy_consumers_);
}
-int ObservableEvents::instance_state_changes_size() const { return static_cast<int>(instance_state_changes_.size()); }
-void ObservableEvents::clear_instance_state_changes() { instance_state_changes_.clear(); }
-ObservableEvents_DataSourceInstanceStateChange* ObservableEvents::add_instance_state_changes() { instance_state_changes_.emplace_back(); return &instance_state_changes_.back(); }
-bool ObservableEvents::ParseFromArray(const void* raw, size_t size) {
- instance_state_changes_.clear();
+int AndroidEnergyConsumerDescriptor::energy_consumers_size() const { return static_cast<int>(energy_consumers_.size()); }
+void AndroidEnergyConsumerDescriptor::clear_energy_consumers() { energy_consumers_.clear(); }
+AndroidEnergyConsumer* AndroidEnergyConsumerDescriptor::add_energy_consumers() { energy_consumers_.emplace_back(); return &energy_consumers_.back(); }
+bool AndroidEnergyConsumerDescriptor::ParseFromArray(const void* raw, size_t size) {
+ energy_consumers_.clear();
unknown_fields_.clear();
bool packed_error = false;
@@ -18648,15 +18827,9 @@ bool ObservableEvents::ParseFromArray(const void* raw, size_t size) {
_has_field_.set(field.id());
}
switch (field.id()) {
- case 1 /* instance_state_changes */:
- instance_state_changes_.emplace_back();
- instance_state_changes_.back().ParseFromArray(field.data(), field.size());
- break;
- case 2 /* all_data_sources_started */:
- field.get(&all_data_sources_started_);
- break;
- case 3 /* clone_trigger_hit */:
- (*clone_trigger_hit_).ParseFromArray(field.data(), field.size());
+ case 1 /* energy_consumers */:
+ energy_consumers_.emplace_back();
+ energy_consumers_.back().ParseFromArray(field.data(), field.size());
break;
default:
field.SerializeAndAppendTo(&unknown_fields_);
@@ -18666,56 +18839,44 @@ bool ObservableEvents::ParseFromArray(const void* raw, size_t size) {
return !packed_error && !dec.bytes_left();
}
-std::string ObservableEvents::SerializeAsString() const {
+std::string AndroidEnergyConsumerDescriptor::SerializeAsString() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsString();
}
-std::vector<uint8_t> ObservableEvents::SerializeAsArray() const {
+std::vector<uint8_t> AndroidEnergyConsumerDescriptor::SerializeAsArray() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsArray();
}
-void ObservableEvents::Serialize(::protozero::Message* msg) const {
- // Field 1: instance_state_changes
- for (auto& it : instance_state_changes_) {
+void AndroidEnergyConsumerDescriptor::Serialize(::protozero::Message* msg) const {
+ // Field 1: energy_consumers
+ for (auto& it : energy_consumers_) {
it.Serialize(msg->BeginNestedMessage<::protozero::Message>(1));
}
- // Field 2: all_data_sources_started
- if (_has_field_[2]) {
- ::protozero::internal::gen_helpers::SerializeTinyVarInt(2, all_data_sources_started_, msg);
- }
-
- // Field 3: clone_trigger_hit
- if (_has_field_[3]) {
- (*clone_trigger_hit_).Serialize(msg->BeginNestedMessage<::protozero::Message>(3));
- }
-
protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
}
-ObservableEvents_CloneTriggerHit::ObservableEvents_CloneTriggerHit() = default;
-ObservableEvents_CloneTriggerHit::~ObservableEvents_CloneTriggerHit() = default;
-ObservableEvents_CloneTriggerHit::ObservableEvents_CloneTriggerHit(const ObservableEvents_CloneTriggerHit&) = default;
-ObservableEvents_CloneTriggerHit& ObservableEvents_CloneTriggerHit::operator=(const ObservableEvents_CloneTriggerHit&) = default;
-ObservableEvents_CloneTriggerHit::ObservableEvents_CloneTriggerHit(ObservableEvents_CloneTriggerHit&&) noexcept = default;
-ObservableEvents_CloneTriggerHit& ObservableEvents_CloneTriggerHit::operator=(ObservableEvents_CloneTriggerHit&&) = default;
+AndroidEnergyConsumer::AndroidEnergyConsumer() = default;
+AndroidEnergyConsumer::~AndroidEnergyConsumer() = default;
+AndroidEnergyConsumer::AndroidEnergyConsumer(const AndroidEnergyConsumer&) = default;
+AndroidEnergyConsumer& AndroidEnergyConsumer::operator=(const AndroidEnergyConsumer&) = default;
+AndroidEnergyConsumer::AndroidEnergyConsumer(AndroidEnergyConsumer&&) noexcept = default;
+AndroidEnergyConsumer& AndroidEnergyConsumer::operator=(AndroidEnergyConsumer&&) = default;
-bool ObservableEvents_CloneTriggerHit::operator==(const ObservableEvents_CloneTriggerHit& other) const {
+bool AndroidEnergyConsumer::operator==(const AndroidEnergyConsumer& other) const {
return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
- && ::protozero::internal::gen_helpers::EqualsField(tracing_session_id_, other.tracing_session_id_)
- && ::protozero::internal::gen_helpers::EqualsField(trigger_name_, other.trigger_name_)
- && ::protozero::internal::gen_helpers::EqualsField(producer_name_, other.producer_name_)
- && ::protozero::internal::gen_helpers::EqualsField(producer_uid_, other.producer_uid_)
- && ::protozero::internal::gen_helpers::EqualsField(boot_time_ns_, other.boot_time_ns_)
- && ::protozero::internal::gen_helpers::EqualsField(trigger_delay_ms_, other.trigger_delay_ms_);
+ && ::protozero::internal::gen_helpers::EqualsField(energy_consumer_id_, other.energy_consumer_id_)
+ && ::protozero::internal::gen_helpers::EqualsField(ordinal_, other.ordinal_)
+ && ::protozero::internal::gen_helpers::EqualsField(type_, other.type_)
+ && ::protozero::internal::gen_helpers::EqualsField(name_, other.name_);
}
-bool ObservableEvents_CloneTriggerHit::ParseFromArray(const void* raw, size_t size) {
+bool AndroidEnergyConsumer::ParseFromArray(const void* raw, size_t size) {
unknown_fields_.clear();
bool packed_error = false;
@@ -18725,23 +18886,17 @@ bool ObservableEvents_CloneTriggerHit::ParseFromArray(const void* raw, size_t si
_has_field_.set(field.id());
}
switch (field.id()) {
- case 1 /* tracing_session_id */:
- field.get(&tracing_session_id_);
- break;
- case 2 /* trigger_name */:
- ::protozero::internal::gen_helpers::DeserializeString(field, &trigger_name_);
- break;
- case 3 /* producer_name */:
- ::protozero::internal::gen_helpers::DeserializeString(field, &producer_name_);
+ case 1 /* energy_consumer_id */:
+ field.get(&energy_consumer_id_);
break;
- case 4 /* producer_uid */:
- field.get(&producer_uid_);
+ case 2 /* ordinal */:
+ field.get(&ordinal_);
break;
- case 5 /* boot_time_ns */:
- field.get(&boot_time_ns_);
+ case 3 /* type */:
+ ::protozero::internal::gen_helpers::DeserializeString(field, &type_);
break;
- case 6 /* trigger_delay_ms */:
- field.get(&trigger_delay_ms_);
+ case 4 /* name */:
+ ::protozero::internal::gen_helpers::DeserializeString(field, &name_);
break;
default:
field.SerializeAndAppendTo(&unknown_fields_);
@@ -18751,132 +18906,93 @@ bool ObservableEvents_CloneTriggerHit::ParseFromArray(const void* raw, size_t si
return !packed_error && !dec.bytes_left();
}
-std::string ObservableEvents_CloneTriggerHit::SerializeAsString() const {
+std::string AndroidEnergyConsumer::SerializeAsString() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsString();
}
-std::vector<uint8_t> ObservableEvents_CloneTriggerHit::SerializeAsArray() const {
+std::vector<uint8_t> AndroidEnergyConsumer::SerializeAsArray() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsArray();
}
-void ObservableEvents_CloneTriggerHit::Serialize(::protozero::Message* msg) const {
- // Field 1: tracing_session_id
+void AndroidEnergyConsumer::Serialize(::protozero::Message* msg) const {
+ // Field 1: energy_consumer_id
if (_has_field_[1]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(1, tracing_session_id_, msg);
+ ::protozero::internal::gen_helpers::SerializeVarInt(1, energy_consumer_id_, msg);
}
- // Field 2: trigger_name
+ // Field 2: ordinal
if (_has_field_[2]) {
- ::protozero::internal::gen_helpers::SerializeString(2, trigger_name_, msg);
+ ::protozero::internal::gen_helpers::SerializeVarInt(2, ordinal_, msg);
}
- // Field 3: producer_name
+ // Field 3: type
if (_has_field_[3]) {
- ::protozero::internal::gen_helpers::SerializeString(3, producer_name_, msg);
+ ::protozero::internal::gen_helpers::SerializeString(3, type_, msg);
}
- // Field 4: producer_uid
+ // Field 4: name
if (_has_field_[4]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(4, producer_uid_, msg);
- }
-
- // Field 5: boot_time_ns
- if (_has_field_[5]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(5, boot_time_ns_, msg);
- }
-
- // Field 6: trigger_delay_ms
- if (_has_field_[6]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(6, trigger_delay_ms_, msg);
+ ::protozero::internal::gen_helpers::SerializeString(4, name_, msg);
}
protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
}
+} // namespace perfetto
+} // namespace protos
+} // namespace gen
+#if defined(__GNUC__) || defined(__clang__)
+#pragma GCC diagnostic pop
+#endif
+// gen_amalgamated begin source: gen/protos/perfetto/common/android_log_constants.gen.cc
+// gen_amalgamated expanded: #include "perfetto/protozero/gen_field_helpers.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/message.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/packed_repeated_fields.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/proto_decoder.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/scattered_heap_buffer.h"
+// DO NOT EDIT. Autogenerated by Perfetto cppgen_plugin
+#if defined(__GNUC__) || defined(__clang__)
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wfloat-equal"
+#endif
+// gen_amalgamated expanded: #include "protos/perfetto/common/android_log_constants.gen.h"
-ObservableEvents_DataSourceInstanceStateChange::ObservableEvents_DataSourceInstanceStateChange() = default;
-ObservableEvents_DataSourceInstanceStateChange::~ObservableEvents_DataSourceInstanceStateChange() = default;
-ObservableEvents_DataSourceInstanceStateChange::ObservableEvents_DataSourceInstanceStateChange(const ObservableEvents_DataSourceInstanceStateChange&) = default;
-ObservableEvents_DataSourceInstanceStateChange& ObservableEvents_DataSourceInstanceStateChange::operator=(const ObservableEvents_DataSourceInstanceStateChange&) = default;
-ObservableEvents_DataSourceInstanceStateChange::ObservableEvents_DataSourceInstanceStateChange(ObservableEvents_DataSourceInstanceStateChange&&) noexcept = default;
-ObservableEvents_DataSourceInstanceStateChange& ObservableEvents_DataSourceInstanceStateChange::operator=(ObservableEvents_DataSourceInstanceStateChange&&) = default;
-
-bool ObservableEvents_DataSourceInstanceStateChange::operator==(const ObservableEvents_DataSourceInstanceStateChange& other) const {
- return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
- && ::protozero::internal::gen_helpers::EqualsField(producer_name_, other.producer_name_)
- && ::protozero::internal::gen_helpers::EqualsField(data_source_name_, other.data_source_name_)
- && ::protozero::internal::gen_helpers::EqualsField(state_, other.state_);
-}
-
-bool ObservableEvents_DataSourceInstanceStateChange::ParseFromArray(const void* raw, size_t size) {
- unknown_fields_.clear();
- bool packed_error = false;
-
- ::protozero::ProtoDecoder dec(raw, size);
- for (auto field = dec.ReadField(); field.valid(); field = dec.ReadField()) {
- if (field.id() < _has_field_.size()) {
- _has_field_.set(field.id());
- }
- switch (field.id()) {
- case 1 /* producer_name */:
- ::protozero::internal::gen_helpers::DeserializeString(field, &producer_name_);
- break;
- case 2 /* data_source_name */:
- ::protozero::internal::gen_helpers::DeserializeString(field, &data_source_name_);
- break;
- case 3 /* state */:
- field.get(&state_);
- break;
- default:
- field.SerializeAndAppendTo(&unknown_fields_);
- break;
- }
- }
- return !packed_error && !dec.bytes_left();
-}
-
-std::string ObservableEvents_DataSourceInstanceStateChange::SerializeAsString() const {
- ::protozero::internal::gen_helpers::MessageSerializer msg;
- Serialize(msg.get());
- return msg.SerializeAsString();
-}
-
-std::vector<uint8_t> ObservableEvents_DataSourceInstanceStateChange::SerializeAsArray() const {
- ::protozero::internal::gen_helpers::MessageSerializer msg;
- Serialize(msg.get());
- return msg.SerializeAsArray();
-}
-
-void ObservableEvents_DataSourceInstanceStateChange::Serialize(::protozero::Message* msg) const {
- // Field 1: producer_name
- if (_has_field_[1]) {
- ::protozero::internal::gen_helpers::SerializeString(1, producer_name_, msg);
- }
-
- // Field 2: data_source_name
- if (_has_field_[2]) {
- ::protozero::internal::gen_helpers::SerializeString(2, data_source_name_, msg);
- }
-
- // Field 3: state
- if (_has_field_[3]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(3, state_, msg);
- }
-
- protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
-}
+namespace perfetto {
+namespace protos {
+namespace gen {
+} // namespace perfetto
+} // namespace protos
+} // namespace gen
+#if defined(__GNUC__) || defined(__clang__)
+#pragma GCC diagnostic pop
+#endif
+// gen_amalgamated begin source: gen/protos/perfetto/common/builtin_clock.gen.cc
+// gen_amalgamated expanded: #include "perfetto/protozero/gen_field_helpers.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/message.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/packed_repeated_fields.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/proto_decoder.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/scattered_heap_buffer.h"
+// DO NOT EDIT. Autogenerated by Perfetto cppgen_plugin
+#if defined(__GNUC__) || defined(__clang__)
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wfloat-equal"
+#endif
+// gen_amalgamated expanded: #include "protos/perfetto/common/builtin_clock.gen.h"
+namespace perfetto {
+namespace protos {
+namespace gen {
} // namespace perfetto
} // namespace protos
} // namespace gen
#if defined(__GNUC__) || defined(__clang__)
#pragma GCC diagnostic pop
#endif
-// gen_amalgamated begin source: gen/protos/perfetto/common/perf_events.gen.cc
+// gen_amalgamated begin source: gen/protos/perfetto/common/commit_data_request.gen.cc
// gen_amalgamated expanded: #include "perfetto/protozero/gen_field_helpers.h"
// gen_amalgamated expanded: #include "perfetto/protozero/message.h"
// gen_amalgamated expanded: #include "perfetto/protozero/packed_repeated_fields.h"
@@ -18887,30 +19003,35 @@ void ObservableEvents_DataSourceInstanceStateChange::Serialize(::protozero::Mess
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wfloat-equal"
#endif
-// gen_amalgamated expanded: #include "protos/perfetto/common/perf_events.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/common/commit_data_request.gen.h"
namespace perfetto {
namespace protos {
namespace gen {
-FollowerEvent::FollowerEvent() = default;
-FollowerEvent::~FollowerEvent() = default;
-FollowerEvent::FollowerEvent(const FollowerEvent&) = default;
-FollowerEvent& FollowerEvent::operator=(const FollowerEvent&) = default;
-FollowerEvent::FollowerEvent(FollowerEvent&&) noexcept = default;
-FollowerEvent& FollowerEvent::operator=(FollowerEvent&&) = default;
+CommitDataRequest::CommitDataRequest() = default;
+CommitDataRequest::~CommitDataRequest() = default;
+CommitDataRequest::CommitDataRequest(const CommitDataRequest&) = default;
+CommitDataRequest& CommitDataRequest::operator=(const CommitDataRequest&) = default;
+CommitDataRequest::CommitDataRequest(CommitDataRequest&&) noexcept = default;
+CommitDataRequest& CommitDataRequest::operator=(CommitDataRequest&&) = default;
-bool FollowerEvent::operator==(const FollowerEvent& other) const {
+bool CommitDataRequest::operator==(const CommitDataRequest& other) const {
return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
- && ::protozero::internal::gen_helpers::EqualsField(counter_, other.counter_)
- && ::protozero::internal::gen_helpers::EqualsField(tracepoint_, other.tracepoint_)
- && ::protozero::internal::gen_helpers::EqualsField(raw_event_, other.raw_event_)
- && ::protozero::internal::gen_helpers::EqualsField(modifiers_, other.modifiers_)
- && ::protozero::internal::gen_helpers::EqualsField(name_, other.name_);
+ && ::protozero::internal::gen_helpers::EqualsField(chunks_to_move_, other.chunks_to_move_)
+ && ::protozero::internal::gen_helpers::EqualsField(chunks_to_patch_, other.chunks_to_patch_)
+ && ::protozero::internal::gen_helpers::EqualsField(flush_request_id_, other.flush_request_id_);
}
-bool FollowerEvent::ParseFromArray(const void* raw, size_t size) {
- modifiers_.clear();
+int CommitDataRequest::chunks_to_move_size() const { return static_cast<int>(chunks_to_move_.size()); }
+void CommitDataRequest::clear_chunks_to_move() { chunks_to_move_.clear(); }
+CommitDataRequest_ChunksToMove* CommitDataRequest::add_chunks_to_move() { chunks_to_move_.emplace_back(); return &chunks_to_move_.back(); }
+int CommitDataRequest::chunks_to_patch_size() const { return static_cast<int>(chunks_to_patch_.size()); }
+void CommitDataRequest::clear_chunks_to_patch() { chunks_to_patch_.clear(); }
+CommitDataRequest_ChunkToPatch* CommitDataRequest::add_chunks_to_patch() { chunks_to_patch_.emplace_back(); return &chunks_to_patch_.back(); }
+bool CommitDataRequest::ParseFromArray(const void* raw, size_t size) {
+ chunks_to_move_.clear();
+ chunks_to_patch_.clear();
unknown_fields_.clear();
bool packed_error = false;
@@ -18920,21 +19041,16 @@ bool FollowerEvent::ParseFromArray(const void* raw, size_t size) {
_has_field_.set(field.id());
}
switch (field.id()) {
- case 1 /* counter */:
- field.get(&counter_);
- break;
- case 2 /* tracepoint */:
- (*tracepoint_).ParseFromArray(field.data(), field.size());
- break;
- case 3 /* raw_event */:
- (*raw_event_).ParseFromArray(field.data(), field.size());
+ case 1 /* chunks_to_move */:
+ chunks_to_move_.emplace_back();
+ chunks_to_move_.back().ParseFromArray(field.data(), field.size());
break;
- case 5 /* modifiers */:
- modifiers_.emplace_back();
- field.get(&modifiers_.back());
+ case 2 /* chunks_to_patch */:
+ chunks_to_patch_.emplace_back();
+ chunks_to_patch_.back().ParseFromArray(field.data(), field.size());
break;
- case 4 /* name */:
- ::protozero::internal::gen_helpers::DeserializeString(field, &name_);
+ case 3 /* flush_request_id */:
+ field.get(&flush_request_id_);
break;
default:
field.SerializeAndAppendTo(&unknown_fields_);
@@ -18944,65 +19060,59 @@ bool FollowerEvent::ParseFromArray(const void* raw, size_t size) {
return !packed_error && !dec.bytes_left();
}
-std::string FollowerEvent::SerializeAsString() const {
+std::string CommitDataRequest::SerializeAsString() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsString();
}
-std::vector<uint8_t> FollowerEvent::SerializeAsArray() const {
+std::vector<uint8_t> CommitDataRequest::SerializeAsArray() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsArray();
}
-void FollowerEvent::Serialize(::protozero::Message* msg) const {
- // Field 1: counter
- if (_has_field_[1]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(1, counter_, msg);
+void CommitDataRequest::Serialize(::protozero::Message* msg) const {
+ // Field 1: chunks_to_move
+ for (auto& it : chunks_to_move_) {
+ it.Serialize(msg->BeginNestedMessage<::protozero::Message>(1));
}
- // Field 2: tracepoint
- if (_has_field_[2]) {
- (*tracepoint_).Serialize(msg->BeginNestedMessage<::protozero::Message>(2));
+ // Field 2: chunks_to_patch
+ for (auto& it : chunks_to_patch_) {
+ it.Serialize(msg->BeginNestedMessage<::protozero::Message>(2));
}
- // Field 3: raw_event
+ // Field 3: flush_request_id
if (_has_field_[3]) {
- (*raw_event_).Serialize(msg->BeginNestedMessage<::protozero::Message>(3));
- }
-
- // Field 5: modifiers
- for (auto& it : modifiers_) {
- ::protozero::internal::gen_helpers::SerializeVarInt(5, it, msg);
- }
-
- // Field 4: name
- if (_has_field_[4]) {
- ::protozero::internal::gen_helpers::SerializeString(4, name_, msg);
+ ::protozero::internal::gen_helpers::SerializeVarInt(3, flush_request_id_, msg);
}
protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
}
-PerfEvents_RawEvent::PerfEvents_RawEvent() = default;
-PerfEvents_RawEvent::~PerfEvents_RawEvent() = default;
-PerfEvents_RawEvent::PerfEvents_RawEvent(const PerfEvents_RawEvent&) = default;
-PerfEvents_RawEvent& PerfEvents_RawEvent::operator=(const PerfEvents_RawEvent&) = default;
-PerfEvents_RawEvent::PerfEvents_RawEvent(PerfEvents_RawEvent&&) noexcept = default;
-PerfEvents_RawEvent& PerfEvents_RawEvent::operator=(PerfEvents_RawEvent&&) = default;
+CommitDataRequest_ChunkToPatch::CommitDataRequest_ChunkToPatch() = default;
+CommitDataRequest_ChunkToPatch::~CommitDataRequest_ChunkToPatch() = default;
+CommitDataRequest_ChunkToPatch::CommitDataRequest_ChunkToPatch(const CommitDataRequest_ChunkToPatch&) = default;
+CommitDataRequest_ChunkToPatch& CommitDataRequest_ChunkToPatch::operator=(const CommitDataRequest_ChunkToPatch&) = default;
+CommitDataRequest_ChunkToPatch::CommitDataRequest_ChunkToPatch(CommitDataRequest_ChunkToPatch&&) noexcept = default;
+CommitDataRequest_ChunkToPatch& CommitDataRequest_ChunkToPatch::operator=(CommitDataRequest_ChunkToPatch&&) = default;
-bool PerfEvents_RawEvent::operator==(const PerfEvents_RawEvent& other) const {
+bool CommitDataRequest_ChunkToPatch::operator==(const CommitDataRequest_ChunkToPatch& other) const {
return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
- && ::protozero::internal::gen_helpers::EqualsField(type_, other.type_)
- && ::protozero::internal::gen_helpers::EqualsField(config_, other.config_)
- && ::protozero::internal::gen_helpers::EqualsField(config1_, other.config1_)
- && ::protozero::internal::gen_helpers::EqualsField(config2_, other.config2_)
- && ::protozero::internal::gen_helpers::EqualsField(pmu_name_, other.pmu_name_);
+ && ::protozero::internal::gen_helpers::EqualsField(target_buffer_, other.target_buffer_)
+ && ::protozero::internal::gen_helpers::EqualsField(writer_id_, other.writer_id_)
+ && ::protozero::internal::gen_helpers::EqualsField(chunk_id_, other.chunk_id_)
+ && ::protozero::internal::gen_helpers::EqualsField(patches_, other.patches_)
+ && ::protozero::internal::gen_helpers::EqualsField(has_more_patches_, other.has_more_patches_);
}
-bool PerfEvents_RawEvent::ParseFromArray(const void* raw, size_t size) {
+int CommitDataRequest_ChunkToPatch::patches_size() const { return static_cast<int>(patches_.size()); }
+void CommitDataRequest_ChunkToPatch::clear_patches() { patches_.clear(); }
+CommitDataRequest_ChunkToPatch_Patch* CommitDataRequest_ChunkToPatch::add_patches() { patches_.emplace_back(); return &patches_.back(); }
+bool CommitDataRequest_ChunkToPatch::ParseFromArray(const void* raw, size_t size) {
+ patches_.clear();
unknown_fields_.clear();
bool packed_error = false;
@@ -19012,20 +19122,21 @@ bool PerfEvents_RawEvent::ParseFromArray(const void* raw, size_t size) {
_has_field_.set(field.id());
}
switch (field.id()) {
- case 1 /* type */:
- field.get(&type_);
+ case 1 /* target_buffer */:
+ field.get(&target_buffer_);
break;
- case 2 /* config */:
- field.get(&config_);
+ case 2 /* writer_id */:
+ field.get(&writer_id_);
break;
- case 3 /* config1 */:
- field.get(&config1_);
+ case 3 /* chunk_id */:
+ field.get(&chunk_id_);
break;
- case 4 /* config2 */:
- field.get(&config2_);
+ case 4 /* patches */:
+ patches_.emplace_back();
+ patches_.back().ParseFromArray(field.data(), field.size());
break;
- case 5 /* pmu_name */:
- ::protozero::internal::gen_helpers::DeserializeString(field, &pmu_name_);
+ case 5 /* has_more_patches */:
+ field.get(&has_more_patches_);
break;
default:
field.SerializeAndAppendTo(&unknown_fields_);
@@ -19035,62 +19146,62 @@ bool PerfEvents_RawEvent::ParseFromArray(const void* raw, size_t size) {
return !packed_error && !dec.bytes_left();
}
-std::string PerfEvents_RawEvent::SerializeAsString() const {
+std::string CommitDataRequest_ChunkToPatch::SerializeAsString() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsString();
}
-std::vector<uint8_t> PerfEvents_RawEvent::SerializeAsArray() const {
+std::vector<uint8_t> CommitDataRequest_ChunkToPatch::SerializeAsArray() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsArray();
}
-void PerfEvents_RawEvent::Serialize(::protozero::Message* msg) const {
- // Field 1: type
+void CommitDataRequest_ChunkToPatch::Serialize(::protozero::Message* msg) const {
+ // Field 1: target_buffer
if (_has_field_[1]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(1, type_, msg);
+ ::protozero::internal::gen_helpers::SerializeVarInt(1, target_buffer_, msg);
}
- // Field 2: config
+ // Field 2: writer_id
if (_has_field_[2]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(2, config_, msg);
+ ::protozero::internal::gen_helpers::SerializeVarInt(2, writer_id_, msg);
}
- // Field 3: config1
+ // Field 3: chunk_id
if (_has_field_[3]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(3, config1_, msg);
+ ::protozero::internal::gen_helpers::SerializeVarInt(3, chunk_id_, msg);
}
- // Field 4: config2
- if (_has_field_[4]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(4, config2_, msg);
+ // Field 4: patches
+ for (auto& it : patches_) {
+ it.Serialize(msg->BeginNestedMessage<::protozero::Message>(4));
}
- // Field 5: pmu_name
+ // Field 5: has_more_patches
if (_has_field_[5]) {
- ::protozero::internal::gen_helpers::SerializeString(5, pmu_name_, msg);
+ ::protozero::internal::gen_helpers::SerializeTinyVarInt(5, has_more_patches_, msg);
}
protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
}
-PerfEvents_Tracepoint::PerfEvents_Tracepoint() = default;
-PerfEvents_Tracepoint::~PerfEvents_Tracepoint() = default;
-PerfEvents_Tracepoint::PerfEvents_Tracepoint(const PerfEvents_Tracepoint&) = default;
-PerfEvents_Tracepoint& PerfEvents_Tracepoint::operator=(const PerfEvents_Tracepoint&) = default;
-PerfEvents_Tracepoint::PerfEvents_Tracepoint(PerfEvents_Tracepoint&&) noexcept = default;
-PerfEvents_Tracepoint& PerfEvents_Tracepoint::operator=(PerfEvents_Tracepoint&&) = default;
+CommitDataRequest_ChunkToPatch_Patch::CommitDataRequest_ChunkToPatch_Patch() = default;
+CommitDataRequest_ChunkToPatch_Patch::~CommitDataRequest_ChunkToPatch_Patch() = default;
+CommitDataRequest_ChunkToPatch_Patch::CommitDataRequest_ChunkToPatch_Patch(const CommitDataRequest_ChunkToPatch_Patch&) = default;
+CommitDataRequest_ChunkToPatch_Patch& CommitDataRequest_ChunkToPatch_Patch::operator=(const CommitDataRequest_ChunkToPatch_Patch&) = default;
+CommitDataRequest_ChunkToPatch_Patch::CommitDataRequest_ChunkToPatch_Patch(CommitDataRequest_ChunkToPatch_Patch&&) noexcept = default;
+CommitDataRequest_ChunkToPatch_Patch& CommitDataRequest_ChunkToPatch_Patch::operator=(CommitDataRequest_ChunkToPatch_Patch&&) = default;
-bool PerfEvents_Tracepoint::operator==(const PerfEvents_Tracepoint& other) const {
+bool CommitDataRequest_ChunkToPatch_Patch::operator==(const CommitDataRequest_ChunkToPatch_Patch& other) const {
return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
- && ::protozero::internal::gen_helpers::EqualsField(name_, other.name_)
- && ::protozero::internal::gen_helpers::EqualsField(filter_, other.filter_);
+ && ::protozero::internal::gen_helpers::EqualsField(offset_, other.offset_)
+ && ::protozero::internal::gen_helpers::EqualsField(data_, other.data_);
}
-bool PerfEvents_Tracepoint::ParseFromArray(const void* raw, size_t size) {
+bool CommitDataRequest_ChunkToPatch_Patch::ParseFromArray(const void* raw, size_t size) {
unknown_fields_.clear();
bool packed_error = false;
@@ -19100,11 +19211,11 @@ bool PerfEvents_Tracepoint::ParseFromArray(const void* raw, size_t size) {
_has_field_.set(field.id());
}
switch (field.id()) {
- case 1 /* name */:
- ::protozero::internal::gen_helpers::DeserializeString(field, &name_);
+ case 1 /* offset */:
+ field.get(&offset_);
break;
- case 2 /* filter */:
- ::protozero::internal::gen_helpers::DeserializeString(field, &filter_);
+ case 2 /* data */:
+ field.get(&data_);
break;
default:
field.SerializeAndAppendTo(&unknown_fields_);
@@ -19114,45 +19225,50 @@ bool PerfEvents_Tracepoint::ParseFromArray(const void* raw, size_t size) {
return !packed_error && !dec.bytes_left();
}
-std::string PerfEvents_Tracepoint::SerializeAsString() const {
+std::string CommitDataRequest_ChunkToPatch_Patch::SerializeAsString() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsString();
}
-std::vector<uint8_t> PerfEvents_Tracepoint::SerializeAsArray() const {
+std::vector<uint8_t> CommitDataRequest_ChunkToPatch_Patch::SerializeAsArray() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsArray();
}
-void PerfEvents_Tracepoint::Serialize(::protozero::Message* msg) const {
- // Field 1: name
+void CommitDataRequest_ChunkToPatch_Patch::Serialize(::protozero::Message* msg) const {
+ // Field 1: offset
if (_has_field_[1]) {
- ::protozero::internal::gen_helpers::SerializeString(1, name_, msg);
+ ::protozero::internal::gen_helpers::SerializeVarInt(1, offset_, msg);
}
- // Field 2: filter
+ // Field 2: data
if (_has_field_[2]) {
- ::protozero::internal::gen_helpers::SerializeString(2, filter_, msg);
+ ::protozero::internal::gen_helpers::SerializeString(2, data_, msg);
}
protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
}
-PerfEvents::PerfEvents() = default;
-PerfEvents::~PerfEvents() = default;
-PerfEvents::PerfEvents(const PerfEvents&) = default;
-PerfEvents& PerfEvents::operator=(const PerfEvents&) = default;
-PerfEvents::PerfEvents(PerfEvents&&) noexcept = default;
-PerfEvents& PerfEvents::operator=(PerfEvents&&) = default;
+CommitDataRequest_ChunksToMove::CommitDataRequest_ChunksToMove() = default;
+CommitDataRequest_ChunksToMove::~CommitDataRequest_ChunksToMove() = default;
+CommitDataRequest_ChunksToMove::CommitDataRequest_ChunksToMove(const CommitDataRequest_ChunksToMove&) = default;
+CommitDataRequest_ChunksToMove& CommitDataRequest_ChunksToMove::operator=(const CommitDataRequest_ChunksToMove&) = default;
+CommitDataRequest_ChunksToMove::CommitDataRequest_ChunksToMove(CommitDataRequest_ChunksToMove&&) noexcept = default;
+CommitDataRequest_ChunksToMove& CommitDataRequest_ChunksToMove::operator=(CommitDataRequest_ChunksToMove&&) = default;
-bool PerfEvents::operator==(const PerfEvents& other) const {
- return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_);
+bool CommitDataRequest_ChunksToMove::operator==(const CommitDataRequest_ChunksToMove& other) const {
+ return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
+ && ::protozero::internal::gen_helpers::EqualsField(page_, other.page_)
+ && ::protozero::internal::gen_helpers::EqualsField(chunk_, other.chunk_)
+ && ::protozero::internal::gen_helpers::EqualsField(target_buffer_, other.target_buffer_)
+ && ::protozero::internal::gen_helpers::EqualsField(data_, other.data_)
+ && ::protozero::internal::gen_helpers::EqualsField(chunk_incomplete_, other.chunk_incomplete_);
}
-bool PerfEvents::ParseFromArray(const void* raw, size_t size) {
+bool CommitDataRequest_ChunksToMove::ParseFromArray(const void* raw, size_t size) {
unknown_fields_.clear();
bool packed_error = false;
@@ -19162,6 +19278,21 @@ bool PerfEvents::ParseFromArray(const void* raw, size_t size) {
_has_field_.set(field.id());
}
switch (field.id()) {
+ case 1 /* page */:
+ field.get(&page_);
+ break;
+ case 2 /* chunk */:
+ field.get(&chunk_);
+ break;
+ case 3 /* target_buffer */:
+ field.get(&target_buffer_);
+ break;
+ case 4 /* data */:
+ field.get(&data_);
+ break;
+ case 5 /* chunk_incomplete */:
+ field.get(&chunk_incomplete_);
+ break;
default:
field.SerializeAndAppendTo(&unknown_fields_);
break;
@@ -19170,45 +19301,92 @@ bool PerfEvents::ParseFromArray(const void* raw, size_t size) {
return !packed_error && !dec.bytes_left();
}
-std::string PerfEvents::SerializeAsString() const {
+std::string CommitDataRequest_ChunksToMove::SerializeAsString() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsString();
}
-std::vector<uint8_t> PerfEvents::SerializeAsArray() const {
+std::vector<uint8_t> CommitDataRequest_ChunksToMove::SerializeAsArray() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsArray();
}
-void PerfEvents::Serialize(::protozero::Message* msg) const {
+void CommitDataRequest_ChunksToMove::Serialize(::protozero::Message* msg) const {
+ // Field 1: page
+ if (_has_field_[1]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(1, page_, msg);
+ }
+
+ // Field 2: chunk
+ if (_has_field_[2]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(2, chunk_, msg);
+ }
+
+ // Field 3: target_buffer
+ if (_has_field_[3]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(3, target_buffer_, msg);
+ }
+
+ // Field 4: data
+ if (_has_field_[4]) {
+ ::protozero::internal::gen_helpers::SerializeString(4, data_, msg);
+ }
+
+ // Field 5: chunk_incomplete
+ if (_has_field_[5]) {
+ ::protozero::internal::gen_helpers::SerializeTinyVarInt(5, chunk_incomplete_, msg);
+ }
+
protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
}
+} // namespace perfetto
+} // namespace protos
+} // namespace gen
+#if defined(__GNUC__) || defined(__clang__)
+#pragma GCC diagnostic pop
+#endif
+// gen_amalgamated begin source: gen/protos/perfetto/common/data_source_descriptor.gen.cc
+// gen_amalgamated expanded: #include "perfetto/protozero/gen_field_helpers.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/message.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/packed_repeated_fields.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/proto_decoder.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/scattered_heap_buffer.h"
+// DO NOT EDIT. Autogenerated by Perfetto cppgen_plugin
+#if defined(__GNUC__) || defined(__clang__)
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wfloat-equal"
+#endif
+// gen_amalgamated expanded: #include "protos/perfetto/common/data_source_descriptor.gen.h"
+
+namespace perfetto {
+namespace protos {
+namespace gen {
-PerfEvents_Timebase::PerfEvents_Timebase() = default;
-PerfEvents_Timebase::~PerfEvents_Timebase() = default;
-PerfEvents_Timebase::PerfEvents_Timebase(const PerfEvents_Timebase&) = default;
-PerfEvents_Timebase& PerfEvents_Timebase::operator=(const PerfEvents_Timebase&) = default;
-PerfEvents_Timebase::PerfEvents_Timebase(PerfEvents_Timebase&&) noexcept = default;
-PerfEvents_Timebase& PerfEvents_Timebase::operator=(PerfEvents_Timebase&&) = default;
+DataSourceDescriptor::DataSourceDescriptor() = default;
+DataSourceDescriptor::~DataSourceDescriptor() = default;
+DataSourceDescriptor::DataSourceDescriptor(const DataSourceDescriptor&) = default;
+DataSourceDescriptor& DataSourceDescriptor::operator=(const DataSourceDescriptor&) = default;
+DataSourceDescriptor::DataSourceDescriptor(DataSourceDescriptor&&) noexcept = default;
+DataSourceDescriptor& DataSourceDescriptor::operator=(DataSourceDescriptor&&) = default;
-bool PerfEvents_Timebase::operator==(const PerfEvents_Timebase& other) const {
+bool DataSourceDescriptor::operator==(const DataSourceDescriptor& other) const {
return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
- && ::protozero::internal::gen_helpers::EqualsField(frequency_, other.frequency_)
- && ::protozero::internal::gen_helpers::EqualsField(period_, other.period_)
- && ::protozero::internal::gen_helpers::EqualsField(poll_period_ms_, other.poll_period_ms_)
- && ::protozero::internal::gen_helpers::EqualsField(counter_, other.counter_)
- && ::protozero::internal::gen_helpers::EqualsField(tracepoint_, other.tracepoint_)
- && ::protozero::internal::gen_helpers::EqualsField(raw_event_, other.raw_event_)
- && ::protozero::internal::gen_helpers::EqualsField(modifiers_, other.modifiers_)
- && ::protozero::internal::gen_helpers::EqualsField(timestamp_clock_, other.timestamp_clock_)
- && ::protozero::internal::gen_helpers::EqualsField(name_, other.name_);
+ && ::protozero::internal::gen_helpers::EqualsField(name_, other.name_)
+ && ::protozero::internal::gen_helpers::EqualsField(id_, other.id_)
+ && ::protozero::internal::gen_helpers::EqualsField(will_notify_on_stop_, other.will_notify_on_stop_)
+ && ::protozero::internal::gen_helpers::EqualsField(will_notify_on_start_, other.will_notify_on_start_)
+ && ::protozero::internal::gen_helpers::EqualsField(handles_incremental_state_clear_, other.handles_incremental_state_clear_)
+ && ::protozero::internal::gen_helpers::EqualsField(no_flush_, other.no_flush_)
+ && ::protozero::internal::gen_helpers::EqualsField(protovm_program_, other.protovm_program_)
+ && ::protozero::internal::gen_helpers::EqualsField(gpu_counter_descriptor_, other.gpu_counter_descriptor_)
+ && ::protozero::internal::gen_helpers::EqualsField(track_event_descriptor_, other.track_event_descriptor_)
+ && ::protozero::internal::gen_helpers::EqualsField(ftrace_descriptor_, other.ftrace_descriptor_);
}
-bool PerfEvents_Timebase::ParseFromArray(const void* raw, size_t size) {
- modifiers_.clear();
+bool DataSourceDescriptor::ParseFromArray(const void* raw, size_t size) {
unknown_fields_.clear();
bool packed_error = false;
@@ -19218,33 +19396,35 @@ bool PerfEvents_Timebase::ParseFromArray(const void* raw, size_t size) {
_has_field_.set(field.id());
}
switch (field.id()) {
- case 2 /* frequency */:
- field.get(&frequency_);
+ case 1 /* name */:
+ ::protozero::internal::gen_helpers::DeserializeString(field, &name_);
break;
- case 1 /* period */:
- field.get(&period_);
+ case 7 /* id */:
+ field.get(&id_);
break;
- case 6 /* poll_period_ms */:
- field.get(&poll_period_ms_);
+ case 2 /* will_notify_on_stop */:
+ field.get(&will_notify_on_stop_);
break;
- case 4 /* counter */:
- field.get(&counter_);
+ case 3 /* will_notify_on_start */:
+ field.get(&will_notify_on_start_);
break;
- case 3 /* tracepoint */:
- (*tracepoint_).ParseFromArray(field.data(), field.size());
+ case 4 /* handles_incremental_state_clear */:
+ field.get(&handles_incremental_state_clear_);
break;
- case 5 /* raw_event */:
- (*raw_event_).ParseFromArray(field.data(), field.size());
+ case 9 /* no_flush */:
+ field.get(&no_flush_);
break;
- case 12 /* modifiers */:
- modifiers_.emplace_back();
- field.get(&modifiers_.back());
+ case 10 /* protovm_program */:
+ ::protozero::internal::gen_helpers::DeserializeString(field, &protovm_program_);
break;
- case 11 /* timestamp_clock */:
- field.get(×tamp_clock_);
+ case 5 /* gpu_counter_descriptor */:
+ ::protozero::internal::gen_helpers::DeserializeString(field, &gpu_counter_descriptor_);
break;
- case 10 /* name */:
- ::protozero::internal::gen_helpers::DeserializeString(field, &name_);
+ case 6 /* track_event_descriptor */:
+ ::protozero::internal::gen_helpers::DeserializeString(field, &track_event_descriptor_);
+ break;
+ case 8 /* ftrace_descriptor */:
+ ::protozero::internal::gen_helpers::DeserializeString(field, &ftrace_descriptor_);
break;
default:
field.SerializeAndAppendTo(&unknown_fields_);
@@ -19254,62 +19434,67 @@ bool PerfEvents_Timebase::ParseFromArray(const void* raw, size_t size) {
return !packed_error && !dec.bytes_left();
}
-std::string PerfEvents_Timebase::SerializeAsString() const {
+std::string DataSourceDescriptor::SerializeAsString() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsString();
}
-std::vector<uint8_t> PerfEvents_Timebase::SerializeAsArray() const {
+std::vector<uint8_t> DataSourceDescriptor::SerializeAsArray() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsArray();
}
-void PerfEvents_Timebase::Serialize(::protozero::Message* msg) const {
- // Field 2: frequency
- if (_has_field_[2]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(2, frequency_, msg);
+void DataSourceDescriptor::Serialize(::protozero::Message* msg) const {
+ // Field 1: name
+ if (_has_field_[1]) {
+ ::protozero::internal::gen_helpers::SerializeString(1, name_, msg);
}
- // Field 1: period
- if (_has_field_[1]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(1, period_, msg);
+ // Field 7: id
+ if (_has_field_[7]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(7, id_, msg);
}
- // Field 6: poll_period_ms
- if (_has_field_[6]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(6, poll_period_ms_, msg);
+ // Field 2: will_notify_on_stop
+ if (_has_field_[2]) {
+ ::protozero::internal::gen_helpers::SerializeTinyVarInt(2, will_notify_on_stop_, msg);
}
- // Field 4: counter
+ // Field 3: will_notify_on_start
+ if (_has_field_[3]) {
+ ::protozero::internal::gen_helpers::SerializeTinyVarInt(3, will_notify_on_start_, msg);
+ }
+
+ // Field 4: handles_incremental_state_clear
if (_has_field_[4]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(4, counter_, msg);
+ ::protozero::internal::gen_helpers::SerializeTinyVarInt(4, handles_incremental_state_clear_, msg);
}
- // Field 3: tracepoint
- if (_has_field_[3]) {
- (*tracepoint_).Serialize(msg->BeginNestedMessage<::protozero::Message>(3));
+ // Field 9: no_flush
+ if (_has_field_[9]) {
+ ::protozero::internal::gen_helpers::SerializeTinyVarInt(9, no_flush_, msg);
}
- // Field 5: raw_event
- if (_has_field_[5]) {
- (*raw_event_).Serialize(msg->BeginNestedMessage<::protozero::Message>(5));
+ // Field 10: protovm_program
+ if (_has_field_[10]) {
+ msg->AppendString(10, protovm_program_);
}
- // Field 12: modifiers
- for (auto& it : modifiers_) {
- ::protozero::internal::gen_helpers::SerializeVarInt(12, it, msg);
+ // Field 5: gpu_counter_descriptor
+ if (_has_field_[5]) {
+ msg->AppendString(5, gpu_counter_descriptor_);
}
- // Field 11: timestamp_clock
- if (_has_field_[11]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(11, timestamp_clock_, msg);
+ // Field 6: track_event_descriptor
+ if (_has_field_[6]) {
+ msg->AppendString(6, track_event_descriptor_);
}
- // Field 10: name
- if (_has_field_[10]) {
- ::protozero::internal::gen_helpers::SerializeString(10, name_, msg);
+ // Field 8: ftrace_descriptor
+ if (_has_field_[8]) {
+ msg->AppendString(8, ftrace_descriptor_);
}
protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
@@ -19321,29 +19506,7 @@ void PerfEvents_Timebase::Serialize(::protozero::Message* msg) const {
#if defined(__GNUC__) || defined(__clang__)
#pragma GCC diagnostic pop
#endif
-// gen_amalgamated begin source: gen/protos/perfetto/common/sys_stats_counters.gen.cc
-// gen_amalgamated expanded: #include "perfetto/protozero/gen_field_helpers.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/message.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/packed_repeated_fields.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/proto_decoder.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/scattered_heap_buffer.h"
-// DO NOT EDIT. Autogenerated by Perfetto cppgen_plugin
-#if defined(__GNUC__) || defined(__clang__)
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wfloat-equal"
-#endif
-// gen_amalgamated expanded: #include "protos/perfetto/common/sys_stats_counters.gen.h"
-
-namespace perfetto {
-namespace protos {
-namespace gen {
-} // namespace perfetto
-} // namespace protos
-} // namespace gen
-#if defined(__GNUC__) || defined(__clang__)
-#pragma GCC diagnostic pop
-#endif
-// gen_amalgamated begin source: gen/protos/perfetto/common/system_info.gen.cc
+// gen_amalgamated begin source: gen/protos/perfetto/common/descriptor.gen.cc
// gen_amalgamated expanded: #include "perfetto/protozero/gen_field_helpers.h"
// gen_amalgamated expanded: #include "perfetto/protozero/message.h"
// gen_amalgamated expanded: #include "perfetto/protozero/packed_repeated_fields.h"
@@ -19354,41 +19517,24 @@ namespace gen {
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wfloat-equal"
#endif
-// gen_amalgamated expanded: #include "protos/perfetto/common/system_info.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/common/descriptor.gen.h"
namespace perfetto {
namespace protos {
namespace gen {
-SystemInfo::SystemInfo() = default;
-SystemInfo::~SystemInfo() = default;
-SystemInfo::SystemInfo(const SystemInfo&) = default;
-SystemInfo& SystemInfo::operator=(const SystemInfo&) = default;
-SystemInfo::SystemInfo(SystemInfo&&) noexcept = default;
-SystemInfo& SystemInfo::operator=(SystemInfo&&) = default;
+OneofOptions::OneofOptions() = default;
+OneofOptions::~OneofOptions() = default;
+OneofOptions::OneofOptions(const OneofOptions&) = default;
+OneofOptions& OneofOptions::operator=(const OneofOptions&) = default;
+OneofOptions::OneofOptions(OneofOptions&&) noexcept = default;
+OneofOptions& OneofOptions::operator=(OneofOptions&&) = default;
-bool SystemInfo::operator==(const SystemInfo& other) const {
- return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
- && ::protozero::internal::gen_helpers::EqualsField(utsname_, other.utsname_)
- && ::protozero::internal::gen_helpers::EqualsField(android_build_fingerprint_, other.android_build_fingerprint_)
- && ::protozero::internal::gen_helpers::EqualsField(android_device_manufacturer_, other.android_device_manufacturer_)
- && ::protozero::internal::gen_helpers::EqualsField(android_soc_model_, other.android_soc_model_)
- && ::protozero::internal::gen_helpers::EqualsField(android_guest_soc_model_, other.android_guest_soc_model_)
- && ::protozero::internal::gen_helpers::EqualsField(android_hardware_revision_, other.android_hardware_revision_)
- && ::protozero::internal::gen_helpers::EqualsField(android_storage_model_, other.android_storage_model_)
- && ::protozero::internal::gen_helpers::EqualsField(android_ram_model_, other.android_ram_model_)
- && ::protozero::internal::gen_helpers::EqualsField(android_serial_console_, other.android_serial_console_)
- && ::protozero::internal::gen_helpers::EqualsField(tracing_service_version_, other.tracing_service_version_)
- && ::protozero::internal::gen_helpers::EqualsField(android_sdk_version_, other.android_sdk_version_)
- && ::protozero::internal::gen_helpers::EqualsField(page_size_, other.page_size_)
- && ::protozero::internal::gen_helpers::EqualsField(num_cpus_, other.num_cpus_)
- && ::protozero::internal::gen_helpers::EqualsField(timezone_off_mins_, other.timezone_off_mins_)
- && ::protozero::internal::gen_helpers::EqualsField(hz_, other.hz_)
- && ::protozero::internal::gen_helpers::EqualsField(system_ram_bytes_, other.system_ram_bytes_)
- && ::protozero::internal::gen_helpers::EqualsField(machine_name_, other.machine_name_);
+bool OneofOptions::operator==(const OneofOptions& other) const {
+ return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_);
}
-bool SystemInfo::ParseFromArray(const void* raw, size_t size) {
+bool OneofOptions::ParseFromArray(const void* raw, size_t size) {
unknown_fields_.clear();
bool packed_error = false;
@@ -19398,57 +19544,6 @@ bool SystemInfo::ParseFromArray(const void* raw, size_t size) {
_has_field_.set(field.id());
}
switch (field.id()) {
- case 1 /* utsname */:
- (*utsname_).ParseFromArray(field.data(), field.size());
- break;
- case 2 /* android_build_fingerprint */:
- ::protozero::internal::gen_helpers::DeserializeString(field, &android_build_fingerprint_);
- break;
- case 14 /* android_device_manufacturer */:
- ::protozero::internal::gen_helpers::DeserializeString(field, &android_device_manufacturer_);
- break;
- case 9 /* android_soc_model */:
- ::protozero::internal::gen_helpers::DeserializeString(field, &android_soc_model_);
- break;
- case 13 /* android_guest_soc_model */:
- ::protozero::internal::gen_helpers::DeserializeString(field, &android_guest_soc_model_);
- break;
- case 10 /* android_hardware_revision */:
- ::protozero::internal::gen_helpers::DeserializeString(field, &android_hardware_revision_);
- break;
- case 11 /* android_storage_model */:
- ::protozero::internal::gen_helpers::DeserializeString(field, &android_storage_model_);
- break;
- case 12 /* android_ram_model */:
- ::protozero::internal::gen_helpers::DeserializeString(field, &android_ram_model_);
- break;
- case 15 /* android_serial_console */:
- ::protozero::internal::gen_helpers::DeserializeString(field, &android_serial_console_);
- break;
- case 4 /* tracing_service_version */:
- ::protozero::internal::gen_helpers::DeserializeString(field, &tracing_service_version_);
- break;
- case 5 /* android_sdk_version */:
- field.get(&android_sdk_version_);
- break;
- case 6 /* page_size */:
- field.get(&page_size_);
- break;
- case 8 /* num_cpus */:
- field.get(&num_cpus_);
- break;
- case 7 /* timezone_off_mins */:
- field.get(&timezone_off_mins_);
- break;
- case 3 /* hz */:
- field.get(&hz_);
- break;
- case 16 /* system_ram_bytes */:
- field.get(&system_ram_bytes_);
- break;
- case 17 /* machine_name */:
- ::protozero::internal::gen_helpers::DeserializeString(field, &machine_name_);
- break;
default:
field.SerializeAndAppendTo(&unknown_fields_);
break;
@@ -19457,124 +19552,107 @@ bool SystemInfo::ParseFromArray(const void* raw, size_t size) {
return !packed_error && !dec.bytes_left();
}
-std::string SystemInfo::SerializeAsString() const {
+std::string OneofOptions::SerializeAsString() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsString();
}
-std::vector<uint8_t> SystemInfo::SerializeAsArray() const {
+std::vector<uint8_t> OneofOptions::SerializeAsArray() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsArray();
}
-void SystemInfo::Serialize(::protozero::Message* msg) const {
- // Field 1: utsname
- if (_has_field_[1]) {
- (*utsname_).Serialize(msg->BeginNestedMessage<::protozero::Message>(1));
- }
-
- // Field 2: android_build_fingerprint
- if (_has_field_[2]) {
- ::protozero::internal::gen_helpers::SerializeString(2, android_build_fingerprint_, msg);
- }
-
- // Field 14: android_device_manufacturer
- if (_has_field_[14]) {
- ::protozero::internal::gen_helpers::SerializeString(14, android_device_manufacturer_, msg);
- }
-
- // Field 9: android_soc_model
- if (_has_field_[9]) {
- ::protozero::internal::gen_helpers::SerializeString(9, android_soc_model_, msg);
- }
-
- // Field 13: android_guest_soc_model
- if (_has_field_[13]) {
- ::protozero::internal::gen_helpers::SerializeString(13, android_guest_soc_model_, msg);
- }
-
- // Field 10: android_hardware_revision
- if (_has_field_[10]) {
- ::protozero::internal::gen_helpers::SerializeString(10, android_hardware_revision_, msg);
- }
-
- // Field 11: android_storage_model
- if (_has_field_[11]) {
- ::protozero::internal::gen_helpers::SerializeString(11, android_storage_model_, msg);
- }
-
- // Field 12: android_ram_model
- if (_has_field_[12]) {
- ::protozero::internal::gen_helpers::SerializeString(12, android_ram_model_, msg);
- }
+void OneofOptions::Serialize(::protozero::Message* msg) const {
+ protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
+}
- // Field 15: android_serial_console
- if (_has_field_[15]) {
- ::protozero::internal::gen_helpers::SerializeString(15, android_serial_console_, msg);
- }
- // Field 4: tracing_service_version
- if (_has_field_[4]) {
- ::protozero::internal::gen_helpers::SerializeString(4, tracing_service_version_, msg);
- }
+EnumValueDescriptorProto::EnumValueDescriptorProto() = default;
+EnumValueDescriptorProto::~EnumValueDescriptorProto() = default;
+EnumValueDescriptorProto::EnumValueDescriptorProto(const EnumValueDescriptorProto&) = default;
+EnumValueDescriptorProto& EnumValueDescriptorProto::operator=(const EnumValueDescriptorProto&) = default;
+EnumValueDescriptorProto::EnumValueDescriptorProto(EnumValueDescriptorProto&&) noexcept = default;
+EnumValueDescriptorProto& EnumValueDescriptorProto::operator=(EnumValueDescriptorProto&&) = default;
- // Field 5: android_sdk_version
- if (_has_field_[5]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(5, android_sdk_version_, msg);
- }
+bool EnumValueDescriptorProto::operator==(const EnumValueDescriptorProto& other) const {
+ return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
+ && ::protozero::internal::gen_helpers::EqualsField(name_, other.name_)
+ && ::protozero::internal::gen_helpers::EqualsField(number_, other.number_);
+}
- // Field 6: page_size
- if (_has_field_[6]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(6, page_size_, msg);
- }
+bool EnumValueDescriptorProto::ParseFromArray(const void* raw, size_t size) {
+ unknown_fields_.clear();
+ bool packed_error = false;
- // Field 8: num_cpus
- if (_has_field_[8]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(8, num_cpus_, msg);
+ ::protozero::ProtoDecoder dec(raw, size);
+ for (auto field = dec.ReadField(); field.valid(); field = dec.ReadField()) {
+ if (field.id() < _has_field_.size()) {
+ _has_field_.set(field.id());
+ }
+ switch (field.id()) {
+ case 1 /* name */:
+ ::protozero::internal::gen_helpers::DeserializeString(field, &name_);
+ break;
+ case 2 /* number */:
+ field.get(&number_);
+ break;
+ default:
+ field.SerializeAndAppendTo(&unknown_fields_);
+ break;
+ }
}
+ return !packed_error && !dec.bytes_left();
+}
- // Field 7: timezone_off_mins
- if (_has_field_[7]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(7, timezone_off_mins_, msg);
- }
+std::string EnumValueDescriptorProto::SerializeAsString() const {
+ ::protozero::internal::gen_helpers::MessageSerializer msg;
+ Serialize(msg.get());
+ return msg.SerializeAsString();
+}
- // Field 3: hz
- if (_has_field_[3]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(3, hz_, msg);
- }
+std::vector<uint8_t> EnumValueDescriptorProto::SerializeAsArray() const {
+ ::protozero::internal::gen_helpers::MessageSerializer msg;
+ Serialize(msg.get());
+ return msg.SerializeAsArray();
+}
- // Field 16: system_ram_bytes
- if (_has_field_[16]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(16, system_ram_bytes_, msg);
+void EnumValueDescriptorProto::Serialize(::protozero::Message* msg) const {
+ // Field 1: name
+ if (_has_field_[1]) {
+ ::protozero::internal::gen_helpers::SerializeString(1, name_, msg);
}
- // Field 17: machine_name
- if (_has_field_[17]) {
- ::protozero::internal::gen_helpers::SerializeString(17, machine_name_, msg);
+ // Field 2: number
+ if (_has_field_[2]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(2, number_, msg);
}
protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
}
-Utsname::Utsname() = default;
-Utsname::~Utsname() = default;
-Utsname::Utsname(const Utsname&) = default;
-Utsname& Utsname::operator=(const Utsname&) = default;
-Utsname::Utsname(Utsname&&) noexcept = default;
-Utsname& Utsname::operator=(Utsname&&) = default;
+EnumDescriptorProto::EnumDescriptorProto() = default;
+EnumDescriptorProto::~EnumDescriptorProto() = default;
+EnumDescriptorProto::EnumDescriptorProto(const EnumDescriptorProto&) = default;
+EnumDescriptorProto& EnumDescriptorProto::operator=(const EnumDescriptorProto&) = default;
+EnumDescriptorProto::EnumDescriptorProto(EnumDescriptorProto&&) noexcept = default;
+EnumDescriptorProto& EnumDescriptorProto::operator=(EnumDescriptorProto&&) = default;
-bool Utsname::operator==(const Utsname& other) const {
+bool EnumDescriptorProto::operator==(const EnumDescriptorProto& other) const {
return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
- && ::protozero::internal::gen_helpers::EqualsField(sysname_, other.sysname_)
- && ::protozero::internal::gen_helpers::EqualsField(version_, other.version_)
- && ::protozero::internal::gen_helpers::EqualsField(release_, other.release_)
- && ::protozero::internal::gen_helpers::EqualsField(machine_, other.machine_);
+ && ::protozero::internal::gen_helpers::EqualsField(name_, other.name_)
+ && ::protozero::internal::gen_helpers::EqualsField(value_, other.value_)
+ && ::protozero::internal::gen_helpers::EqualsField(reserved_name_, other.reserved_name_);
}
-bool Utsname::ParseFromArray(const void* raw, size_t size) {
+int EnumDescriptorProto::value_size() const { return static_cast<int>(value_.size()); }
+void EnumDescriptorProto::clear_value() { value_.clear(); }
+EnumValueDescriptorProto* EnumDescriptorProto::add_value() { value_.emplace_back(); return &value_.back(); }
+bool EnumDescriptorProto::ParseFromArray(const void* raw, size_t size) {
+ value_.clear();
+ reserved_name_.clear();
unknown_fields_.clear();
bool packed_error = false;
@@ -19584,17 +19662,16 @@ bool Utsname::ParseFromArray(const void* raw, size_t size) {
_has_field_.set(field.id());
}
switch (field.id()) {
- case 1 /* sysname */:
- ::protozero::internal::gen_helpers::DeserializeString(field, &sysname_);
- break;
- case 2 /* version */:
- ::protozero::internal::gen_helpers::DeserializeString(field, &version_);
+ case 1 /* name */:
+ ::protozero::internal::gen_helpers::DeserializeString(field, &name_);
break;
- case 3 /* release */:
- ::protozero::internal::gen_helpers::DeserializeString(field, &release_);
+ case 2 /* value */:
+ value_.emplace_back();
+ value_.back().ParseFromArray(field.data(), field.size());
break;
- case 4 /* machine */:
- ::protozero::internal::gen_helpers::DeserializeString(field, &machine_);
+ case 5 /* reserved_name */:
+ reserved_name_.emplace_back();
+ ::protozero::internal::gen_helpers::DeserializeString(field, &reserved_name_.back());
break;
default:
field.SerializeAndAppendTo(&unknown_fields_);
@@ -19604,82 +19681,52 @@ bool Utsname::ParseFromArray(const void* raw, size_t size) {
return !packed_error && !dec.bytes_left();
}
-std::string Utsname::SerializeAsString() const {
+std::string EnumDescriptorProto::SerializeAsString() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsString();
}
-std::vector<uint8_t> Utsname::SerializeAsArray() const {
+std::vector<uint8_t> EnumDescriptorProto::SerializeAsArray() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsArray();
}
-void Utsname::Serialize(::protozero::Message* msg) const {
- // Field 1: sysname
+void EnumDescriptorProto::Serialize(::protozero::Message* msg) const {
+ // Field 1: name
if (_has_field_[1]) {
- ::protozero::internal::gen_helpers::SerializeString(1, sysname_, msg);
- }
-
- // Field 2: version
- if (_has_field_[2]) {
- ::protozero::internal::gen_helpers::SerializeString(2, version_, msg);
+ ::protozero::internal::gen_helpers::SerializeString(1, name_, msg);
}
- // Field 3: release
- if (_has_field_[3]) {
- ::protozero::internal::gen_helpers::SerializeString(3, release_, msg);
+ // Field 2: value
+ for (auto& it : value_) {
+ it.Serialize(msg->BeginNestedMessage<::protozero::Message>(2));
}
- // Field 4: machine
- if (_has_field_[4]) {
- ::protozero::internal::gen_helpers::SerializeString(4, machine_, msg);
+ // Field 5: reserved_name
+ for (auto& it : reserved_name_) {
+ ::protozero::internal::gen_helpers::SerializeString(5, it, msg);
}
protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
}
-} // namespace perfetto
-} // namespace protos
-} // namespace gen
-#if defined(__GNUC__) || defined(__clang__)
-#pragma GCC diagnostic pop
-#endif
-// gen_amalgamated begin source: gen/protos/perfetto/common/trace_attributes.gen.cc
-// gen_amalgamated expanded: #include "perfetto/protozero/gen_field_helpers.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/message.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/packed_repeated_fields.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/proto_decoder.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/scattered_heap_buffer.h"
-// DO NOT EDIT. Autogenerated by Perfetto cppgen_plugin
-#if defined(__GNUC__) || defined(__clang__)
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wfloat-equal"
-#endif
-// gen_amalgamated expanded: #include "protos/perfetto/common/trace_attributes.gen.h"
-
-namespace perfetto {
-namespace protos {
-namespace gen {
-TraceAttributes::TraceAttributes() = default;
-TraceAttributes::~TraceAttributes() = default;
-TraceAttributes::TraceAttributes(const TraceAttributes&) = default;
-TraceAttributes& TraceAttributes::operator=(const TraceAttributes&) = default;
-TraceAttributes::TraceAttributes(TraceAttributes&&) noexcept = default;
-TraceAttributes& TraceAttributes::operator=(TraceAttributes&&) = default;
+OneofDescriptorProto::OneofDescriptorProto() = default;
+OneofDescriptorProto::~OneofDescriptorProto() = default;
+OneofDescriptorProto::OneofDescriptorProto(const OneofDescriptorProto&) = default;
+OneofDescriptorProto& OneofDescriptorProto::operator=(const OneofDescriptorProto&) = default;
+OneofDescriptorProto::OneofDescriptorProto(OneofDescriptorProto&&) noexcept = default;
+OneofDescriptorProto& OneofDescriptorProto::operator=(OneofDescriptorProto&&) = default;
-bool TraceAttributes::operator==(const TraceAttributes& other) const {
+bool OneofDescriptorProto::operator==(const OneofDescriptorProto& other) const {
return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
- && ::protozero::internal::gen_helpers::EqualsField(attribute_, other.attribute_);
+ && ::protozero::internal::gen_helpers::EqualsField(name_, other.name_)
+ && ::protozero::internal::gen_helpers::EqualsField(options_, other.options_);
}
-int TraceAttributes::attribute_size() const { return static_cast<int>(attribute_.size()); }
-void TraceAttributes::clear_attribute() { attribute_.clear(); }
-TraceAttributes_Attribute* TraceAttributes::add_attribute() { attribute_.emplace_back(); return &attribute_.back(); }
-bool TraceAttributes::ParseFromArray(const void* raw, size_t size) {
- attribute_.clear();
+bool OneofDescriptorProto::ParseFromArray(const void* raw, size_t size) {
unknown_fields_.clear();
bool packed_error = false;
@@ -19689,9 +19736,11 @@ bool TraceAttributes::ParseFromArray(const void* raw, size_t size) {
_has_field_.set(field.id());
}
switch (field.id()) {
- case 1 /* attribute */:
- attribute_.emplace_back();
- attribute_.back().ParseFromArray(field.data(), field.size());
+ case 1 /* name */:
+ ::protozero::internal::gen_helpers::DeserializeString(field, &name_);
+ break;
+ case 2 /* options */:
+ (*options_).ParseFromArray(field.data(), field.size());
break;
default:
field.SerializeAndAppendTo(&unknown_fields_);
@@ -19701,43 +19750,54 @@ bool TraceAttributes::ParseFromArray(const void* raw, size_t size) {
return !packed_error && !dec.bytes_left();
}
-std::string TraceAttributes::SerializeAsString() const {
+std::string OneofDescriptorProto::SerializeAsString() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsString();
}
-std::vector<uint8_t> TraceAttributes::SerializeAsArray() const {
+std::vector<uint8_t> OneofDescriptorProto::SerializeAsArray() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsArray();
}
-void TraceAttributes::Serialize(::protozero::Message* msg) const {
- // Field 1: attribute
- for (auto& it : attribute_) {
- it.Serialize(msg->BeginNestedMessage<::protozero::Message>(1));
+void OneofDescriptorProto::Serialize(::protozero::Message* msg) const {
+ // Field 1: name
+ if (_has_field_[1]) {
+ ::protozero::internal::gen_helpers::SerializeString(1, name_, msg);
+ }
+
+ // Field 2: options
+ if (_has_field_[2]) {
+ (*options_).Serialize(msg->BeginNestedMessage<::protozero::Message>(2));
}
protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
}
-TraceAttributes_Attribute::TraceAttributes_Attribute() = default;
-TraceAttributes_Attribute::~TraceAttributes_Attribute() = default;
-TraceAttributes_Attribute::TraceAttributes_Attribute(const TraceAttributes_Attribute&) = default;
-TraceAttributes_Attribute& TraceAttributes_Attribute::operator=(const TraceAttributes_Attribute&) = default;
-TraceAttributes_Attribute::TraceAttributes_Attribute(TraceAttributes_Attribute&&) noexcept = default;
-TraceAttributes_Attribute& TraceAttributes_Attribute::operator=(TraceAttributes_Attribute&&) = default;
+FieldDescriptorProto::FieldDescriptorProto() = default;
+FieldDescriptorProto::~FieldDescriptorProto() = default;
+FieldDescriptorProto::FieldDescriptorProto(const FieldDescriptorProto&) = default;
+FieldDescriptorProto& FieldDescriptorProto::operator=(const FieldDescriptorProto&) = default;
+FieldDescriptorProto::FieldDescriptorProto(FieldDescriptorProto&&) noexcept = default;
+FieldDescriptorProto& FieldDescriptorProto::operator=(FieldDescriptorProto&&) = default;
-bool TraceAttributes_Attribute::operator==(const TraceAttributes_Attribute& other) const {
+bool FieldDescriptorProto::operator==(const FieldDescriptorProto& other) const {
return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
- && ::protozero::internal::gen_helpers::EqualsField(key_, other.key_)
- && ::protozero::internal::gen_helpers::EqualsField(long_value_, other.long_value_)
- && ::protozero::internal::gen_helpers::EqualsField(string_value_, other.string_value_);
+ && ::protozero::internal::gen_helpers::EqualsField(name_, other.name_)
+ && ::protozero::internal::gen_helpers::EqualsField(number_, other.number_)
+ && ::protozero::internal::gen_helpers::EqualsField(label_, other.label_)
+ && ::protozero::internal::gen_helpers::EqualsField(type_, other.type_)
+ && ::protozero::internal::gen_helpers::EqualsField(type_name_, other.type_name_)
+ && ::protozero::internal::gen_helpers::EqualsField(extendee_, other.extendee_)
+ && ::protozero::internal::gen_helpers::EqualsField(default_value_, other.default_value_)
+ && ::protozero::internal::gen_helpers::EqualsField(options_, other.options_)
+ && ::protozero::internal::gen_helpers::EqualsField(oneof_index_, other.oneof_index_);
}
-bool TraceAttributes_Attribute::ParseFromArray(const void* raw, size_t size) {
+bool FieldDescriptorProto::ParseFromArray(const void* raw, size_t size) {
unknown_fields_.clear();
bool packed_error = false;
@@ -19747,14 +19807,32 @@ bool TraceAttributes_Attribute::ParseFromArray(const void* raw, size_t size) {
_has_field_.set(field.id());
}
switch (field.id()) {
- case 1 /* key */:
- ::protozero::internal::gen_helpers::DeserializeString(field, &key_);
+ case 1 /* name */:
+ ::protozero::internal::gen_helpers::DeserializeString(field, &name_);
break;
- case 2 /* long_value */:
- field.get(&long_value_);
+ case 3 /* number */:
+ field.get(&number_);
break;
- case 3 /* string_value */:
- ::protozero::internal::gen_helpers::DeserializeString(field, &string_value_);
+ case 4 /* label */:
+ field.get(&label_);
+ break;
+ case 5 /* type */:
+ field.get(&type_);
+ break;
+ case 6 /* type_name */:
+ ::protozero::internal::gen_helpers::DeserializeString(field, &type_name_);
+ break;
+ case 2 /* extendee */:
+ ::protozero::internal::gen_helpers::DeserializeString(field, &extendee_);
+ break;
+ case 7 /* default_value */:
+ ::protozero::internal::gen_helpers::DeserializeString(field, &default_value_);
+ break;
+ case 8 /* options */:
+ (*options_).ParseFromArray(field.data(), field.size());
+ break;
+ case 9 /* oneof_index */:
+ field.get(&oneof_index_);
break;
default:
field.SerializeAndAppendTo(&unknown_fields_);
@@ -19764,98 +19842,86 @@ bool TraceAttributes_Attribute::ParseFromArray(const void* raw, size_t size) {
return !packed_error && !dec.bytes_left();
}
-std::string TraceAttributes_Attribute::SerializeAsString() const {
+std::string FieldDescriptorProto::SerializeAsString() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsString();
}
-std::vector<uint8_t> TraceAttributes_Attribute::SerializeAsArray() const {
+std::vector<uint8_t> FieldDescriptorProto::SerializeAsArray() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsArray();
}
-void TraceAttributes_Attribute::Serialize(::protozero::Message* msg) const {
- // Field 1: key
+void FieldDescriptorProto::Serialize(::protozero::Message* msg) const {
+ // Field 1: name
if (_has_field_[1]) {
- ::protozero::internal::gen_helpers::SerializeString(1, key_, msg);
- }
-
- // Field 2: long_value
- if (_has_field_[2]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(2, long_value_, msg);
+ ::protozero::internal::gen_helpers::SerializeString(1, name_, msg);
}
- // Field 3: string_value
+ // Field 3: number
if (_has_field_[3]) {
- ::protozero::internal::gen_helpers::SerializeString(3, string_value_, msg);
+ ::protozero::internal::gen_helpers::SerializeVarInt(3, number_, msg);
}
- protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
-}
+ // Field 4: label
+ if (_has_field_[4]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(4, label_, msg);
+ }
-} // namespace perfetto
-} // namespace protos
-} // namespace gen
-#if defined(__GNUC__) || defined(__clang__)
-#pragma GCC diagnostic pop
-#endif
-// gen_amalgamated begin source: gen/protos/perfetto/common/trace_stats.gen.cc
-// gen_amalgamated expanded: #include "perfetto/protozero/gen_field_helpers.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/message.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/packed_repeated_fields.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/proto_decoder.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/scattered_heap_buffer.h"
-// DO NOT EDIT. Autogenerated by Perfetto cppgen_plugin
-#if defined(__GNUC__) || defined(__clang__)
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wfloat-equal"
-#endif
-// gen_amalgamated expanded: #include "protos/perfetto/common/trace_stats.gen.h"
+ // Field 5: type
+ if (_has_field_[5]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(5, type_, msg);
+ }
-namespace perfetto {
-namespace protos {
-namespace gen {
+ // Field 6: type_name
+ if (_has_field_[6]) {
+ ::protozero::internal::gen_helpers::SerializeString(6, type_name_, msg);
+ }
-TraceStats::TraceStats() = default;
-TraceStats::~TraceStats() = default;
-TraceStats::TraceStats(const TraceStats&) = default;
-TraceStats& TraceStats::operator=(const TraceStats&) = default;
-TraceStats::TraceStats(TraceStats&&) noexcept = default;
-TraceStats& TraceStats::operator=(TraceStats&&) = default;
+ // Field 2: extendee
+ if (_has_field_[2]) {
+ ::protozero::internal::gen_helpers::SerializeString(2, extendee_, msg);
+ }
-bool TraceStats::operator==(const TraceStats& other) const {
+ // Field 7: default_value
+ if (_has_field_[7]) {
+ ::protozero::internal::gen_helpers::SerializeString(7, default_value_, msg);
+ }
+
+ // Field 8: options
+ if (_has_field_[8]) {
+ (*options_).Serialize(msg->BeginNestedMessage<::protozero::Message>(8));
+ }
+
+ // Field 9: oneof_index
+ if (_has_field_[9]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(9, oneof_index_, msg);
+ }
+
+ protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
+}
+
+
+FieldOptions::FieldOptions() = default;
+FieldOptions::~FieldOptions() = default;
+FieldOptions::FieldOptions(const FieldOptions&) = default;
+FieldOptions& FieldOptions::operator=(const FieldOptions&) = default;
+FieldOptions::FieldOptions(FieldOptions&&) noexcept = default;
+FieldOptions& FieldOptions::operator=(FieldOptions&&) = default;
+
+bool FieldOptions::operator==(const FieldOptions& other) const {
return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
- && ::protozero::internal::gen_helpers::EqualsField(buffer_stats_, other.buffer_stats_)
- && ::protozero::internal::gen_helpers::EqualsField(chunk_payload_histogram_def_, other.chunk_payload_histogram_def_)
- && ::protozero::internal::gen_helpers::EqualsField(writer_stats_, other.writer_stats_)
- && ::protozero::internal::gen_helpers::EqualsField(producers_connected_, other.producers_connected_)
- && ::protozero::internal::gen_helpers::EqualsField(producers_seen_, other.producers_seen_)
- && ::protozero::internal::gen_helpers::EqualsField(data_sources_registered_, other.data_sources_registered_)
- && ::protozero::internal::gen_helpers::EqualsField(data_sources_seen_, other.data_sources_seen_)
- && ::protozero::internal::gen_helpers::EqualsField(tracing_sessions_, other.tracing_sessions_)
- && ::protozero::internal::gen_helpers::EqualsField(total_buffers_, other.total_buffers_)
- && ::protozero::internal::gen_helpers::EqualsField(chunks_discarded_, other.chunks_discarded_)
- && ::protozero::internal::gen_helpers::EqualsField(patches_discarded_, other.patches_discarded_)
- && ::protozero::internal::gen_helpers::EqualsField(invalid_packets_, other.invalid_packets_)
- && ::protozero::internal::gen_helpers::EqualsField(filter_stats_, other.filter_stats_)
- && ::protozero::internal::gen_helpers::EqualsField(flushes_requested_, other.flushes_requested_)
- && ::protozero::internal::gen_helpers::EqualsField(flushes_succeeded_, other.flushes_succeeded_)
- && ::protozero::internal::gen_helpers::EqualsField(flushes_failed_, other.flushes_failed_)
- && ::protozero::internal::gen_helpers::EqualsField(final_flush_outcome_, other.final_flush_outcome_);
+ && ::protozero::internal::gen_helpers::EqualsField(packed_, other.packed_)
+ && ::protozero::internal::gen_helpers::EqualsField(uninterpreted_option_, other.uninterpreted_option_);
}
-int TraceStats::buffer_stats_size() const { return static_cast<int>(buffer_stats_.size()); }
-void TraceStats::clear_buffer_stats() { buffer_stats_.clear(); }
-TraceStats_BufferStats* TraceStats::add_buffer_stats() { buffer_stats_.emplace_back(); return &buffer_stats_.back(); }
-int TraceStats::writer_stats_size() const { return static_cast<int>(writer_stats_.size()); }
-void TraceStats::clear_writer_stats() { writer_stats_.clear(); }
-TraceStats_WriterStats* TraceStats::add_writer_stats() { writer_stats_.emplace_back(); return &writer_stats_.back(); }
-bool TraceStats::ParseFromArray(const void* raw, size_t size) {
- buffer_stats_.clear();
- chunk_payload_histogram_def_.clear();
- writer_stats_.clear();
+int FieldOptions::uninterpreted_option_size() const { return static_cast<int>(uninterpreted_option_.size()); }
+void FieldOptions::clear_uninterpreted_option() { uninterpreted_option_.clear(); }
+UninterpretedOption* FieldOptions::add_uninterpreted_option() { uninterpreted_option_.emplace_back(); return &uninterpreted_option_.back(); }
+bool FieldOptions::ParseFromArray(const void* raw, size_t size) {
+ uninterpreted_option_.clear();
unknown_fields_.clear();
bool packed_error = false;
@@ -19865,59 +19931,12 @@ bool TraceStats::ParseFromArray(const void* raw, size_t size) {
_has_field_.set(field.id());
}
switch (field.id()) {
- case 1 /* buffer_stats */:
- buffer_stats_.emplace_back();
- buffer_stats_.back().ParseFromArray(field.data(), field.size());
- break;
- case 17 /* chunk_payload_histogram_def */:
- chunk_payload_histogram_def_.emplace_back();
- field.get(&chunk_payload_histogram_def_.back());
- break;
- case 18 /* writer_stats */:
- writer_stats_.emplace_back();
- writer_stats_.back().ParseFromArray(field.data(), field.size());
- break;
- case 2 /* producers_connected */:
- field.get(&producers_connected_);
- break;
- case 3 /* producers_seen */:
- field.get(&producers_seen_);
- break;
- case 4 /* data_sources_registered */:
- field.get(&data_sources_registered_);
- break;
- case 5 /* data_sources_seen */:
- field.get(&data_sources_seen_);
- break;
- case 6 /* tracing_sessions */:
- field.get(&tracing_sessions_);
- break;
- case 7 /* total_buffers */:
- field.get(&total_buffers_);
- break;
- case 8 /* chunks_discarded */:
- field.get(&chunks_discarded_);
- break;
- case 9 /* patches_discarded */:
- field.get(&patches_discarded_);
- break;
- case 10 /* invalid_packets */:
- field.get(&invalid_packets_);
- break;
- case 11 /* filter_stats */:
- (*filter_stats_).ParseFromArray(field.data(), field.size());
- break;
- case 12 /* flushes_requested */:
- field.get(&flushes_requested_);
- break;
- case 13 /* flushes_succeeded */:
- field.get(&flushes_succeeded_);
- break;
- case 14 /* flushes_failed */:
- field.get(&flushes_failed_);
+ case 2 /* packed */:
+ field.get(&packed_);
break;
- case 15 /* final_flush_outcome */:
- field.get(&final_flush_outcome_);
+ case 999 /* uninterpreted_option */:
+ uninterpreted_option_.emplace_back();
+ uninterpreted_option_.back().ParseFromArray(field.data(), field.size());
break;
default:
field.SerializeAndAppendTo(&unknown_fields_);
@@ -19927,127 +19946,56 @@ bool TraceStats::ParseFromArray(const void* raw, size_t size) {
return !packed_error && !dec.bytes_left();
}
-std::string TraceStats::SerializeAsString() const {
+std::string FieldOptions::SerializeAsString() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsString();
}
-std::vector<uint8_t> TraceStats::SerializeAsArray() const {
+std::vector<uint8_t> FieldOptions::SerializeAsArray() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsArray();
}
-void TraceStats::Serialize(::protozero::Message* msg) const {
- // Field 1: buffer_stats
- for (auto& it : buffer_stats_) {
- it.Serialize(msg->BeginNestedMessage<::protozero::Message>(1));
- }
-
- // Field 17: chunk_payload_histogram_def
- for (auto& it : chunk_payload_histogram_def_) {
- ::protozero::internal::gen_helpers::SerializeVarInt(17, it, msg);
- }
-
- // Field 18: writer_stats
- for (auto& it : writer_stats_) {
- it.Serialize(msg->BeginNestedMessage<::protozero::Message>(18));
- }
-
- // Field 2: producers_connected
+void FieldOptions::Serialize(::protozero::Message* msg) const {
+ // Field 2: packed
if (_has_field_[2]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(2, producers_connected_, msg);
- }
-
- // Field 3: producers_seen
- if (_has_field_[3]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(3, producers_seen_, msg);
- }
-
- // Field 4: data_sources_registered
- if (_has_field_[4]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(4, data_sources_registered_, msg);
- }
-
- // Field 5: data_sources_seen
- if (_has_field_[5]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(5, data_sources_seen_, msg);
- }
-
- // Field 6: tracing_sessions
- if (_has_field_[6]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(6, tracing_sessions_, msg);
- }
-
- // Field 7: total_buffers
- if (_has_field_[7]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(7, total_buffers_, msg);
- }
-
- // Field 8: chunks_discarded
- if (_has_field_[8]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(8, chunks_discarded_, msg);
- }
-
- // Field 9: patches_discarded
- if (_has_field_[9]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(9, patches_discarded_, msg);
- }
-
- // Field 10: invalid_packets
- if (_has_field_[10]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(10, invalid_packets_, msg);
- }
-
- // Field 11: filter_stats
- if (_has_field_[11]) {
- (*filter_stats_).Serialize(msg->BeginNestedMessage<::protozero::Message>(11));
- }
-
- // Field 12: flushes_requested
- if (_has_field_[12]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(12, flushes_requested_, msg);
- }
-
- // Field 13: flushes_succeeded
- if (_has_field_[13]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(13, flushes_succeeded_, msg);
- }
-
- // Field 14: flushes_failed
- if (_has_field_[14]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(14, flushes_failed_, msg);
+ ::protozero::internal::gen_helpers::SerializeTinyVarInt(2, packed_, msg);
}
- // Field 15: final_flush_outcome
- if (_has_field_[15]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(15, final_flush_outcome_, msg);
+ // Field 999: uninterpreted_option
+ for (auto& it : uninterpreted_option_) {
+ it.Serialize(msg->BeginNestedMessage<::protozero::Message>(999));
}
protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
}
-TraceStats_FilterStats::TraceStats_FilterStats() = default;
-TraceStats_FilterStats::~TraceStats_FilterStats() = default;
-TraceStats_FilterStats::TraceStats_FilterStats(const TraceStats_FilterStats&) = default;
-TraceStats_FilterStats& TraceStats_FilterStats::operator=(const TraceStats_FilterStats&) = default;
-TraceStats_FilterStats::TraceStats_FilterStats(TraceStats_FilterStats&&) noexcept = default;
-TraceStats_FilterStats& TraceStats_FilterStats::operator=(TraceStats_FilterStats&&) = default;
+UninterpretedOption::UninterpretedOption() = default;
+UninterpretedOption::~UninterpretedOption() = default;
+UninterpretedOption::UninterpretedOption(const UninterpretedOption&) = default;
+UninterpretedOption& UninterpretedOption::operator=(const UninterpretedOption&) = default;
+UninterpretedOption::UninterpretedOption(UninterpretedOption&&) noexcept = default;
+UninterpretedOption& UninterpretedOption::operator=(UninterpretedOption&&) = default;
-bool TraceStats_FilterStats::operator==(const TraceStats_FilterStats& other) const {
+bool UninterpretedOption::operator==(const UninterpretedOption& other) const {
return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
- && ::protozero::internal::gen_helpers::EqualsField(input_packets_, other.input_packets_)
- && ::protozero::internal::gen_helpers::EqualsField(input_bytes_, other.input_bytes_)
- && ::protozero::internal::gen_helpers::EqualsField(output_bytes_, other.output_bytes_)
- && ::protozero::internal::gen_helpers::EqualsField(errors_, other.errors_)
- && ::protozero::internal::gen_helpers::EqualsField(time_taken_ns_, other.time_taken_ns_)
- && ::protozero::internal::gen_helpers::EqualsField(bytes_discarded_per_buffer_, other.bytes_discarded_per_buffer_);
+ && ::protozero::internal::gen_helpers::EqualsField(name_, other.name_)
+ && ::protozero::internal::gen_helpers::EqualsField(identifier_value_, other.identifier_value_)
+ && ::protozero::internal::gen_helpers::EqualsField(positive_int_value_, other.positive_int_value_)
+ && ::protozero::internal::gen_helpers::EqualsField(negative_int_value_, other.negative_int_value_)
+ && ::protozero::internal::gen_helpers::EqualsField(double_value_, other.double_value_)
+ && ::protozero::internal::gen_helpers::EqualsField(string_value_, other.string_value_)
+ && ::protozero::internal::gen_helpers::EqualsField(aggregate_value_, other.aggregate_value_);
}
-bool TraceStats_FilterStats::ParseFromArray(const void* raw, size_t size) {
- bytes_discarded_per_buffer_.clear();
+int UninterpretedOption::name_size() const { return static_cast<int>(name_.size()); }
+void UninterpretedOption::clear_name() { name_.clear(); }
+UninterpretedOption_NamePart* UninterpretedOption::add_name() { name_.emplace_back(); return &name_.back(); }
+bool UninterpretedOption::ParseFromArray(const void* raw, size_t size) {
+ name_.clear();
unknown_fields_.clear();
bool packed_error = false;
@@ -20057,24 +20005,27 @@ bool TraceStats_FilterStats::ParseFromArray(const void* raw, size_t size) {
_has_field_.set(field.id());
}
switch (field.id()) {
- case 1 /* input_packets */:
- field.get(&input_packets_);
+ case 2 /* name */:
+ name_.emplace_back();
+ name_.back().ParseFromArray(field.data(), field.size());
break;
- case 2 /* input_bytes */:
- field.get(&input_bytes_);
+ case 3 /* identifier_value */:
+ ::protozero::internal::gen_helpers::DeserializeString(field, &identifier_value_);
break;
- case 3 /* output_bytes */:
- field.get(&output_bytes_);
+ case 4 /* positive_int_value */:
+ field.get(&positive_int_value_);
break;
- case 4 /* errors */:
- field.get(&errors_);
+ case 5 /* negative_int_value */:
+ field.get(&negative_int_value_);
break;
- case 5 /* time_taken_ns */:
- field.get(&time_taken_ns_);
+ case 6 /* double_value */:
+ field.get(&double_value_);
break;
- case 20 /* bytes_discarded_per_buffer */:
- bytes_discarded_per_buffer_.emplace_back();
- field.get(&bytes_discarded_per_buffer_.back());
+ case 7 /* string_value */:
+ field.get(&string_value_);
+ break;
+ case 8 /* aggregate_value */:
+ ::protozero::internal::gen_helpers::DeserializeString(field, &aggregate_value_);
break;
default:
field.SerializeAndAppendTo(&unknown_fields_);
@@ -20084,71 +20035,72 @@ bool TraceStats_FilterStats::ParseFromArray(const void* raw, size_t size) {
return !packed_error && !dec.bytes_left();
}
-std::string TraceStats_FilterStats::SerializeAsString() const {
+std::string UninterpretedOption::SerializeAsString() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsString();
}
-std::vector<uint8_t> TraceStats_FilterStats::SerializeAsArray() const {
+std::vector<uint8_t> UninterpretedOption::SerializeAsArray() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsArray();
}
-void TraceStats_FilterStats::Serialize(::protozero::Message* msg) const {
- // Field 1: input_packets
- if (_has_field_[1]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(1, input_packets_, msg);
- }
-
- // Field 2: input_bytes
- if (_has_field_[2]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(2, input_bytes_, msg);
+void UninterpretedOption::Serialize(::protozero::Message* msg) const {
+ // Field 2: name
+ for (auto& it : name_) {
+ it.Serialize(msg->BeginNestedMessage<::protozero::Message>(2));
}
- // Field 3: output_bytes
+ // Field 3: identifier_value
if (_has_field_[3]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(3, output_bytes_, msg);
+ ::protozero::internal::gen_helpers::SerializeString(3, identifier_value_, msg);
}
- // Field 4: errors
+ // Field 4: positive_int_value
if (_has_field_[4]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(4, errors_, msg);
+ ::protozero::internal::gen_helpers::SerializeVarInt(4, positive_int_value_, msg);
}
- // Field 5: time_taken_ns
+ // Field 5: negative_int_value
if (_has_field_[5]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(5, time_taken_ns_, msg);
+ ::protozero::internal::gen_helpers::SerializeVarInt(5, negative_int_value_, msg);
}
- // Field 20: bytes_discarded_per_buffer
- for (auto& it : bytes_discarded_per_buffer_) {
- ::protozero::internal::gen_helpers::SerializeVarInt(20, it, msg);
+ // Field 6: double_value
+ if (_has_field_[6]) {
+ ::protozero::internal::gen_helpers::SerializeFixed(6, double_value_, msg);
+ }
+
+ // Field 7: string_value
+ if (_has_field_[7]) {
+ ::protozero::internal::gen_helpers::SerializeString(7, string_value_, msg);
+ }
+
+ // Field 8: aggregate_value
+ if (_has_field_[8]) {
+ ::protozero::internal::gen_helpers::SerializeString(8, aggregate_value_, msg);
}
protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
}
-TraceStats_WriterStats::TraceStats_WriterStats() = default;
-TraceStats_WriterStats::~TraceStats_WriterStats() = default;
-TraceStats_WriterStats::TraceStats_WriterStats(const TraceStats_WriterStats&) = default;
-TraceStats_WriterStats& TraceStats_WriterStats::operator=(const TraceStats_WriterStats&) = default;
-TraceStats_WriterStats::TraceStats_WriterStats(TraceStats_WriterStats&&) noexcept = default;
-TraceStats_WriterStats& TraceStats_WriterStats::operator=(TraceStats_WriterStats&&) = default;
+UninterpretedOption_NamePart::UninterpretedOption_NamePart() = default;
+UninterpretedOption_NamePart::~UninterpretedOption_NamePart() = default;
+UninterpretedOption_NamePart::UninterpretedOption_NamePart(const UninterpretedOption_NamePart&) = default;
+UninterpretedOption_NamePart& UninterpretedOption_NamePart::operator=(const UninterpretedOption_NamePart&) = default;
+UninterpretedOption_NamePart::UninterpretedOption_NamePart(UninterpretedOption_NamePart&&) noexcept = default;
+UninterpretedOption_NamePart& UninterpretedOption_NamePart::operator=(UninterpretedOption_NamePart&&) = default;
-bool TraceStats_WriterStats::operator==(const TraceStats_WriterStats& other) const {
+bool UninterpretedOption_NamePart::operator==(const UninterpretedOption_NamePart& other) const {
return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
- && ::protozero::internal::gen_helpers::EqualsField(sequence_id_, other.sequence_id_)
- && ::protozero::internal::gen_helpers::EqualsField(buffer_, other.buffer_)
- && ::protozero::internal::gen_helpers::EqualsField(chunk_payload_histogram_counts_, other.chunk_payload_histogram_counts_)
- && ::protozero::internal::gen_helpers::EqualsField(chunk_payload_histogram_sum_, other.chunk_payload_histogram_sum_);
+ && ::protozero::internal::gen_helpers::EqualsField(name_part_, other.name_part_)
+ && ::protozero::internal::gen_helpers::EqualsField(is_extension_, other.is_extension_);
}
-bool TraceStats_WriterStats::ParseFromArray(const void* raw, size_t size) {
- chunk_payload_histogram_counts_.clear();
- chunk_payload_histogram_sum_.clear();
+bool UninterpretedOption_NamePart::ParseFromArray(const void* raw, size_t size) {
unknown_fields_.clear();
bool packed_error = false;
@@ -20158,19 +20110,11 @@ bool TraceStats_WriterStats::ParseFromArray(const void* raw, size_t size) {
_has_field_.set(field.id());
}
switch (field.id()) {
- case 1 /* sequence_id */:
- field.get(&sequence_id_);
- break;
- case 4 /* buffer */:
- field.get(&buffer_);
- break;
- case 2 /* chunk_payload_histogram_counts */:
- if (!::protozero::internal::gen_helpers::DeserializePackedRepeated<::protozero::proto_utils::ProtoWireType::kVarInt, uint64_t>(field, &chunk_payload_histogram_counts_)) {
- packed_error = true;}
+ case 1 /* name_part */:
+ ::protozero::internal::gen_helpers::DeserializeString(field, &name_part_);
break;
- case 3 /* chunk_payload_histogram_sum */:
- if (!::protozero::internal::gen_helpers::DeserializePackedRepeated<::protozero::proto_utils::ProtoWireType::kVarInt, int64_t>(field, &chunk_payload_histogram_sum_)) {
- packed_error = true;}
+ case 2 /* is_extension */:
+ field.get(&is_extension_);
break;
default:
field.SerializeAndAppendTo(&unknown_fields_);
@@ -20180,81 +20124,78 @@ bool TraceStats_WriterStats::ParseFromArray(const void* raw, size_t size) {
return !packed_error && !dec.bytes_left();
}
-std::string TraceStats_WriterStats::SerializeAsString() const {
+std::string UninterpretedOption_NamePart::SerializeAsString() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsString();
}
-std::vector<uint8_t> TraceStats_WriterStats::SerializeAsArray() const {
+std::vector<uint8_t> UninterpretedOption_NamePart::SerializeAsArray() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsArray();
}
-void TraceStats_WriterStats::Serialize(::protozero::Message* msg) const {
- // Field 1: sequence_id
+void UninterpretedOption_NamePart::Serialize(::protozero::Message* msg) const {
+ // Field 1: name_part
if (_has_field_[1]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(1, sequence_id_, msg);
- }
-
- // Field 4: buffer
- if (_has_field_[4]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(4, buffer_, msg);
- }
-
- // Field 2: chunk_payload_histogram_counts
- {
- ::protozero::PackedVarInt pack;
- for (auto& it : chunk_payload_histogram_counts_)
- pack.Append(it);
- msg->AppendBytes(2, pack.data(), pack.size());
+ ::protozero::internal::gen_helpers::SerializeString(1, name_part_, msg);
}
- // Field 3: chunk_payload_histogram_sum
- {
- ::protozero::PackedVarInt pack;
- for (auto& it : chunk_payload_histogram_sum_)
- pack.Append(it);
- msg->AppendBytes(3, pack.data(), pack.size());
+ // Field 2: is_extension
+ if (_has_field_[2]) {
+ ::protozero::internal::gen_helpers::SerializeTinyVarInt(2, is_extension_, msg);
}
protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
}
-TraceStats_BufferStats::TraceStats_BufferStats() = default;
-TraceStats_BufferStats::~TraceStats_BufferStats() = default;
-TraceStats_BufferStats::TraceStats_BufferStats(const TraceStats_BufferStats&) = default;
-TraceStats_BufferStats& TraceStats_BufferStats::operator=(const TraceStats_BufferStats&) = default;
-TraceStats_BufferStats::TraceStats_BufferStats(TraceStats_BufferStats&&) noexcept = default;
-TraceStats_BufferStats& TraceStats_BufferStats::operator=(TraceStats_BufferStats&&) = default;
+DescriptorProto::DescriptorProto() = default;
+DescriptorProto::~DescriptorProto() = default;
+DescriptorProto::DescriptorProto(const DescriptorProto&) = default;
+DescriptorProto& DescriptorProto::operator=(const DescriptorProto&) = default;
+DescriptorProto::DescriptorProto(DescriptorProto&&) noexcept = default;
+DescriptorProto& DescriptorProto::operator=(DescriptorProto&&) = default;
-bool TraceStats_BufferStats::operator==(const TraceStats_BufferStats& other) const {
+bool DescriptorProto::operator==(const DescriptorProto& other) const {
return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
- && ::protozero::internal::gen_helpers::EqualsField(buffer_size_, other.buffer_size_)
- && ::protozero::internal::gen_helpers::EqualsField(bytes_written_, other.bytes_written_)
- && ::protozero::internal::gen_helpers::EqualsField(bytes_overwritten_, other.bytes_overwritten_)
- && ::protozero::internal::gen_helpers::EqualsField(bytes_read_, other.bytes_read_)
- && ::protozero::internal::gen_helpers::EqualsField(padding_bytes_written_, other.padding_bytes_written_)
- && ::protozero::internal::gen_helpers::EqualsField(padding_bytes_cleared_, other.padding_bytes_cleared_)
- && ::protozero::internal::gen_helpers::EqualsField(chunks_written_, other.chunks_written_)
- && ::protozero::internal::gen_helpers::EqualsField(chunks_rewritten_, other.chunks_rewritten_)
- && ::protozero::internal::gen_helpers::EqualsField(chunks_relocated_, other.chunks_relocated_)
- && ::protozero::internal::gen_helpers::EqualsField(chunks_overwritten_, other.chunks_overwritten_)
- && ::protozero::internal::gen_helpers::EqualsField(chunks_discarded_, other.chunks_discarded_)
- && ::protozero::internal::gen_helpers::EqualsField(chunks_read_, other.chunks_read_)
- && ::protozero::internal::gen_helpers::EqualsField(chunks_committed_out_of_order_, other.chunks_committed_out_of_order_)
- && ::protozero::internal::gen_helpers::EqualsField(write_wrap_count_, other.write_wrap_count_)
- && ::protozero::internal::gen_helpers::EqualsField(patches_succeeded_, other.patches_succeeded_)
- && ::protozero::internal::gen_helpers::EqualsField(patches_failed_, other.patches_failed_)
- && ::protozero::internal::gen_helpers::EqualsField(readaheads_succeeded_, other.readaheads_succeeded_)
- && ::protozero::internal::gen_helpers::EqualsField(readaheads_failed_, other.readaheads_failed_)
- && ::protozero::internal::gen_helpers::EqualsField(abi_violations_, other.abi_violations_)
- && ::protozero::internal::gen_helpers::EqualsField(trace_writer_packet_loss_, other.trace_writer_packet_loss_);
+ && ::protozero::internal::gen_helpers::EqualsField(name_, other.name_)
+ && ::protozero::internal::gen_helpers::EqualsField(field_, other.field_)
+ && ::protozero::internal::gen_helpers::EqualsField(extension_, other.extension_)
+ && ::protozero::internal::gen_helpers::EqualsField(nested_type_, other.nested_type_)
+ && ::protozero::internal::gen_helpers::EqualsField(enum_type_, other.enum_type_)
+ && ::protozero::internal::gen_helpers::EqualsField(oneof_decl_, other.oneof_decl_)
+ && ::protozero::internal::gen_helpers::EqualsField(reserved_range_, other.reserved_range_)
+ && ::protozero::internal::gen_helpers::EqualsField(reserved_name_, other.reserved_name_);
}
-bool TraceStats_BufferStats::ParseFromArray(const void* raw, size_t size) {
+int DescriptorProto::field_size() const { return static_cast<int>(field_.size()); }
+void DescriptorProto::clear_field() { field_.clear(); }
+FieldDescriptorProto* DescriptorProto::add_field() { field_.emplace_back(); return &field_.back(); }
+int DescriptorProto::extension_size() const { return static_cast<int>(extension_.size()); }
+void DescriptorProto::clear_extension() { extension_.clear(); }
+FieldDescriptorProto* DescriptorProto::add_extension() { extension_.emplace_back(); return &extension_.back(); }
+int DescriptorProto::nested_type_size() const { return static_cast<int>(nested_type_.size()); }
+void DescriptorProto::clear_nested_type() { nested_type_.clear(); }
+DescriptorProto* DescriptorProto::add_nested_type() { nested_type_.emplace_back(); return &nested_type_.back(); }
+int DescriptorProto::enum_type_size() const { return static_cast<int>(enum_type_.size()); }
+void DescriptorProto::clear_enum_type() { enum_type_.clear(); }
+EnumDescriptorProto* DescriptorProto::add_enum_type() { enum_type_.emplace_back(); return &enum_type_.back(); }
+int DescriptorProto::oneof_decl_size() const { return static_cast<int>(oneof_decl_.size()); }
+void DescriptorProto::clear_oneof_decl() { oneof_decl_.clear(); }
+OneofDescriptorProto* DescriptorProto::add_oneof_decl() { oneof_decl_.emplace_back(); return &oneof_decl_.back(); }
+int DescriptorProto::reserved_range_size() const { return static_cast<int>(reserved_range_.size()); }
+void DescriptorProto::clear_reserved_range() { reserved_range_.clear(); }
+DescriptorProto_ReservedRange* DescriptorProto::add_reserved_range() { reserved_range_.emplace_back(); return &reserved_range_.back(); }
+bool DescriptorProto::ParseFromArray(const void* raw, size_t size) {
+ field_.clear();
+ extension_.clear();
+ nested_type_.clear();
+ enum_type_.clear();
+ oneof_decl_.clear();
+ reserved_range_.clear();
+ reserved_name_.clear();
unknown_fields_.clear();
bool packed_error = false;
@@ -20264,65 +20205,36 @@ bool TraceStats_BufferStats::ParseFromArray(const void* raw, size_t size) {
_has_field_.set(field.id());
}
switch (field.id()) {
- case 12 /* buffer_size */:
- field.get(&buffer_size_);
+ case 1 /* name */:
+ ::protozero::internal::gen_helpers::DeserializeString(field, &name_);
break;
- case 1 /* bytes_written */:
- field.get(&bytes_written_);
+ case 2 /* field */:
+ field_.emplace_back();
+ field_.back().ParseFromArray(field.data(), field.size());
break;
- case 13 /* bytes_overwritten */:
- field.get(&bytes_overwritten_);
- break;
- case 14 /* bytes_read */:
- field.get(&bytes_read_);
- break;
- case 15 /* padding_bytes_written */:
- field.get(&padding_bytes_written_);
- break;
- case 16 /* padding_bytes_cleared */:
- field.get(&padding_bytes_cleared_);
- break;
- case 2 /* chunks_written */:
- field.get(&chunks_written_);
- break;
- case 10 /* chunks_rewritten */:
- field.get(&chunks_rewritten_);
- break;
- case 20 /* chunks_relocated */:
- field.get(&chunks_relocated_);
- break;
- case 3 /* chunks_overwritten */:
- field.get(&chunks_overwritten_);
- break;
- case 18 /* chunks_discarded */:
- field.get(&chunks_discarded_);
- break;
- case 17 /* chunks_read */:
- field.get(&chunks_read_);
- break;
- case 11 /* chunks_committed_out_of_order */:
- field.get(&chunks_committed_out_of_order_);
- break;
- case 4 /* write_wrap_count */:
- field.get(&write_wrap_count_);
- break;
- case 5 /* patches_succeeded */:
- field.get(&patches_succeeded_);
+ case 6 /* extension */:
+ extension_.emplace_back();
+ extension_.back().ParseFromArray(field.data(), field.size());
break;
- case 6 /* patches_failed */:
- field.get(&patches_failed_);
+ case 3 /* nested_type */:
+ nested_type_.emplace_back();
+ nested_type_.back().ParseFromArray(field.data(), field.size());
break;
- case 7 /* readaheads_succeeded */:
- field.get(&readaheads_succeeded_);
+ case 4 /* enum_type */:
+ enum_type_.emplace_back();
+ enum_type_.back().ParseFromArray(field.data(), field.size());
break;
- case 8 /* readaheads_failed */:
- field.get(&readaheads_failed_);
+ case 8 /* oneof_decl */:
+ oneof_decl_.emplace_back();
+ oneof_decl_.back().ParseFromArray(field.data(), field.size());
break;
- case 9 /* abi_violations */:
- field.get(&abi_violations_);
+ case 9 /* reserved_range */:
+ reserved_range_.emplace_back();
+ reserved_range_.back().ParseFromArray(field.data(), field.size());
break;
- case 19 /* trace_writer_packet_loss */:
- field.get(&trace_writer_packet_loss_);
+ case 10 /* reserved_name */:
+ reserved_name_.emplace_back();
+ ::protozero::internal::gen_helpers::DeserializeString(field, &reserved_name_.back());
break;
default:
field.SerializeAndAppendTo(&unknown_fields_);
@@ -20332,163 +20244,77 @@ bool TraceStats_BufferStats::ParseFromArray(const void* raw, size_t size) {
return !packed_error && !dec.bytes_left();
}
-std::string TraceStats_BufferStats::SerializeAsString() const {
+std::string DescriptorProto::SerializeAsString() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsString();
}
-std::vector<uint8_t> TraceStats_BufferStats::SerializeAsArray() const {
+std::vector<uint8_t> DescriptorProto::SerializeAsArray() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsArray();
}
-void TraceStats_BufferStats::Serialize(::protozero::Message* msg) const {
- // Field 12: buffer_size
- if (_has_field_[12]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(12, buffer_size_, msg);
- }
-
- // Field 1: bytes_written
+void DescriptorProto::Serialize(::protozero::Message* msg) const {
+ // Field 1: name
if (_has_field_[1]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(1, bytes_written_, msg);
- }
-
- // Field 13: bytes_overwritten
- if (_has_field_[13]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(13, bytes_overwritten_, msg);
- }
-
- // Field 14: bytes_read
- if (_has_field_[14]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(14, bytes_read_, msg);
- }
-
- // Field 15: padding_bytes_written
- if (_has_field_[15]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(15, padding_bytes_written_, msg);
- }
-
- // Field 16: padding_bytes_cleared
- if (_has_field_[16]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(16, padding_bytes_cleared_, msg);
- }
-
- // Field 2: chunks_written
- if (_has_field_[2]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(2, chunks_written_, msg);
- }
-
- // Field 10: chunks_rewritten
- if (_has_field_[10]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(10, chunks_rewritten_, msg);
- }
-
- // Field 20: chunks_relocated
- if (_has_field_[20]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(20, chunks_relocated_, msg);
- }
-
- // Field 3: chunks_overwritten
- if (_has_field_[3]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(3, chunks_overwritten_, msg);
- }
-
- // Field 18: chunks_discarded
- if (_has_field_[18]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(18, chunks_discarded_, msg);
- }
-
- // Field 17: chunks_read
- if (_has_field_[17]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(17, chunks_read_, msg);
- }
-
- // Field 11: chunks_committed_out_of_order
- if (_has_field_[11]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(11, chunks_committed_out_of_order_, msg);
+ ::protozero::internal::gen_helpers::SerializeString(1, name_, msg);
}
- // Field 4: write_wrap_count
- if (_has_field_[4]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(4, write_wrap_count_, msg);
+ // Field 2: field
+ for (auto& it : field_) {
+ it.Serialize(msg->BeginNestedMessage<::protozero::Message>(2));
}
- // Field 5: patches_succeeded
- if (_has_field_[5]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(5, patches_succeeded_, msg);
+ // Field 6: extension
+ for (auto& it : extension_) {
+ it.Serialize(msg->BeginNestedMessage<::protozero::Message>(6));
}
- // Field 6: patches_failed
- if (_has_field_[6]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(6, patches_failed_, msg);
+ // Field 3: nested_type
+ for (auto& it : nested_type_) {
+ it.Serialize(msg->BeginNestedMessage<::protozero::Message>(3));
}
- // Field 7: readaheads_succeeded
- if (_has_field_[7]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(7, readaheads_succeeded_, msg);
+ // Field 4: enum_type
+ for (auto& it : enum_type_) {
+ it.Serialize(msg->BeginNestedMessage<::protozero::Message>(4));
}
- // Field 8: readaheads_failed
- if (_has_field_[8]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(8, readaheads_failed_, msg);
+ // Field 8: oneof_decl
+ for (auto& it : oneof_decl_) {
+ it.Serialize(msg->BeginNestedMessage<::protozero::Message>(8));
}
- // Field 9: abi_violations
- if (_has_field_[9]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(9, abi_violations_, msg);
+ // Field 9: reserved_range
+ for (auto& it : reserved_range_) {
+ it.Serialize(msg->BeginNestedMessage<::protozero::Message>(9));
}
- // Field 19: trace_writer_packet_loss
- if (_has_field_[19]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(19, trace_writer_packet_loss_, msg);
+ // Field 10: reserved_name
+ for (auto& it : reserved_name_) {
+ ::protozero::internal::gen_helpers::SerializeString(10, it, msg);
}
protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
}
-} // namespace perfetto
-} // namespace protos
-} // namespace gen
-#if defined(__GNUC__) || defined(__clang__)
-#pragma GCC diagnostic pop
-#endif
-// gen_amalgamated begin source: gen/protos/perfetto/common/tracing_service_capabilities.gen.cc
-// gen_amalgamated expanded: #include "perfetto/protozero/gen_field_helpers.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/message.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/packed_repeated_fields.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/proto_decoder.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/scattered_heap_buffer.h"
-// DO NOT EDIT. Autogenerated by Perfetto cppgen_plugin
-#if defined(__GNUC__) || defined(__clang__)
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wfloat-equal"
-#endif
-// gen_amalgamated expanded: #include "protos/perfetto/common/tracing_service_capabilities.gen.h"
-// gen_amalgamated expanded: #include "protos/perfetto/common/observable_events.gen.h"
-
-namespace perfetto {
-namespace protos {
-namespace gen {
-TracingServiceCapabilities::TracingServiceCapabilities() = default;
-TracingServiceCapabilities::~TracingServiceCapabilities() = default;
-TracingServiceCapabilities::TracingServiceCapabilities(const TracingServiceCapabilities&) = default;
-TracingServiceCapabilities& TracingServiceCapabilities::operator=(const TracingServiceCapabilities&) = default;
-TracingServiceCapabilities::TracingServiceCapabilities(TracingServiceCapabilities&&) noexcept = default;
-TracingServiceCapabilities& TracingServiceCapabilities::operator=(TracingServiceCapabilities&&) = default;
+DescriptorProto_ReservedRange::DescriptorProto_ReservedRange() = default;
+DescriptorProto_ReservedRange::~DescriptorProto_ReservedRange() = default;
+DescriptorProto_ReservedRange::DescriptorProto_ReservedRange(const DescriptorProto_ReservedRange&) = default;
+DescriptorProto_ReservedRange& DescriptorProto_ReservedRange::operator=(const DescriptorProto_ReservedRange&) = default;
+DescriptorProto_ReservedRange::DescriptorProto_ReservedRange(DescriptorProto_ReservedRange&&) noexcept = default;
+DescriptorProto_ReservedRange& DescriptorProto_ReservedRange::operator=(DescriptorProto_ReservedRange&&) = default;
-bool TracingServiceCapabilities::operator==(const TracingServiceCapabilities& other) const {
+bool DescriptorProto_ReservedRange::operator==(const DescriptorProto_ReservedRange& other) const {
return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
- && ::protozero::internal::gen_helpers::EqualsField(has_query_capabilities_, other.has_query_capabilities_)
- && ::protozero::internal::gen_helpers::EqualsField(observable_events_, other.observable_events_)
- && ::protozero::internal::gen_helpers::EqualsField(has_trace_config_output_path_, other.has_trace_config_output_path_)
- && ::protozero::internal::gen_helpers::EqualsField(has_clone_session_, other.has_clone_session_);
+ && ::protozero::internal::gen_helpers::EqualsField(start_, other.start_)
+ && ::protozero::internal::gen_helpers::EqualsField(end_, other.end_);
}
-bool TracingServiceCapabilities::ParseFromArray(const void* raw, size_t size) {
- observable_events_.clear();
+bool DescriptorProto_ReservedRange::ParseFromArray(const void* raw, size_t size) {
unknown_fields_.clear();
bool packed_error = false;
@@ -20498,18 +20324,11 @@ bool TracingServiceCapabilities::ParseFromArray(const void* raw, size_t size) {
_has_field_.set(field.id());
}
switch (field.id()) {
- case 1 /* has_query_capabilities */:
- field.get(&has_query_capabilities_);
- break;
- case 2 /* observable_events */:
- observable_events_.emplace_back();
- field.get(&observable_events_.back());
- break;
- case 3 /* has_trace_config_output_path */:
- field.get(&has_trace_config_output_path_);
+ case 1 /* start */:
+ field.get(&start_);
break;
- case 4 /* has_clone_session */:
- field.get(&has_clone_session_);
+ case 2 /* end */:
+ field.get(&end_);
break;
default:
field.SerializeAndAppendTo(&unknown_fields_);
@@ -20519,101 +20338,68 @@ bool TracingServiceCapabilities::ParseFromArray(const void* raw, size_t size) {
return !packed_error && !dec.bytes_left();
}
-std::string TracingServiceCapabilities::SerializeAsString() const {
+std::string DescriptorProto_ReservedRange::SerializeAsString() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsString();
}
-std::vector<uint8_t> TracingServiceCapabilities::SerializeAsArray() const {
+std::vector<uint8_t> DescriptorProto_ReservedRange::SerializeAsArray() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsArray();
}
-void TracingServiceCapabilities::Serialize(::protozero::Message* msg) const {
- // Field 1: has_query_capabilities
+void DescriptorProto_ReservedRange::Serialize(::protozero::Message* msg) const {
+ // Field 1: start
if (_has_field_[1]) {
- ::protozero::internal::gen_helpers::SerializeTinyVarInt(1, has_query_capabilities_, msg);
- }
-
- // Field 2: observable_events
- for (auto& it : observable_events_) {
- ::protozero::internal::gen_helpers::SerializeVarInt(2, it, msg);
- }
-
- // Field 3: has_trace_config_output_path
- if (_has_field_[3]) {
- ::protozero::internal::gen_helpers::SerializeTinyVarInt(3, has_trace_config_output_path_, msg);
+ ::protozero::internal::gen_helpers::SerializeVarInt(1, start_, msg);
}
- // Field 4: has_clone_session
- if (_has_field_[4]) {
- ::protozero::internal::gen_helpers::SerializeTinyVarInt(4, has_clone_session_, msg);
+ // Field 2: end
+ if (_has_field_[2]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(2, end_, msg);
}
protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
}
-} // namespace perfetto
-} // namespace protos
-} // namespace gen
-#if defined(__GNUC__) || defined(__clang__)
-#pragma GCC diagnostic pop
-#endif
-// gen_amalgamated begin source: gen/protos/perfetto/common/tracing_service_state.gen.cc
-// gen_amalgamated expanded: #include "perfetto/protozero/gen_field_helpers.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/message.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/packed_repeated_fields.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/proto_decoder.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/scattered_heap_buffer.h"
-// DO NOT EDIT. Autogenerated by Perfetto cppgen_plugin
-#if defined(__GNUC__) || defined(__clang__)
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wfloat-equal"
-#endif
-// gen_amalgamated expanded: #include "protos/perfetto/common/tracing_service_state.gen.h"
-// gen_amalgamated expanded: #include "protos/perfetto/common/data_source_descriptor.gen.h"
-// gen_amalgamated expanded: #include "protos/perfetto/protovm/vm_program.gen.h"
-// gen_amalgamated expanded: #include "protos/perfetto/common/track_event_descriptor.gen.h"
-// gen_amalgamated expanded: #include "protos/perfetto/common/gpu_counter_descriptor.gen.h"
-// gen_amalgamated expanded: #include "protos/perfetto/common/ftrace_descriptor.gen.h"
-
-namespace perfetto {
-namespace protos {
-namespace gen {
-TracingServiceState::TracingServiceState() = default;
-TracingServiceState::~TracingServiceState() = default;
-TracingServiceState::TracingServiceState(const TracingServiceState&) = default;
-TracingServiceState& TracingServiceState::operator=(const TracingServiceState&) = default;
-TracingServiceState::TracingServiceState(TracingServiceState&&) noexcept = default;
-TracingServiceState& TracingServiceState::operator=(TracingServiceState&&) = default;
+FileDescriptorProto::FileDescriptorProto() = default;
+FileDescriptorProto::~FileDescriptorProto() = default;
+FileDescriptorProto::FileDescriptorProto(const FileDescriptorProto&) = default;
+FileDescriptorProto& FileDescriptorProto::operator=(const FileDescriptorProto&) = default;
+FileDescriptorProto::FileDescriptorProto(FileDescriptorProto&&) noexcept = default;
+FileDescriptorProto& FileDescriptorProto::operator=(FileDescriptorProto&&) = default;
-bool TracingServiceState::operator==(const TracingServiceState& other) const {
+bool FileDescriptorProto::operator==(const FileDescriptorProto& other) const {
return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
- && ::protozero::internal::gen_helpers::EqualsField(producers_, other.producers_)
- && ::protozero::internal::gen_helpers::EqualsField(data_sources_, other.data_sources_)
- && ::protozero::internal::gen_helpers::EqualsField(tracing_sessions_, other.tracing_sessions_)
- && ::protozero::internal::gen_helpers::EqualsField(supports_tracing_sessions_, other.supports_tracing_sessions_)
- && ::protozero::internal::gen_helpers::EqualsField(num_sessions_, other.num_sessions_)
- && ::protozero::internal::gen_helpers::EqualsField(num_sessions_started_, other.num_sessions_started_)
- && ::protozero::internal::gen_helpers::EqualsField(tracing_service_version_, other.tracing_service_version_);
+ && ::protozero::internal::gen_helpers::EqualsField(name_, other.name_)
+ && ::protozero::internal::gen_helpers::EqualsField(package_, other.package_)
+ && ::protozero::internal::gen_helpers::EqualsField(dependency_, other.dependency_)
+ && ::protozero::internal::gen_helpers::EqualsField(public_dependency_, other.public_dependency_)
+ && ::protozero::internal::gen_helpers::EqualsField(weak_dependency_, other.weak_dependency_)
+ && ::protozero::internal::gen_helpers::EqualsField(message_type_, other.message_type_)
+ && ::protozero::internal::gen_helpers::EqualsField(enum_type_, other.enum_type_)
+ && ::protozero::internal::gen_helpers::EqualsField(extension_, other.extension_);
}
-int TracingServiceState::producers_size() const { return static_cast<int>(producers_.size()); }
-void TracingServiceState::clear_producers() { producers_.clear(); }
-TracingServiceState_Producer* TracingServiceState::add_producers() { producers_.emplace_back(); return &producers_.back(); }
-int TracingServiceState::data_sources_size() const { return static_cast<int>(data_sources_.size()); }
-void TracingServiceState::clear_data_sources() { data_sources_.clear(); }
-TracingServiceState_DataSource* TracingServiceState::add_data_sources() { data_sources_.emplace_back(); return &data_sources_.back(); }
-int TracingServiceState::tracing_sessions_size() const { return static_cast<int>(tracing_sessions_.size()); }
-void TracingServiceState::clear_tracing_sessions() { tracing_sessions_.clear(); }
-TracingServiceState_TracingSession* TracingServiceState::add_tracing_sessions() { tracing_sessions_.emplace_back(); return &tracing_sessions_.back(); }
-bool TracingServiceState::ParseFromArray(const void* raw, size_t size) {
- producers_.clear();
- data_sources_.clear();
- tracing_sessions_.clear();
+int FileDescriptorProto::message_type_size() const { return static_cast<int>(message_type_.size()); }
+void FileDescriptorProto::clear_message_type() { message_type_.clear(); }
+DescriptorProto* FileDescriptorProto::add_message_type() { message_type_.emplace_back(); return &message_type_.back(); }
+int FileDescriptorProto::enum_type_size() const { return static_cast<int>(enum_type_.size()); }
+void FileDescriptorProto::clear_enum_type() { enum_type_.clear(); }
+EnumDescriptorProto* FileDescriptorProto::add_enum_type() { enum_type_.emplace_back(); return &enum_type_.back(); }
+int FileDescriptorProto::extension_size() const { return static_cast<int>(extension_.size()); }
+void FileDescriptorProto::clear_extension() { extension_.clear(); }
+FieldDescriptorProto* FileDescriptorProto::add_extension() { extension_.emplace_back(); return &extension_.back(); }
+bool FileDescriptorProto::ParseFromArray(const void* raw, size_t size) {
+ dependency_.clear();
+ public_dependency_.clear();
+ weak_dependency_.clear();
+ message_type_.clear();
+ enum_type_.clear();
+ extension_.clear();
unknown_fields_.clear();
bool packed_error = false;
@@ -20623,29 +20409,35 @@ bool TracingServiceState::ParseFromArray(const void* raw, size_t size) {
_has_field_.set(field.id());
}
switch (field.id()) {
- case 1 /* producers */:
- producers_.emplace_back();
- producers_.back().ParseFromArray(field.data(), field.size());
+ case 1 /* name */:
+ ::protozero::internal::gen_helpers::DeserializeString(field, &name_);
break;
- case 2 /* data_sources */:
- data_sources_.emplace_back();
- data_sources_.back().ParseFromArray(field.data(), field.size());
+ case 2 /* package */:
+ ::protozero::internal::gen_helpers::DeserializeString(field, &package_);
break;
- case 6 /* tracing_sessions */:
- tracing_sessions_.emplace_back();
- tracing_sessions_.back().ParseFromArray(field.data(), field.size());
+ case 3 /* dependency */:
+ dependency_.emplace_back();
+ ::protozero::internal::gen_helpers::DeserializeString(field, &dependency_.back());
break;
- case 7 /* supports_tracing_sessions */:
- field.get(&supports_tracing_sessions_);
+ case 10 /* public_dependency */:
+ public_dependency_.emplace_back();
+ field.get(&public_dependency_.back());
break;
- case 3 /* num_sessions */:
- field.get(&num_sessions_);
+ case 11 /* weak_dependency */:
+ weak_dependency_.emplace_back();
+ field.get(&weak_dependency_.back());
break;
- case 4 /* num_sessions_started */:
- field.get(&num_sessions_started_);
+ case 4 /* message_type */:
+ message_type_.emplace_back();
+ message_type_.back().ParseFromArray(field.data(), field.size());
break;
- case 5 /* tracing_service_version */:
- ::protozero::internal::gen_helpers::DeserializeString(field, &tracing_service_version_);
+ case 5 /* enum_type */:
+ enum_type_.emplace_back();
+ enum_type_.back().ParseFromArray(field.data(), field.size());
+ break;
+ case 7 /* extension */:
+ extension_.emplace_back();
+ extension_.back().ParseFromArray(field.data(), field.size());
break;
default:
field.SerializeAndAppendTo(&unknown_fields_);
@@ -20655,82 +20447,80 @@ bool TracingServiceState::ParseFromArray(const void* raw, size_t size) {
return !packed_error && !dec.bytes_left();
}
-std::string TracingServiceState::SerializeAsString() const {
+std::string FileDescriptorProto::SerializeAsString() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsString();
}
-std::vector<uint8_t> TracingServiceState::SerializeAsArray() const {
+std::vector<uint8_t> FileDescriptorProto::SerializeAsArray() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsArray();
}
-void TracingServiceState::Serialize(::protozero::Message* msg) const {
- // Field 1: producers
- for (auto& it : producers_) {
- it.Serialize(msg->BeginNestedMessage<::protozero::Message>(1));
+void FileDescriptorProto::Serialize(::protozero::Message* msg) const {
+ // Field 1: name
+ if (_has_field_[1]) {
+ ::protozero::internal::gen_helpers::SerializeString(1, name_, msg);
}
- // Field 2: data_sources
- for (auto& it : data_sources_) {
- it.Serialize(msg->BeginNestedMessage<::protozero::Message>(2));
+ // Field 2: package
+ if (_has_field_[2]) {
+ ::protozero::internal::gen_helpers::SerializeString(2, package_, msg);
}
- // Field 6: tracing_sessions
- for (auto& it : tracing_sessions_) {
- it.Serialize(msg->BeginNestedMessage<::protozero::Message>(6));
+ // Field 3: dependency
+ for (auto& it : dependency_) {
+ ::protozero::internal::gen_helpers::SerializeString(3, it, msg);
}
- // Field 7: supports_tracing_sessions
- if (_has_field_[7]) {
- ::protozero::internal::gen_helpers::SerializeTinyVarInt(7, supports_tracing_sessions_, msg);
+ // Field 10: public_dependency
+ for (auto& it : public_dependency_) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(10, it, msg);
}
- // Field 3: num_sessions
- if (_has_field_[3]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(3, num_sessions_, msg);
+ // Field 11: weak_dependency
+ for (auto& it : weak_dependency_) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(11, it, msg);
}
- // Field 4: num_sessions_started
- if (_has_field_[4]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(4, num_sessions_started_, msg);
+ // Field 4: message_type
+ for (auto& it : message_type_) {
+ it.Serialize(msg->BeginNestedMessage<::protozero::Message>(4));
}
- // Field 5: tracing_service_version
- if (_has_field_[5]) {
- ::protozero::internal::gen_helpers::SerializeString(5, tracing_service_version_, msg);
+ // Field 5: enum_type
+ for (auto& it : enum_type_) {
+ it.Serialize(msg->BeginNestedMessage<::protozero::Message>(5));
+ }
+
+ // Field 7: extension
+ for (auto& it : extension_) {
+ it.Serialize(msg->BeginNestedMessage<::protozero::Message>(7));
}
protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
}
-TracingServiceState_TracingSession::TracingServiceState_TracingSession() = default;
-TracingServiceState_TracingSession::~TracingServiceState_TracingSession() = default;
-TracingServiceState_TracingSession::TracingServiceState_TracingSession(const TracingServiceState_TracingSession&) = default;
-TracingServiceState_TracingSession& TracingServiceState_TracingSession::operator=(const TracingServiceState_TracingSession&) = default;
-TracingServiceState_TracingSession::TracingServiceState_TracingSession(TracingServiceState_TracingSession&&) noexcept = default;
-TracingServiceState_TracingSession& TracingServiceState_TracingSession::operator=(TracingServiceState_TracingSession&&) = default;
+FileDescriptorSet::FileDescriptorSet() = default;
+FileDescriptorSet::~FileDescriptorSet() = default;
+FileDescriptorSet::FileDescriptorSet(const FileDescriptorSet&) = default;
+FileDescriptorSet& FileDescriptorSet::operator=(const FileDescriptorSet&) = default;
+FileDescriptorSet::FileDescriptorSet(FileDescriptorSet&&) noexcept = default;
+FileDescriptorSet& FileDescriptorSet::operator=(FileDescriptorSet&&) = default;
-bool TracingServiceState_TracingSession::operator==(const TracingServiceState_TracingSession& other) const {
+bool FileDescriptorSet::operator==(const FileDescriptorSet& other) const {
return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
- && ::protozero::internal::gen_helpers::EqualsField(id_, other.id_)
- && ::protozero::internal::gen_helpers::EqualsField(consumer_uid_, other.consumer_uid_)
- && ::protozero::internal::gen_helpers::EqualsField(state_, other.state_)
- && ::protozero::internal::gen_helpers::EqualsField(unique_session_name_, other.unique_session_name_)
- && ::protozero::internal::gen_helpers::EqualsField(buffer_size_kb_, other.buffer_size_kb_)
- && ::protozero::internal::gen_helpers::EqualsField(duration_ms_, other.duration_ms_)
- && ::protozero::internal::gen_helpers::EqualsField(num_data_sources_, other.num_data_sources_)
- && ::protozero::internal::gen_helpers::EqualsField(start_realtime_ns_, other.start_realtime_ns_)
- && ::protozero::internal::gen_helpers::EqualsField(bugreport_score_, other.bugreport_score_)
- && ::protozero::internal::gen_helpers::EqualsField(bugreport_filename_, other.bugreport_filename_)
- && ::protozero::internal::gen_helpers::EqualsField(is_started_, other.is_started_);
+ && ::protozero::internal::gen_helpers::EqualsField(file_, other.file_);
}
-bool TracingServiceState_TracingSession::ParseFromArray(const void* raw, size_t size) {
- buffer_size_kb_.clear();
+int FileDescriptorSet::file_size() const { return static_cast<int>(file_.size()); }
+void FileDescriptorSet::clear_file() { file_.clear(); }
+FileDescriptorProto* FileDescriptorSet::add_file() { file_.emplace_back(); return &file_.back(); }
+bool FileDescriptorSet::ParseFromArray(const void* raw, size_t size) {
+ file_.clear();
unknown_fields_.clear();
bool packed_error = false;
@@ -20740,39 +20530,9 @@ bool TracingServiceState_TracingSession::ParseFromArray(const void* raw, size_t
_has_field_.set(field.id());
}
switch (field.id()) {
- case 1 /* id */:
- field.get(&id_);
- break;
- case 2 /* consumer_uid */:
- field.get(&consumer_uid_);
- break;
- case 3 /* state */:
- ::protozero::internal::gen_helpers::DeserializeString(field, &state_);
- break;
- case 4 /* unique_session_name */:
- ::protozero::internal::gen_helpers::DeserializeString(field, &unique_session_name_);
- break;
- case 5 /* buffer_size_kb */:
- buffer_size_kb_.emplace_back();
- field.get(&buffer_size_kb_.back());
- break;
- case 6 /* duration_ms */:
- field.get(&duration_ms_);
- break;
- case 7 /* num_data_sources */:
- field.get(&num_data_sources_);
- break;
- case 8 /* start_realtime_ns */:
- field.get(&start_realtime_ns_);
- break;
- case 9 /* bugreport_score */:
- field.get(&bugreport_score_);
- break;
- case 10 /* bugreport_filename */:
- ::protozero::internal::gen_helpers::DeserializeString(field, &bugreport_filename_);
- break;
- case 11 /* is_started */:
- field.get(&is_started_);
+ case 1 /* file */:
+ file_.emplace_back();
+ file_.back().ParseFromArray(field.data(), field.size());
break;
default:
field.SerializeAndAppendTo(&unknown_fields_);
@@ -20782,92 +20542,67 @@ bool TracingServiceState_TracingSession::ParseFromArray(const void* raw, size_t
return !packed_error && !dec.bytes_left();
}
-std::string TracingServiceState_TracingSession::SerializeAsString() const {
+std::string FileDescriptorSet::SerializeAsString() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsString();
}
-std::vector<uint8_t> TracingServiceState_TracingSession::SerializeAsArray() const {
+std::vector<uint8_t> FileDescriptorSet::SerializeAsArray() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsArray();
}
-void TracingServiceState_TracingSession::Serialize(::protozero::Message* msg) const {
- // Field 1: id
- if (_has_field_[1]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(1, id_, msg);
- }
-
- // Field 2: consumer_uid
- if (_has_field_[2]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(2, consumer_uid_, msg);
- }
-
- // Field 3: state
- if (_has_field_[3]) {
- ::protozero::internal::gen_helpers::SerializeString(3, state_, msg);
- }
-
- // Field 4: unique_session_name
- if (_has_field_[4]) {
- ::protozero::internal::gen_helpers::SerializeString(4, unique_session_name_, msg);
- }
-
- // Field 5: buffer_size_kb
- for (auto& it : buffer_size_kb_) {
- ::protozero::internal::gen_helpers::SerializeVarInt(5, it, msg);
- }
-
- // Field 6: duration_ms
- if (_has_field_[6]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(6, duration_ms_, msg);
- }
-
- // Field 7: num_data_sources
- if (_has_field_[7]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(7, num_data_sources_, msg);
- }
-
- // Field 8: start_realtime_ns
- if (_has_field_[8]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(8, start_realtime_ns_, msg);
- }
-
- // Field 9: bugreport_score
- if (_has_field_[9]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(9, bugreport_score_, msg);
- }
-
- // Field 10: bugreport_filename
- if (_has_field_[10]) {
- ::protozero::internal::gen_helpers::SerializeString(10, bugreport_filename_, msg);
- }
-
- // Field 11: is_started
- if (_has_field_[11]) {
- ::protozero::internal::gen_helpers::SerializeTinyVarInt(11, is_started_, msg);
+void FileDescriptorSet::Serialize(::protozero::Message* msg) const {
+ // Field 1: file
+ for (auto& it : file_) {
+ it.Serialize(msg->BeginNestedMessage<::protozero::Message>(1));
}
protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
}
+} // namespace perfetto
+} // namespace protos
+} // namespace gen
+#if defined(__GNUC__) || defined(__clang__)
+#pragma GCC diagnostic pop
+#endif
+// gen_amalgamated begin source: gen/protos/perfetto/common/ftrace_descriptor.gen.cc
+// gen_amalgamated expanded: #include "perfetto/protozero/gen_field_helpers.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/message.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/packed_repeated_fields.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/proto_decoder.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/scattered_heap_buffer.h"
+// DO NOT EDIT. Autogenerated by Perfetto cppgen_plugin
+#if defined(__GNUC__) || defined(__clang__)
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wfloat-equal"
+#endif
+// gen_amalgamated expanded: #include "protos/perfetto/common/ftrace_descriptor.gen.h"
+
+namespace perfetto {
+namespace protos {
+namespace gen {
-TracingServiceState_DataSource::TracingServiceState_DataSource() = default;
-TracingServiceState_DataSource::~TracingServiceState_DataSource() = default;
-TracingServiceState_DataSource::TracingServiceState_DataSource(const TracingServiceState_DataSource&) = default;
-TracingServiceState_DataSource& TracingServiceState_DataSource::operator=(const TracingServiceState_DataSource&) = default;
-TracingServiceState_DataSource::TracingServiceState_DataSource(TracingServiceState_DataSource&&) noexcept = default;
-TracingServiceState_DataSource& TracingServiceState_DataSource::operator=(TracingServiceState_DataSource&&) = default;
+FtraceDescriptor::FtraceDescriptor() = default;
+FtraceDescriptor::~FtraceDescriptor() = default;
+FtraceDescriptor::FtraceDescriptor(const FtraceDescriptor&) = default;
+FtraceDescriptor& FtraceDescriptor::operator=(const FtraceDescriptor&) = default;
+FtraceDescriptor::FtraceDescriptor(FtraceDescriptor&&) noexcept = default;
+FtraceDescriptor& FtraceDescriptor::operator=(FtraceDescriptor&&) = default;
-bool TracingServiceState_DataSource::operator==(const TracingServiceState_DataSource& other) const {
+bool FtraceDescriptor::operator==(const FtraceDescriptor& other) const {
return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
- && ::protozero::internal::gen_helpers::EqualsField(ds_descriptor_, other.ds_descriptor_)
- && ::protozero::internal::gen_helpers::EqualsField(producer_id_, other.producer_id_);
+ && ::protozero::internal::gen_helpers::EqualsField(atrace_categories_, other.atrace_categories_);
}
-bool TracingServiceState_DataSource::ParseFromArray(const void* raw, size_t size) {
+int FtraceDescriptor::atrace_categories_size() const { return static_cast<int>(atrace_categories_.size()); }
+void FtraceDescriptor::clear_atrace_categories() { atrace_categories_.clear(); }
+FtraceDescriptor_AtraceCategory* FtraceDescriptor::add_atrace_categories() { atrace_categories_.emplace_back(); return &atrace_categories_.back(); }
+bool FtraceDescriptor::ParseFromArray(const void* raw, size_t size) {
+ atrace_categories_.clear();
unknown_fields_.clear();
bool packed_error = false;
@@ -20877,11 +20612,9 @@ bool TracingServiceState_DataSource::ParseFromArray(const void* raw, size_t size
_has_field_.set(field.id());
}
switch (field.id()) {
- case 1 /* ds_descriptor */:
- (*ds_descriptor_).ParseFromArray(field.data(), field.size());
- break;
- case 2 /* producer_id */:
- field.get(&producer_id_);
+ case 1 /* atrace_categories */:
+ atrace_categories_.emplace_back();
+ atrace_categories_.back().ParseFromArray(field.data(), field.size());
break;
default:
field.SerializeAndAppendTo(&unknown_fields_);
@@ -20891,53 +20624,42 @@ bool TracingServiceState_DataSource::ParseFromArray(const void* raw, size_t size
return !packed_error && !dec.bytes_left();
}
-std::string TracingServiceState_DataSource::SerializeAsString() const {
+std::string FtraceDescriptor::SerializeAsString() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsString();
}
-std::vector<uint8_t> TracingServiceState_DataSource::SerializeAsArray() const {
+std::vector<uint8_t> FtraceDescriptor::SerializeAsArray() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsArray();
}
-void TracingServiceState_DataSource::Serialize(::protozero::Message* msg) const {
- // Field 1: ds_descriptor
- if (_has_field_[1]) {
- (*ds_descriptor_).Serialize(msg->BeginNestedMessage<::protozero::Message>(1));
- }
-
- // Field 2: producer_id
- if (_has_field_[2]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(2, producer_id_, msg);
+void FtraceDescriptor::Serialize(::protozero::Message* msg) const {
+ // Field 1: atrace_categories
+ for (auto& it : atrace_categories_) {
+ it.Serialize(msg->BeginNestedMessage<::protozero::Message>(1));
}
protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
}
-TracingServiceState_Producer::TracingServiceState_Producer() = default;
-TracingServiceState_Producer::~TracingServiceState_Producer() = default;
-TracingServiceState_Producer::TracingServiceState_Producer(const TracingServiceState_Producer&) = default;
-TracingServiceState_Producer& TracingServiceState_Producer::operator=(const TracingServiceState_Producer&) = default;
-TracingServiceState_Producer::TracingServiceState_Producer(TracingServiceState_Producer&&) noexcept = default;
-TracingServiceState_Producer& TracingServiceState_Producer::operator=(TracingServiceState_Producer&&) = default;
+FtraceDescriptor_AtraceCategory::FtraceDescriptor_AtraceCategory() = default;
+FtraceDescriptor_AtraceCategory::~FtraceDescriptor_AtraceCategory() = default;
+FtraceDescriptor_AtraceCategory::FtraceDescriptor_AtraceCategory(const FtraceDescriptor_AtraceCategory&) = default;
+FtraceDescriptor_AtraceCategory& FtraceDescriptor_AtraceCategory::operator=(const FtraceDescriptor_AtraceCategory&) = default;
+FtraceDescriptor_AtraceCategory::FtraceDescriptor_AtraceCategory(FtraceDescriptor_AtraceCategory&&) noexcept = default;
+FtraceDescriptor_AtraceCategory& FtraceDescriptor_AtraceCategory::operator=(FtraceDescriptor_AtraceCategory&&) = default;
-bool TracingServiceState_Producer::operator==(const TracingServiceState_Producer& other) const {
+bool FtraceDescriptor_AtraceCategory::operator==(const FtraceDescriptor_AtraceCategory& other) const {
return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
- && ::protozero::internal::gen_helpers::EqualsField(id_, other.id_)
&& ::protozero::internal::gen_helpers::EqualsField(name_, other.name_)
- && ::protozero::internal::gen_helpers::EqualsField(pid_, other.pid_)
- && ::protozero::internal::gen_helpers::EqualsField(uid_, other.uid_)
- && ::protozero::internal::gen_helpers::EqualsField(sdk_version_, other.sdk_version_)
- && ::protozero::internal::gen_helpers::EqualsField(frozen_, other.frozen_)
- && ::protozero::internal::gen_helpers::EqualsField(machine_id_, other.machine_id_)
- && ::protozero::internal::gen_helpers::EqualsField(machine_name_, other.machine_name_);
+ && ::protozero::internal::gen_helpers::EqualsField(description_, other.description_);
}
-bool TracingServiceState_Producer::ParseFromArray(const void* raw, size_t size) {
+bool FtraceDescriptor_AtraceCategory::ParseFromArray(const void* raw, size_t size) {
unknown_fields_.clear();
bool packed_error = false;
@@ -20947,29 +20669,11 @@ bool TracingServiceState_Producer::ParseFromArray(const void* raw, size_t size)
_has_field_.set(field.id());
}
switch (field.id()) {
- case 1 /* id */:
- field.get(&id_);
- break;
- case 2 /* name */:
+ case 1 /* name */:
::protozero::internal::gen_helpers::DeserializeString(field, &name_);
break;
- case 5 /* pid */:
- field.get(&pid_);
- break;
- case 3 /* uid */:
- field.get(&uid_);
- break;
- case 4 /* sdk_version */:
- ::protozero::internal::gen_helpers::DeserializeString(field, &sdk_version_);
- break;
- case 6 /* frozen */:
- field.get(&frozen_);
- break;
- case 7 /* machine_id */:
- field.get(&machine_id_);
- break;
- case 8 /* machine_name */:
- ::protozero::internal::gen_helpers::DeserializeString(field, &machine_name_);
+ case 2 /* description */:
+ ::protozero::internal::gen_helpers::DeserializeString(field, &description_);
break;
default:
field.SerializeAndAppendTo(&unknown_fields_);
@@ -20979,57 +20683,27 @@ bool TracingServiceState_Producer::ParseFromArray(const void* raw, size_t size)
return !packed_error && !dec.bytes_left();
}
-std::string TracingServiceState_Producer::SerializeAsString() const {
+std::string FtraceDescriptor_AtraceCategory::SerializeAsString() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsString();
}
-std::vector<uint8_t> TracingServiceState_Producer::SerializeAsArray() const {
+std::vector<uint8_t> FtraceDescriptor_AtraceCategory::SerializeAsArray() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsArray();
}
-void TracingServiceState_Producer::Serialize(::protozero::Message* msg) const {
- // Field 1: id
+void FtraceDescriptor_AtraceCategory::Serialize(::protozero::Message* msg) const {
+ // Field 1: name
if (_has_field_[1]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(1, id_, msg);
+ ::protozero::internal::gen_helpers::SerializeString(1, name_, msg);
}
- // Field 2: name
+ // Field 2: description
if (_has_field_[2]) {
- ::protozero::internal::gen_helpers::SerializeString(2, name_, msg);
- }
-
- // Field 5: pid
- if (_has_field_[5]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(5, pid_, msg);
- }
-
- // Field 3: uid
- if (_has_field_[3]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(3, uid_, msg);
- }
-
- // Field 4: sdk_version
- if (_has_field_[4]) {
- ::protozero::internal::gen_helpers::SerializeString(4, sdk_version_, msg);
- }
-
- // Field 6: frozen
- if (_has_field_[6]) {
- ::protozero::internal::gen_helpers::SerializeTinyVarInt(6, frozen_, msg);
- }
-
- // Field 7: machine_id
- if (_has_field_[7]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(7, machine_id_, msg);
- }
-
- // Field 8: machine_name
- if (_has_field_[8]) {
- ::protozero::internal::gen_helpers::SerializeString(8, machine_name_, msg);
+ ::protozero::internal::gen_helpers::SerializeString(2, description_, msg);
}
protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
@@ -21041,7 +20715,7 @@ void TracingServiceState_Producer::Serialize(::protozero::Message* msg) const {
#if defined(__GNUC__) || defined(__clang__)
#pragma GCC diagnostic pop
#endif
-// gen_amalgamated begin source: gen/protos/perfetto/common/track_event_descriptor.gen.cc
+// gen_amalgamated begin source: gen/protos/perfetto/common/gpu_counter_descriptor.gen.cc
// gen_amalgamated expanded: #include "perfetto/protozero/gen_field_helpers.h"
// gen_amalgamated expanded: #include "perfetto/protozero/message.h"
// gen_amalgamated expanded: #include "perfetto/protozero/packed_repeated_fields.h"
@@ -21052,29 +20726,44 @@ void TracingServiceState_Producer::Serialize(::protozero::Message* msg) const {
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wfloat-equal"
#endif
-// gen_amalgamated expanded: #include "protos/perfetto/common/track_event_descriptor.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/common/gpu_counter_descriptor.gen.h"
namespace perfetto {
namespace protos {
namespace gen {
-TrackEventDescriptor::TrackEventDescriptor() = default;
-TrackEventDescriptor::~TrackEventDescriptor() = default;
-TrackEventDescriptor::TrackEventDescriptor(const TrackEventDescriptor&) = default;
-TrackEventDescriptor& TrackEventDescriptor::operator=(const TrackEventDescriptor&) = default;
-TrackEventDescriptor::TrackEventDescriptor(TrackEventDescriptor&&) noexcept = default;
-TrackEventDescriptor& TrackEventDescriptor::operator=(TrackEventDescriptor&&) = default;
+GpuCounterDescriptor::GpuCounterDescriptor() = default;
+GpuCounterDescriptor::~GpuCounterDescriptor() = default;
+GpuCounterDescriptor::GpuCounterDescriptor(const GpuCounterDescriptor&) = default;
+GpuCounterDescriptor& GpuCounterDescriptor::operator=(const GpuCounterDescriptor&) = default;
+GpuCounterDescriptor::GpuCounterDescriptor(GpuCounterDescriptor&&) noexcept = default;
+GpuCounterDescriptor& GpuCounterDescriptor::operator=(GpuCounterDescriptor&&) = default;
-bool TrackEventDescriptor::operator==(const TrackEventDescriptor& other) const {
+bool GpuCounterDescriptor::operator==(const GpuCounterDescriptor& other) const {
return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
- && ::protozero::internal::gen_helpers::EqualsField(available_categories_, other.available_categories_);
+ && ::protozero::internal::gen_helpers::EqualsField(specs_, other.specs_)
+ && ::protozero::internal::gen_helpers::EqualsField(blocks_, other.blocks_)
+ && ::protozero::internal::gen_helpers::EqualsField(counter_groups_, other.counter_groups_)
+ && ::protozero::internal::gen_helpers::EqualsField(min_sampling_period_ns_, other.min_sampling_period_ns_)
+ && ::protozero::internal::gen_helpers::EqualsField(max_sampling_period_ns_, other.max_sampling_period_ns_)
+ && ::protozero::internal::gen_helpers::EqualsField(supports_instrumented_sampling_, other.supports_instrumented_sampling_)
+ && ::protozero::internal::gen_helpers::EqualsField(supports_counter_names_, other.supports_counter_names_)
+ && ::protozero::internal::gen_helpers::EqualsField(supports_counter_name_globs_, other.supports_counter_name_globs_);
}
-int TrackEventDescriptor::available_categories_size() const { return static_cast<int>(available_categories_.size()); }
-void TrackEventDescriptor::clear_available_categories() { available_categories_.clear(); }
-TrackEventCategory* TrackEventDescriptor::add_available_categories() { available_categories_.emplace_back(); return &available_categories_.back(); }
-bool TrackEventDescriptor::ParseFromArray(const void* raw, size_t size) {
- available_categories_.clear();
+int GpuCounterDescriptor::specs_size() const { return static_cast<int>(specs_.size()); }
+void GpuCounterDescriptor::clear_specs() { specs_.clear(); }
+GpuCounterDescriptor_GpuCounterSpec* GpuCounterDescriptor::add_specs() { specs_.emplace_back(); return &specs_.back(); }
+int GpuCounterDescriptor::blocks_size() const { return static_cast<int>(blocks_.size()); }
+void GpuCounterDescriptor::clear_blocks() { blocks_.clear(); }
+GpuCounterDescriptor_GpuCounterBlock* GpuCounterDescriptor::add_blocks() { blocks_.emplace_back(); return &blocks_.back(); }
+int GpuCounterDescriptor::counter_groups_size() const { return static_cast<int>(counter_groups_.size()); }
+void GpuCounterDescriptor::clear_counter_groups() { counter_groups_.clear(); }
+GpuCounterDescriptor_GpuCounterGroupSpec* GpuCounterDescriptor::add_counter_groups() { counter_groups_.emplace_back(); return &counter_groups_.back(); }
+bool GpuCounterDescriptor::ParseFromArray(const void* raw, size_t size) {
+ specs_.clear();
+ blocks_.clear();
+ counter_groups_.clear();
unknown_fields_.clear();
bool packed_error = false;
@@ -21084,9 +20773,32 @@ bool TrackEventDescriptor::ParseFromArray(const void* raw, size_t size) {
_has_field_.set(field.id());
}
switch (field.id()) {
- case 1 /* available_categories */:
- available_categories_.emplace_back();
- available_categories_.back().ParseFromArray(field.data(), field.size());
+ case 1 /* specs */:
+ specs_.emplace_back();
+ specs_.back().ParseFromArray(field.data(), field.size());
+ break;
+ case 2 /* blocks */:
+ blocks_.emplace_back();
+ blocks_.back().ParseFromArray(field.data(), field.size());
+ break;
+ case 6 /* counter_groups */:
+ counter_groups_.emplace_back();
+ counter_groups_.back().ParseFromArray(field.data(), field.size());
+ break;
+ case 3 /* min_sampling_period_ns */:
+ field.get(&min_sampling_period_ns_);
+ break;
+ case 4 /* max_sampling_period_ns */:
+ field.get(&max_sampling_period_ns_);
+ break;
+ case 5 /* supports_instrumented_sampling */:
+ field.get(&supports_instrumented_sampling_);
+ break;
+ case 7 /* supports_counter_names */:
+ field.get(&supports_counter_names_);
+ break;
+ case 8 /* supports_counter_name_globs */:
+ field.get(&supports_counter_name_globs_);
break;
default:
field.SerializeAndAppendTo(&unknown_fields_);
@@ -21096,44 +20808,80 @@ bool TrackEventDescriptor::ParseFromArray(const void* raw, size_t size) {
return !packed_error && !dec.bytes_left();
}
-std::string TrackEventDescriptor::SerializeAsString() const {
+std::string GpuCounterDescriptor::SerializeAsString() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsString();
}
-std::vector<uint8_t> TrackEventDescriptor::SerializeAsArray() const {
+std::vector<uint8_t> GpuCounterDescriptor::SerializeAsArray() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsArray();
}
-void TrackEventDescriptor::Serialize(::protozero::Message* msg) const {
- // Field 1: available_categories
- for (auto& it : available_categories_) {
+void GpuCounterDescriptor::Serialize(::protozero::Message* msg) const {
+ // Field 1: specs
+ for (auto& it : specs_) {
it.Serialize(msg->BeginNestedMessage<::protozero::Message>(1));
}
+ // Field 2: blocks
+ for (auto& it : blocks_) {
+ it.Serialize(msg->BeginNestedMessage<::protozero::Message>(2));
+ }
+
+ // Field 6: counter_groups
+ for (auto& it : counter_groups_) {
+ it.Serialize(msg->BeginNestedMessage<::protozero::Message>(6));
+ }
+
+ // Field 3: min_sampling_period_ns
+ if (_has_field_[3]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(3, min_sampling_period_ns_, msg);
+ }
+
+ // Field 4: max_sampling_period_ns
+ if (_has_field_[4]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(4, max_sampling_period_ns_, msg);
+ }
+
+ // Field 5: supports_instrumented_sampling
+ if (_has_field_[5]) {
+ ::protozero::internal::gen_helpers::SerializeTinyVarInt(5, supports_instrumented_sampling_, msg);
+ }
+
+ // Field 7: supports_counter_names
+ if (_has_field_[7]) {
+ ::protozero::internal::gen_helpers::SerializeTinyVarInt(7, supports_counter_names_, msg);
+ }
+
+ // Field 8: supports_counter_name_globs
+ if (_has_field_[8]) {
+ ::protozero::internal::gen_helpers::SerializeTinyVarInt(8, supports_counter_name_globs_, msg);
+ }
+
protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
}
-TrackEventCategory::TrackEventCategory() = default;
-TrackEventCategory::~TrackEventCategory() = default;
-TrackEventCategory::TrackEventCategory(const TrackEventCategory&) = default;
-TrackEventCategory& TrackEventCategory::operator=(const TrackEventCategory&) = default;
-TrackEventCategory::TrackEventCategory(TrackEventCategory&&) noexcept = default;
-TrackEventCategory& TrackEventCategory::operator=(TrackEventCategory&&) = default;
+GpuCounterDescriptor_GpuCounterGroupSpec::GpuCounterDescriptor_GpuCounterGroupSpec() = default;
+GpuCounterDescriptor_GpuCounterGroupSpec::~GpuCounterDescriptor_GpuCounterGroupSpec() = default;
+GpuCounterDescriptor_GpuCounterGroupSpec::GpuCounterDescriptor_GpuCounterGroupSpec(const GpuCounterDescriptor_GpuCounterGroupSpec&) = default;
+GpuCounterDescriptor_GpuCounterGroupSpec& GpuCounterDescriptor_GpuCounterGroupSpec::operator=(const GpuCounterDescriptor_GpuCounterGroupSpec&) = default;
+GpuCounterDescriptor_GpuCounterGroupSpec::GpuCounterDescriptor_GpuCounterGroupSpec(GpuCounterDescriptor_GpuCounterGroupSpec&&) noexcept = default;
+GpuCounterDescriptor_GpuCounterGroupSpec& GpuCounterDescriptor_GpuCounterGroupSpec::operator=(GpuCounterDescriptor_GpuCounterGroupSpec&&) = default;
-bool TrackEventCategory::operator==(const TrackEventCategory& other) const {
+bool GpuCounterDescriptor_GpuCounterGroupSpec::operator==(const GpuCounterDescriptor_GpuCounterGroupSpec& other) const {
return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
+ && ::protozero::internal::gen_helpers::EqualsField(group_id_, other.group_id_)
&& ::protozero::internal::gen_helpers::EqualsField(name_, other.name_)
&& ::protozero::internal::gen_helpers::EqualsField(description_, other.description_)
- && ::protozero::internal::gen_helpers::EqualsField(tags_, other.tags_);
+ && ::protozero::internal::gen_helpers::EqualsField(counter_ids_, other.counter_ids_);
}
-bool TrackEventCategory::ParseFromArray(const void* raw, size_t size) {
- tags_.clear();
+bool GpuCounterDescriptor_GpuCounterGroupSpec::ParseFromArray(const void* raw, size_t size) {
+ counter_ids_.clear();
unknown_fields_.clear();
bool packed_error = false;
@@ -21143,15 +20891,18 @@ bool TrackEventCategory::ParseFromArray(const void* raw, size_t size) {
_has_field_.set(field.id());
}
switch (field.id()) {
- case 1 /* name */:
+ case 1 /* group_id */:
+ field.get(&group_id_);
+ break;
+ case 2 /* name */:
::protozero::internal::gen_helpers::DeserializeString(field, &name_);
break;
- case 2 /* description */:
+ case 3 /* description */:
::protozero::internal::gen_helpers::DeserializeString(field, &description_);
break;
- case 3 /* tags */:
- tags_.emplace_back();
- ::protozero::internal::gen_helpers::DeserializeString(field, &tags_.back());
+ case 4 /* counter_ids */:
+ counter_ids_.emplace_back();
+ field.get(&counter_ids_.back());
break;
default:
field.SerializeAndAppendTo(&unknown_fields_);
@@ -21161,95 +20912,61 @@ bool TrackEventCategory::ParseFromArray(const void* raw, size_t size) {
return !packed_error && !dec.bytes_left();
}
-std::string TrackEventCategory::SerializeAsString() const {
+std::string GpuCounterDescriptor_GpuCounterGroupSpec::SerializeAsString() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsString();
}
-std::vector<uint8_t> TrackEventCategory::SerializeAsArray() const {
+std::vector<uint8_t> GpuCounterDescriptor_GpuCounterGroupSpec::SerializeAsArray() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsArray();
}
-void TrackEventCategory::Serialize(::protozero::Message* msg) const {
- // Field 1: name
+void GpuCounterDescriptor_GpuCounterGroupSpec::Serialize(::protozero::Message* msg) const {
+ // Field 1: group_id
if (_has_field_[1]) {
- ::protozero::internal::gen_helpers::SerializeString(1, name_, msg);
+ ::protozero::internal::gen_helpers::SerializeVarInt(1, group_id_, msg);
}
- // Field 2: description
+ // Field 2: name
if (_has_field_[2]) {
- ::protozero::internal::gen_helpers::SerializeString(2, description_, msg);
+ ::protozero::internal::gen_helpers::SerializeString(2, name_, msg);
}
- // Field 3: tags
- for (auto& it : tags_) {
- ::protozero::internal::gen_helpers::SerializeString(3, it, msg);
+ // Field 3: description
+ if (_has_field_[3]) {
+ ::protozero::internal::gen_helpers::SerializeString(3, description_, msg);
+ }
+
+ // Field 4: counter_ids
+ for (auto& it : counter_ids_) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(4, it, msg);
}
protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
}
-} // namespace perfetto
-} // namespace protos
-} // namespace gen
-#if defined(__GNUC__) || defined(__clang__)
-#pragma GCC diagnostic pop
-#endif
-// gen_amalgamated begin source: gen/protos/perfetto/common/semantic_type.gen.cc
-// gen_amalgamated expanded: #include "perfetto/protozero/gen_field_helpers.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/message.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/packed_repeated_fields.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/proto_decoder.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/scattered_heap_buffer.h"
-// DO NOT EDIT. Autogenerated by Perfetto cppgen_plugin
-#if defined(__GNUC__) || defined(__clang__)
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wfloat-equal"
-#endif
-// gen_amalgamated expanded: #include "protos/perfetto/common/semantic_type.gen.h"
-
-namespace perfetto {
-namespace protos {
-namespace gen {
-} // namespace perfetto
-} // namespace protos
-} // namespace gen
-#if defined(__GNUC__) || defined(__clang__)
-#pragma GCC diagnostic pop
-#endif
-// gen_amalgamated begin source: gen/protos/perfetto/config/android/android_aflags_config.gen.cc
-// gen_amalgamated expanded: #include "perfetto/protozero/gen_field_helpers.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/message.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/packed_repeated_fields.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/proto_decoder.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/scattered_heap_buffer.h"
-// DO NOT EDIT. Autogenerated by Perfetto cppgen_plugin
-#if defined(__GNUC__) || defined(__clang__)
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wfloat-equal"
-#endif
-// gen_amalgamated expanded: #include "protos/perfetto/config/android/android_aflags_config.gen.h"
-
-namespace perfetto {
-namespace protos {
-namespace gen {
-AndroidAflagsConfig::AndroidAflagsConfig() = default;
-AndroidAflagsConfig::~AndroidAflagsConfig() = default;
-AndroidAflagsConfig::AndroidAflagsConfig(const AndroidAflagsConfig&) = default;
-AndroidAflagsConfig& AndroidAflagsConfig::operator=(const AndroidAflagsConfig&) = default;
-AndroidAflagsConfig::AndroidAflagsConfig(AndroidAflagsConfig&&) noexcept = default;
-AndroidAflagsConfig& AndroidAflagsConfig::operator=(AndroidAflagsConfig&&) = default;
+GpuCounterDescriptor_GpuCounterBlock::GpuCounterDescriptor_GpuCounterBlock() = default;
+GpuCounterDescriptor_GpuCounterBlock::~GpuCounterDescriptor_GpuCounterBlock() = default;
+GpuCounterDescriptor_GpuCounterBlock::GpuCounterDescriptor_GpuCounterBlock(const GpuCounterDescriptor_GpuCounterBlock&) = default;
+GpuCounterDescriptor_GpuCounterBlock& GpuCounterDescriptor_GpuCounterBlock::operator=(const GpuCounterDescriptor_GpuCounterBlock&) = default;
+GpuCounterDescriptor_GpuCounterBlock::GpuCounterDescriptor_GpuCounterBlock(GpuCounterDescriptor_GpuCounterBlock&&) noexcept = default;
+GpuCounterDescriptor_GpuCounterBlock& GpuCounterDescriptor_GpuCounterBlock::operator=(GpuCounterDescriptor_GpuCounterBlock&&) = default;
-bool AndroidAflagsConfig::operator==(const AndroidAflagsConfig& other) const {
+bool GpuCounterDescriptor_GpuCounterBlock::operator==(const GpuCounterDescriptor_GpuCounterBlock& other) const {
return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
- && ::protozero::internal::gen_helpers::EqualsField(poll_ms_, other.poll_ms_);
+ && ::protozero::internal::gen_helpers::EqualsField(block_id_, other.block_id_)
+ && ::protozero::internal::gen_helpers::EqualsField(block_capacity_, other.block_capacity_)
+ && ::protozero::internal::gen_helpers::EqualsField(name_, other.name_)
+ && ::protozero::internal::gen_helpers::EqualsField(description_, other.description_)
+ && ::protozero::internal::gen_helpers::EqualsField(counter_ids_, other.counter_ids_);
}
-bool AndroidAflagsConfig::ParseFromArray(const void* raw, size_t size) {
+bool GpuCounterDescriptor_GpuCounterBlock::ParseFromArray(const void* raw, size_t size) {
+ counter_ids_.clear();
unknown_fields_.clear();
bool packed_error = false;
@@ -21259,8 +20976,21 @@ bool AndroidAflagsConfig::ParseFromArray(const void* raw, size_t size) {
_has_field_.set(field.id());
}
switch (field.id()) {
- case 1 /* poll_ms */:
- field.get(&poll_ms_);
+ case 1 /* block_id */:
+ field.get(&block_id_);
+ break;
+ case 2 /* block_capacity */:
+ field.get(&block_capacity_);
+ break;
+ case 3 /* name */:
+ ::protozero::internal::gen_helpers::DeserializeString(field, &name_);
+ break;
+ case 4 /* description */:
+ ::protozero::internal::gen_helpers::DeserializeString(field, &description_);
+ break;
+ case 5 /* counter_ids */:
+ counter_ids_.emplace_back();
+ field.get(&counter_ids_.back());
break;
default:
field.SerializeAndAppendTo(&unknown_fields_);
@@ -21270,64 +21000,225 @@ bool AndroidAflagsConfig::ParseFromArray(const void* raw, size_t size) {
return !packed_error && !dec.bytes_left();
}
-std::string AndroidAflagsConfig::SerializeAsString() const {
+std::string GpuCounterDescriptor_GpuCounterBlock::SerializeAsString() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsString();
}
-std::vector<uint8_t> AndroidAflagsConfig::SerializeAsArray() const {
+std::vector<uint8_t> GpuCounterDescriptor_GpuCounterBlock::SerializeAsArray() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsArray();
}
-void AndroidAflagsConfig::Serialize(::protozero::Message* msg) const {
- // Field 1: poll_ms
+void GpuCounterDescriptor_GpuCounterBlock::Serialize(::protozero::Message* msg) const {
+ // Field 1: block_id
if (_has_field_[1]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(1, poll_ms_, msg);
+ ::protozero::internal::gen_helpers::SerializeVarInt(1, block_id_, msg);
}
- protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
-}
+ // Field 2: block_capacity
+ if (_has_field_[2]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(2, block_capacity_, msg);
+ }
-} // namespace perfetto
-} // namespace protos
-} // namespace gen
-#if defined(__GNUC__) || defined(__clang__)
-#pragma GCC diagnostic pop
-#endif
-// gen_amalgamated begin source: gen/protos/perfetto/config/android/android_game_intervention_list_config.gen.cc
-// gen_amalgamated expanded: #include "perfetto/protozero/gen_field_helpers.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/message.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/packed_repeated_fields.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/proto_decoder.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/scattered_heap_buffer.h"
+ // Field 3: name
+ if (_has_field_[3]) {
+ ::protozero::internal::gen_helpers::SerializeString(3, name_, msg);
+ }
+
+ // Field 4: description
+ if (_has_field_[4]) {
+ ::protozero::internal::gen_helpers::SerializeString(4, description_, msg);
+ }
+
+ // Field 5: counter_ids
+ for (auto& it : counter_ids_) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(5, it, msg);
+ }
+
+ protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
+}
+
+
+GpuCounterDescriptor_GpuCounterSpec::GpuCounterDescriptor_GpuCounterSpec() = default;
+GpuCounterDescriptor_GpuCounterSpec::~GpuCounterDescriptor_GpuCounterSpec() = default;
+GpuCounterDescriptor_GpuCounterSpec::GpuCounterDescriptor_GpuCounterSpec(const GpuCounterDescriptor_GpuCounterSpec&) = default;
+GpuCounterDescriptor_GpuCounterSpec& GpuCounterDescriptor_GpuCounterSpec::operator=(const GpuCounterDescriptor_GpuCounterSpec&) = default;
+GpuCounterDescriptor_GpuCounterSpec::GpuCounterDescriptor_GpuCounterSpec(GpuCounterDescriptor_GpuCounterSpec&&) noexcept = default;
+GpuCounterDescriptor_GpuCounterSpec& GpuCounterDescriptor_GpuCounterSpec::operator=(GpuCounterDescriptor_GpuCounterSpec&&) = default;
+
+bool GpuCounterDescriptor_GpuCounterSpec::operator==(const GpuCounterDescriptor_GpuCounterSpec& other) const {
+ return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
+ && ::protozero::internal::gen_helpers::EqualsField(counter_id_, other.counter_id_)
+ && ::protozero::internal::gen_helpers::EqualsField(name_, other.name_)
+ && ::protozero::internal::gen_helpers::EqualsField(description_, other.description_)
+ && ::protozero::internal::gen_helpers::EqualsField(int_peak_value_, other.int_peak_value_)
+ && ::protozero::internal::gen_helpers::EqualsField(double_peak_value_, other.double_peak_value_)
+ && ::protozero::internal::gen_helpers::EqualsField(numerator_units_, other.numerator_units_)
+ && ::protozero::internal::gen_helpers::EqualsField(denominator_units_, other.denominator_units_)
+ && ::protozero::internal::gen_helpers::EqualsField(select_by_default_, other.select_by_default_)
+ && ::protozero::internal::gen_helpers::EqualsField(groups_, other.groups_)
+ && ::protozero::internal::gen_helpers::EqualsField(value_direction_, other.value_direction_);
+}
+
+bool GpuCounterDescriptor_GpuCounterSpec::ParseFromArray(const void* raw, size_t size) {
+ numerator_units_.clear();
+ denominator_units_.clear();
+ groups_.clear();
+ unknown_fields_.clear();
+ bool packed_error = false;
+
+ ::protozero::ProtoDecoder dec(raw, size);
+ for (auto field = dec.ReadField(); field.valid(); field = dec.ReadField()) {
+ if (field.id() < _has_field_.size()) {
+ _has_field_.set(field.id());
+ }
+ switch (field.id()) {
+ case 1 /* counter_id */:
+ field.get(&counter_id_);
+ break;
+ case 2 /* name */:
+ ::protozero::internal::gen_helpers::DeserializeString(field, &name_);
+ break;
+ case 3 /* description */:
+ ::protozero::internal::gen_helpers::DeserializeString(field, &description_);
+ break;
+ case 5 /* int_peak_value */:
+ field.get(&int_peak_value_);
+ break;
+ case 6 /* double_peak_value */:
+ field.get(&double_peak_value_);
+ break;
+ case 7 /* numerator_units */:
+ numerator_units_.emplace_back();
+ field.get(&numerator_units_.back());
+ break;
+ case 8 /* denominator_units */:
+ denominator_units_.emplace_back();
+ field.get(&denominator_units_.back());
+ break;
+ case 9 /* select_by_default */:
+ field.get(&select_by_default_);
+ break;
+ case 10 /* groups */:
+ groups_.emplace_back();
+ field.get(&groups_.back());
+ break;
+ case 11 /* value_direction */:
+ field.get(&value_direction_);
+ break;
+ default:
+ field.SerializeAndAppendTo(&unknown_fields_);
+ break;
+ }
+ }
+ return !packed_error && !dec.bytes_left();
+}
+
+std::string GpuCounterDescriptor_GpuCounterSpec::SerializeAsString() const {
+ ::protozero::internal::gen_helpers::MessageSerializer msg;
+ Serialize(msg.get());
+ return msg.SerializeAsString();
+}
+
+std::vector<uint8_t> GpuCounterDescriptor_GpuCounterSpec::SerializeAsArray() const {
+ ::protozero::internal::gen_helpers::MessageSerializer msg;
+ Serialize(msg.get());
+ return msg.SerializeAsArray();
+}
+
+void GpuCounterDescriptor_GpuCounterSpec::Serialize(::protozero::Message* msg) const {
+ // Field 1: counter_id
+ if (_has_field_[1]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(1, counter_id_, msg);
+ }
+
+ // Field 2: name
+ if (_has_field_[2]) {
+ ::protozero::internal::gen_helpers::SerializeString(2, name_, msg);
+ }
+
+ // Field 3: description
+ if (_has_field_[3]) {
+ ::protozero::internal::gen_helpers::SerializeString(3, description_, msg);
+ }
+
+ // Field 5: int_peak_value
+ if (_has_field_[5]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(5, int_peak_value_, msg);
+ }
+
+ // Field 6: double_peak_value
+ if (_has_field_[6]) {
+ ::protozero::internal::gen_helpers::SerializeFixed(6, double_peak_value_, msg);
+ }
+
+ // Field 7: numerator_units
+ for (auto& it : numerator_units_) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(7, it, msg);
+ }
+
+ // Field 8: denominator_units
+ for (auto& it : denominator_units_) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(8, it, msg);
+ }
+
+ // Field 9: select_by_default
+ if (_has_field_[9]) {
+ ::protozero::internal::gen_helpers::SerializeTinyVarInt(9, select_by_default_, msg);
+ }
+
+ // Field 10: groups
+ for (auto& it : groups_) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(10, it, msg);
+ }
+
+ // Field 11: value_direction
+ if (_has_field_[11]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(11, value_direction_, msg);
+ }
+
+ protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
+}
+
+} // namespace perfetto
+} // namespace protos
+} // namespace gen
+#if defined(__GNUC__) || defined(__clang__)
+#pragma GCC diagnostic pop
+#endif
+// gen_amalgamated begin source: gen/protos/perfetto/common/interceptor_descriptor.gen.cc
+// gen_amalgamated expanded: #include "perfetto/protozero/gen_field_helpers.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/message.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/packed_repeated_fields.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/proto_decoder.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/scattered_heap_buffer.h"
// DO NOT EDIT. Autogenerated by Perfetto cppgen_plugin
#if defined(__GNUC__) || defined(__clang__)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wfloat-equal"
#endif
-// gen_amalgamated expanded: #include "protos/perfetto/config/android/android_game_intervention_list_config.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/common/interceptor_descriptor.gen.h"
namespace perfetto {
namespace protos {
namespace gen {
-AndroidGameInterventionListConfig::AndroidGameInterventionListConfig() = default;
-AndroidGameInterventionListConfig::~AndroidGameInterventionListConfig() = default;
-AndroidGameInterventionListConfig::AndroidGameInterventionListConfig(const AndroidGameInterventionListConfig&) = default;
-AndroidGameInterventionListConfig& AndroidGameInterventionListConfig::operator=(const AndroidGameInterventionListConfig&) = default;
-AndroidGameInterventionListConfig::AndroidGameInterventionListConfig(AndroidGameInterventionListConfig&&) noexcept = default;
-AndroidGameInterventionListConfig& AndroidGameInterventionListConfig::operator=(AndroidGameInterventionListConfig&&) = default;
+InterceptorDescriptor::InterceptorDescriptor() = default;
+InterceptorDescriptor::~InterceptorDescriptor() = default;
+InterceptorDescriptor::InterceptorDescriptor(const InterceptorDescriptor&) = default;
+InterceptorDescriptor& InterceptorDescriptor::operator=(const InterceptorDescriptor&) = default;
+InterceptorDescriptor::InterceptorDescriptor(InterceptorDescriptor&&) noexcept = default;
+InterceptorDescriptor& InterceptorDescriptor::operator=(InterceptorDescriptor&&) = default;
-bool AndroidGameInterventionListConfig::operator==(const AndroidGameInterventionListConfig& other) const {
+bool InterceptorDescriptor::operator==(const InterceptorDescriptor& other) const {
return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
- && ::protozero::internal::gen_helpers::EqualsField(package_name_filter_, other.package_name_filter_);
+ && ::protozero::internal::gen_helpers::EqualsField(name_, other.name_);
}
-bool AndroidGameInterventionListConfig::ParseFromArray(const void* raw, size_t size) {
- package_name_filter_.clear();
+bool InterceptorDescriptor::ParseFromArray(const void* raw, size_t size) {
unknown_fields_.clear();
bool packed_error = false;
@@ -21337,9 +21228,8 @@ bool AndroidGameInterventionListConfig::ParseFromArray(const void* raw, size_t s
_has_field_.set(field.id());
}
switch (field.id()) {
- case 1 /* package_name_filter */:
- package_name_filter_.emplace_back();
- ::protozero::internal::gen_helpers::DeserializeString(field, &package_name_filter_.back());
+ case 1 /* name */:
+ ::protozero::internal::gen_helpers::DeserializeString(field, &name_);
break;
default:
field.SerializeAndAppendTo(&unknown_fields_);
@@ -21349,22 +21239,22 @@ bool AndroidGameInterventionListConfig::ParseFromArray(const void* raw, size_t s
return !packed_error && !dec.bytes_left();
}
-std::string AndroidGameInterventionListConfig::SerializeAsString() const {
+std::string InterceptorDescriptor::SerializeAsString() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsString();
}
-std::vector<uint8_t> AndroidGameInterventionListConfig::SerializeAsArray() const {
+std::vector<uint8_t> InterceptorDescriptor::SerializeAsArray() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsArray();
}
-void AndroidGameInterventionListConfig::Serialize(::protozero::Message* msg) const {
- // Field 1: package_name_filter
- for (auto& it : package_name_filter_) {
- ::protozero::internal::gen_helpers::SerializeString(1, it, msg);
+void InterceptorDescriptor::Serialize(::protozero::Message* msg) const {
+ // Field 1: name
+ if (_has_field_[1]) {
+ ::protozero::internal::gen_helpers::SerializeString(1, name_, msg);
}
protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
@@ -21376,7 +21266,7 @@ void AndroidGameInterventionListConfig::Serialize(::protozero::Message* msg) con
#if defined(__GNUC__) || defined(__clang__)
#pragma GCC diagnostic pop
#endif
-// gen_amalgamated begin source: gen/protos/perfetto/config/android/android_input_event_config.gen.cc
+// gen_amalgamated begin source: gen/protos/perfetto/common/observable_events.gen.cc
// gen_amalgamated expanded: #include "perfetto/protozero/gen_field_helpers.h"
// gen_amalgamated expanded: #include "perfetto/protozero/message.h"
// gen_amalgamated expanded: #include "perfetto/protozero/packed_repeated_fields.h"
@@ -21387,33 +21277,31 @@ void AndroidGameInterventionListConfig::Serialize(::protozero::Message* msg) con
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wfloat-equal"
#endif
-// gen_amalgamated expanded: #include "protos/perfetto/config/android/android_input_event_config.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/common/observable_events.gen.h"
namespace perfetto {
namespace protos {
namespace gen {
-AndroidInputEventConfig::AndroidInputEventConfig() = default;
-AndroidInputEventConfig::~AndroidInputEventConfig() = default;
-AndroidInputEventConfig::AndroidInputEventConfig(const AndroidInputEventConfig&) = default;
-AndroidInputEventConfig& AndroidInputEventConfig::operator=(const AndroidInputEventConfig&) = default;
-AndroidInputEventConfig::AndroidInputEventConfig(AndroidInputEventConfig&&) noexcept = default;
-AndroidInputEventConfig& AndroidInputEventConfig::operator=(AndroidInputEventConfig&&) = default;
+ObservableEvents::ObservableEvents() = default;
+ObservableEvents::~ObservableEvents() = default;
+ObservableEvents::ObservableEvents(const ObservableEvents&) = default;
+ObservableEvents& ObservableEvents::operator=(const ObservableEvents&) = default;
+ObservableEvents::ObservableEvents(ObservableEvents&&) noexcept = default;
+ObservableEvents& ObservableEvents::operator=(ObservableEvents&&) = default;
-bool AndroidInputEventConfig::operator==(const AndroidInputEventConfig& other) const {
+bool ObservableEvents::operator==(const ObservableEvents& other) const {
return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
- && ::protozero::internal::gen_helpers::EqualsField(mode_, other.mode_)
- && ::protozero::internal::gen_helpers::EqualsField(rules_, other.rules_)
- && ::protozero::internal::gen_helpers::EqualsField(trace_dispatcher_input_events_, other.trace_dispatcher_input_events_)
- && ::protozero::internal::gen_helpers::EqualsField(trace_dispatcher_window_dispatch_, other.trace_dispatcher_window_dispatch_)
- && ::protozero::internal::gen_helpers::EqualsField(trace_evdev_events_, other.trace_evdev_events_);
+ && ::protozero::internal::gen_helpers::EqualsField(instance_state_changes_, other.instance_state_changes_)
+ && ::protozero::internal::gen_helpers::EqualsField(all_data_sources_started_, other.all_data_sources_started_)
+ && ::protozero::internal::gen_helpers::EqualsField(clone_trigger_hit_, other.clone_trigger_hit_);
}
-int AndroidInputEventConfig::rules_size() const { return static_cast<int>(rules_.size()); }
-void AndroidInputEventConfig::clear_rules() { rules_.clear(); }
-AndroidInputEventConfig_TraceRule* AndroidInputEventConfig::add_rules() { rules_.emplace_back(); return &rules_.back(); }
-bool AndroidInputEventConfig::ParseFromArray(const void* raw, size_t size) {
- rules_.clear();
+int ObservableEvents::instance_state_changes_size() const { return static_cast<int>(instance_state_changes_.size()); }
+void ObservableEvents::clear_instance_state_changes() { instance_state_changes_.clear(); }
+ObservableEvents_DataSourceInstanceStateChange* ObservableEvents::add_instance_state_changes() { instance_state_changes_.emplace_back(); return &instance_state_changes_.back(); }
+bool ObservableEvents::ParseFromArray(const void* raw, size_t size) {
+ instance_state_changes_.clear();
unknown_fields_.clear();
bool packed_error = false;
@@ -21423,21 +21311,15 @@ bool AndroidInputEventConfig::ParseFromArray(const void* raw, size_t size) {
_has_field_.set(field.id());
}
switch (field.id()) {
- case 1 /* mode */:
- field.get(&mode_);
- break;
- case 2 /* rules */:
- rules_.emplace_back();
- rules_.back().ParseFromArray(field.data(), field.size());
- break;
- case 3 /* trace_dispatcher_input_events */:
- field.get(&trace_dispatcher_input_events_);
+ case 1 /* instance_state_changes */:
+ instance_state_changes_.emplace_back();
+ instance_state_changes_.back().ParseFromArray(field.data(), field.size());
break;
- case 4 /* trace_dispatcher_window_dispatch */:
- field.get(&trace_dispatcher_window_dispatch_);
+ case 2 /* all_data_sources_started */:
+ field.get(&all_data_sources_started_);
break;
- case 5 /* trace_evdev_events */:
- field.get(&trace_evdev_events_);
+ case 3 /* clone_trigger_hit */:
+ (*clone_trigger_hit_).ParseFromArray(field.data(), field.size());
break;
default:
field.SerializeAndAppendTo(&unknown_fields_);
@@ -21447,67 +21329,56 @@ bool AndroidInputEventConfig::ParseFromArray(const void* raw, size_t size) {
return !packed_error && !dec.bytes_left();
}
-std::string AndroidInputEventConfig::SerializeAsString() const {
+std::string ObservableEvents::SerializeAsString() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsString();
}
-std::vector<uint8_t> AndroidInputEventConfig::SerializeAsArray() const {
+std::vector<uint8_t> ObservableEvents::SerializeAsArray() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsArray();
}
-void AndroidInputEventConfig::Serialize(::protozero::Message* msg) const {
- // Field 1: mode
- if (_has_field_[1]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(1, mode_, msg);
+void ObservableEvents::Serialize(::protozero::Message* msg) const {
+ // Field 1: instance_state_changes
+ for (auto& it : instance_state_changes_) {
+ it.Serialize(msg->BeginNestedMessage<::protozero::Message>(1));
}
- // Field 2: rules
- for (auto& it : rules_) {
- it.Serialize(msg->BeginNestedMessage<::protozero::Message>(2));
+ // Field 2: all_data_sources_started
+ if (_has_field_[2]) {
+ ::protozero::internal::gen_helpers::SerializeTinyVarInt(2, all_data_sources_started_, msg);
}
- // Field 3: trace_dispatcher_input_events
+ // Field 3: clone_trigger_hit
if (_has_field_[3]) {
- ::protozero::internal::gen_helpers::SerializeTinyVarInt(3, trace_dispatcher_input_events_, msg);
- }
-
- // Field 4: trace_dispatcher_window_dispatch
- if (_has_field_[4]) {
- ::protozero::internal::gen_helpers::SerializeTinyVarInt(4, trace_dispatcher_window_dispatch_, msg);
- }
-
- // Field 5: trace_evdev_events
- if (_has_field_[5]) {
- ::protozero::internal::gen_helpers::SerializeTinyVarInt(5, trace_evdev_events_, msg);
+ (*clone_trigger_hit_).Serialize(msg->BeginNestedMessage<::protozero::Message>(3));
}
protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
}
-AndroidInputEventConfig_TraceRule::AndroidInputEventConfig_TraceRule() = default;
-AndroidInputEventConfig_TraceRule::~AndroidInputEventConfig_TraceRule() = default;
-AndroidInputEventConfig_TraceRule::AndroidInputEventConfig_TraceRule(const AndroidInputEventConfig_TraceRule&) = default;
-AndroidInputEventConfig_TraceRule& AndroidInputEventConfig_TraceRule::operator=(const AndroidInputEventConfig_TraceRule&) = default;
-AndroidInputEventConfig_TraceRule::AndroidInputEventConfig_TraceRule(AndroidInputEventConfig_TraceRule&&) noexcept = default;
-AndroidInputEventConfig_TraceRule& AndroidInputEventConfig_TraceRule::operator=(AndroidInputEventConfig_TraceRule&&) = default;
+ObservableEvents_CloneTriggerHit::ObservableEvents_CloneTriggerHit() = default;
+ObservableEvents_CloneTriggerHit::~ObservableEvents_CloneTriggerHit() = default;
+ObservableEvents_CloneTriggerHit::ObservableEvents_CloneTriggerHit(const ObservableEvents_CloneTriggerHit&) = default;
+ObservableEvents_CloneTriggerHit& ObservableEvents_CloneTriggerHit::operator=(const ObservableEvents_CloneTriggerHit&) = default;
+ObservableEvents_CloneTriggerHit::ObservableEvents_CloneTriggerHit(ObservableEvents_CloneTriggerHit&&) noexcept = default;
+ObservableEvents_CloneTriggerHit& ObservableEvents_CloneTriggerHit::operator=(ObservableEvents_CloneTriggerHit&&) = default;
-bool AndroidInputEventConfig_TraceRule::operator==(const AndroidInputEventConfig_TraceRule& other) const {
+bool ObservableEvents_CloneTriggerHit::operator==(const ObservableEvents_CloneTriggerHit& other) const {
return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
- && ::protozero::internal::gen_helpers::EqualsField(trace_level_, other.trace_level_)
- && ::protozero::internal::gen_helpers::EqualsField(match_all_packages_, other.match_all_packages_)
- && ::protozero::internal::gen_helpers::EqualsField(match_any_packages_, other.match_any_packages_)
- && ::protozero::internal::gen_helpers::EqualsField(match_secure_, other.match_secure_)
- && ::protozero::internal::gen_helpers::EqualsField(match_ime_connection_active_, other.match_ime_connection_active_);
+ && ::protozero::internal::gen_helpers::EqualsField(tracing_session_id_, other.tracing_session_id_)
+ && ::protozero::internal::gen_helpers::EqualsField(trigger_name_, other.trigger_name_)
+ && ::protozero::internal::gen_helpers::EqualsField(producer_name_, other.producer_name_)
+ && ::protozero::internal::gen_helpers::EqualsField(producer_uid_, other.producer_uid_)
+ && ::protozero::internal::gen_helpers::EqualsField(boot_time_ns_, other.boot_time_ns_)
+ && ::protozero::internal::gen_helpers::EqualsField(trigger_delay_ms_, other.trigger_delay_ms_);
}
-bool AndroidInputEventConfig_TraceRule::ParseFromArray(const void* raw, size_t size) {
- match_all_packages_.clear();
- match_any_packages_.clear();
+bool ObservableEvents_CloneTriggerHit::ParseFromArray(const void* raw, size_t size) {
unknown_fields_.clear();
bool packed_error = false;
@@ -21517,22 +21388,23 @@ bool AndroidInputEventConfig_TraceRule::ParseFromArray(const void* raw, size_t s
_has_field_.set(field.id());
}
switch (field.id()) {
- case 1 /* trace_level */:
- field.get(&trace_level_);
+ case 1 /* tracing_session_id */:
+ field.get(&tracing_session_id_);
break;
- case 2 /* match_all_packages */:
- match_all_packages_.emplace_back();
- ::protozero::internal::gen_helpers::DeserializeString(field, &match_all_packages_.back());
+ case 2 /* trigger_name */:
+ ::protozero::internal::gen_helpers::DeserializeString(field, &trigger_name_);
break;
- case 3 /* match_any_packages */:
- match_any_packages_.emplace_back();
- ::protozero::internal::gen_helpers::DeserializeString(field, &match_any_packages_.back());
+ case 3 /* producer_name */:
+ ::protozero::internal::gen_helpers::DeserializeString(field, &producer_name_);
break;
- case 4 /* match_secure */:
- field.get(&match_secure_);
+ case 4 /* producer_uid */:
+ field.get(&producer_uid_);
break;
- case 5 /* match_ime_connection_active */:
- field.get(&match_ime_connection_active_);
+ case 5 /* boot_time_ns */:
+ field.get(&boot_time_ns_);
+ break;
+ case 6 /* trigger_delay_ms */:
+ field.get(&trigger_delay_ms_);
break;
default:
field.SerializeAndAppendTo(&unknown_fields_);
@@ -21542,89 +21414,68 @@ bool AndroidInputEventConfig_TraceRule::ParseFromArray(const void* raw, size_t s
return !packed_error && !dec.bytes_left();
}
-std::string AndroidInputEventConfig_TraceRule::SerializeAsString() const {
+std::string ObservableEvents_CloneTriggerHit::SerializeAsString() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsString();
}
-std::vector<uint8_t> AndroidInputEventConfig_TraceRule::SerializeAsArray() const {
+std::vector<uint8_t> ObservableEvents_CloneTriggerHit::SerializeAsArray() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsArray();
}
-void AndroidInputEventConfig_TraceRule::Serialize(::protozero::Message* msg) const {
- // Field 1: trace_level
+void ObservableEvents_CloneTriggerHit::Serialize(::protozero::Message* msg) const {
+ // Field 1: tracing_session_id
if (_has_field_[1]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(1, trace_level_, msg);
+ ::protozero::internal::gen_helpers::SerializeVarInt(1, tracing_session_id_, msg);
}
- // Field 2: match_all_packages
- for (auto& it : match_all_packages_) {
- ::protozero::internal::gen_helpers::SerializeString(2, it, msg);
+ // Field 2: trigger_name
+ if (_has_field_[2]) {
+ ::protozero::internal::gen_helpers::SerializeString(2, trigger_name_, msg);
}
- // Field 3: match_any_packages
- for (auto& it : match_any_packages_) {
- ::protozero::internal::gen_helpers::SerializeString(3, it, msg);
+ // Field 3: producer_name
+ if (_has_field_[3]) {
+ ::protozero::internal::gen_helpers::SerializeString(3, producer_name_, msg);
}
- // Field 4: match_secure
+ // Field 4: producer_uid
if (_has_field_[4]) {
- ::protozero::internal::gen_helpers::SerializeTinyVarInt(4, match_secure_, msg);
+ ::protozero::internal::gen_helpers::SerializeVarInt(4, producer_uid_, msg);
}
- // Field 5: match_ime_connection_active
+ // Field 5: boot_time_ns
if (_has_field_[5]) {
- ::protozero::internal::gen_helpers::SerializeTinyVarInt(5, match_ime_connection_active_, msg);
+ ::protozero::internal::gen_helpers::SerializeVarInt(5, boot_time_ns_, msg);
+ }
+
+ // Field 6: trigger_delay_ms
+ if (_has_field_[6]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(6, trigger_delay_ms_, msg);
}
protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
}
-} // namespace perfetto
-} // namespace protos
-} // namespace gen
-#if defined(__GNUC__) || defined(__clang__)
-#pragma GCC diagnostic pop
-#endif
-// gen_amalgamated begin source: gen/protos/perfetto/config/android/android_log_config.gen.cc
-// gen_amalgamated expanded: #include "perfetto/protozero/gen_field_helpers.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/message.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/packed_repeated_fields.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/proto_decoder.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/scattered_heap_buffer.h"
-// DO NOT EDIT. Autogenerated by Perfetto cppgen_plugin
-#if defined(__GNUC__) || defined(__clang__)
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wfloat-equal"
-#endif
-// gen_amalgamated expanded: #include "protos/perfetto/config/android/android_log_config.gen.h"
-// gen_amalgamated expanded: #include "protos/perfetto/common/android_log_constants.gen.h"
-
-namespace perfetto {
-namespace protos {
-namespace gen {
-AndroidLogConfig::AndroidLogConfig() = default;
-AndroidLogConfig::~AndroidLogConfig() = default;
-AndroidLogConfig::AndroidLogConfig(const AndroidLogConfig&) = default;
-AndroidLogConfig& AndroidLogConfig::operator=(const AndroidLogConfig&) = default;
-AndroidLogConfig::AndroidLogConfig(AndroidLogConfig&&) noexcept = default;
-AndroidLogConfig& AndroidLogConfig::operator=(AndroidLogConfig&&) = default;
+ObservableEvents_DataSourceInstanceStateChange::ObservableEvents_DataSourceInstanceStateChange() = default;
+ObservableEvents_DataSourceInstanceStateChange::~ObservableEvents_DataSourceInstanceStateChange() = default;
+ObservableEvents_DataSourceInstanceStateChange::ObservableEvents_DataSourceInstanceStateChange(const ObservableEvents_DataSourceInstanceStateChange&) = default;
+ObservableEvents_DataSourceInstanceStateChange& ObservableEvents_DataSourceInstanceStateChange::operator=(const ObservableEvents_DataSourceInstanceStateChange&) = default;
+ObservableEvents_DataSourceInstanceStateChange::ObservableEvents_DataSourceInstanceStateChange(ObservableEvents_DataSourceInstanceStateChange&&) noexcept = default;
+ObservableEvents_DataSourceInstanceStateChange& ObservableEvents_DataSourceInstanceStateChange::operator=(ObservableEvents_DataSourceInstanceStateChange&&) = default;
-bool AndroidLogConfig::operator==(const AndroidLogConfig& other) const {
+bool ObservableEvents_DataSourceInstanceStateChange::operator==(const ObservableEvents_DataSourceInstanceStateChange& other) const {
return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
- && ::protozero::internal::gen_helpers::EqualsField(log_ids_, other.log_ids_)
- && ::protozero::internal::gen_helpers::EqualsField(min_prio_, other.min_prio_)
- && ::protozero::internal::gen_helpers::EqualsField(filter_tags_, other.filter_tags_)
- && ::protozero::internal::gen_helpers::EqualsField(preserve_log_buffer_, other.preserve_log_buffer_);
+ && ::protozero::internal::gen_helpers::EqualsField(producer_name_, other.producer_name_)
+ && ::protozero::internal::gen_helpers::EqualsField(data_source_name_, other.data_source_name_)
+ && ::protozero::internal::gen_helpers::EqualsField(state_, other.state_);
}
-bool AndroidLogConfig::ParseFromArray(const void* raw, size_t size) {
- log_ids_.clear();
- filter_tags_.clear();
+bool ObservableEvents_DataSourceInstanceStateChange::ParseFromArray(const void* raw, size_t size) {
unknown_fields_.clear();
bool packed_error = false;
@@ -21634,19 +21485,14 @@ bool AndroidLogConfig::ParseFromArray(const void* raw, size_t size) {
_has_field_.set(field.id());
}
switch (field.id()) {
- case 1 /* log_ids */:
- log_ids_.emplace_back();
- field.get(&log_ids_.back());
- break;
- case 3 /* min_prio */:
- field.get(&min_prio_);
+ case 1 /* producer_name */:
+ ::protozero::internal::gen_helpers::DeserializeString(field, &producer_name_);
break;
- case 4 /* filter_tags */:
- filter_tags_.emplace_back();
- ::protozero::internal::gen_helpers::DeserializeString(field, &filter_tags_.back());
+ case 2 /* data_source_name */:
+ ::protozero::internal::gen_helpers::DeserializeString(field, &data_source_name_);
break;
- case 5 /* preserve_log_buffer */:
- field.get(&preserve_log_buffer_);
+ case 3 /* state */:
+ field.get(&state_);
break;
default:
field.SerializeAndAppendTo(&unknown_fields_);
@@ -21656,37 +21502,32 @@ bool AndroidLogConfig::ParseFromArray(const void* raw, size_t size) {
return !packed_error && !dec.bytes_left();
}
-std::string AndroidLogConfig::SerializeAsString() const {
+std::string ObservableEvents_DataSourceInstanceStateChange::SerializeAsString() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsString();
}
-std::vector<uint8_t> AndroidLogConfig::SerializeAsArray() const {
+std::vector<uint8_t> ObservableEvents_DataSourceInstanceStateChange::SerializeAsArray() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsArray();
}
-void AndroidLogConfig::Serialize(::protozero::Message* msg) const {
- // Field 1: log_ids
- for (auto& it : log_ids_) {
- ::protozero::internal::gen_helpers::SerializeVarInt(1, it, msg);
- }
-
- // Field 3: min_prio
- if (_has_field_[3]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(3, min_prio_, msg);
+void ObservableEvents_DataSourceInstanceStateChange::Serialize(::protozero::Message* msg) const {
+ // Field 1: producer_name
+ if (_has_field_[1]) {
+ ::protozero::internal::gen_helpers::SerializeString(1, producer_name_, msg);
}
- // Field 4: filter_tags
- for (auto& it : filter_tags_) {
- ::protozero::internal::gen_helpers::SerializeString(4, it, msg);
+ // Field 2: data_source_name
+ if (_has_field_[2]) {
+ ::protozero::internal::gen_helpers::SerializeString(2, data_source_name_, msg);
}
- // Field 5: preserve_log_buffer
- if (_has_field_[5]) {
- ::protozero::internal::gen_helpers::SerializeTinyVarInt(5, preserve_log_buffer_, msg);
+ // Field 3: state
+ if (_has_field_[3]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(3, state_, msg);
}
protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
@@ -21698,7 +21539,7 @@ void AndroidLogConfig::Serialize(::protozero::Message* msg) const {
#if defined(__GNUC__) || defined(__clang__)
#pragma GCC diagnostic pop
#endif
-// gen_amalgamated begin source: gen/protos/perfetto/config/android/android_polled_state_config.gen.cc
+// gen_amalgamated begin source: gen/protos/perfetto/common/perf_events.gen.cc
// gen_amalgamated expanded: #include "perfetto/protozero/gen_field_helpers.h"
// gen_amalgamated expanded: #include "perfetto/protozero/message.h"
// gen_amalgamated expanded: #include "perfetto/protozero/packed_repeated_fields.h"
@@ -21709,25 +21550,30 @@ void AndroidLogConfig::Serialize(::protozero::Message* msg) const {
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wfloat-equal"
#endif
-// gen_amalgamated expanded: #include "protos/perfetto/config/android/android_polled_state_config.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/common/perf_events.gen.h"
namespace perfetto {
namespace protos {
namespace gen {
-AndroidPolledStateConfig::AndroidPolledStateConfig() = default;
-AndroidPolledStateConfig::~AndroidPolledStateConfig() = default;
-AndroidPolledStateConfig::AndroidPolledStateConfig(const AndroidPolledStateConfig&) = default;
-AndroidPolledStateConfig& AndroidPolledStateConfig::operator=(const AndroidPolledStateConfig&) = default;
-AndroidPolledStateConfig::AndroidPolledStateConfig(AndroidPolledStateConfig&&) noexcept = default;
-AndroidPolledStateConfig& AndroidPolledStateConfig::operator=(AndroidPolledStateConfig&&) = default;
+FollowerEvent::FollowerEvent() = default;
+FollowerEvent::~FollowerEvent() = default;
+FollowerEvent::FollowerEvent(const FollowerEvent&) = default;
+FollowerEvent& FollowerEvent::operator=(const FollowerEvent&) = default;
+FollowerEvent::FollowerEvent(FollowerEvent&&) noexcept = default;
+FollowerEvent& FollowerEvent::operator=(FollowerEvent&&) = default;
-bool AndroidPolledStateConfig::operator==(const AndroidPolledStateConfig& other) const {
+bool FollowerEvent::operator==(const FollowerEvent& other) const {
return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
- && ::protozero::internal::gen_helpers::EqualsField(poll_ms_, other.poll_ms_);
+ && ::protozero::internal::gen_helpers::EqualsField(counter_, other.counter_)
+ && ::protozero::internal::gen_helpers::EqualsField(tracepoint_, other.tracepoint_)
+ && ::protozero::internal::gen_helpers::EqualsField(raw_event_, other.raw_event_)
+ && ::protozero::internal::gen_helpers::EqualsField(modifiers_, other.modifiers_)
+ && ::protozero::internal::gen_helpers::EqualsField(name_, other.name_);
}
-bool AndroidPolledStateConfig::ParseFromArray(const void* raw, size_t size) {
+bool FollowerEvent::ParseFromArray(const void* raw, size_t size) {
+ modifiers_.clear();
unknown_fields_.clear();
bool packed_error = false;
@@ -21737,8 +21583,21 @@ bool AndroidPolledStateConfig::ParseFromArray(const void* raw, size_t size) {
_has_field_.set(field.id());
}
switch (field.id()) {
- case 1 /* poll_ms */:
- field.get(&poll_ms_);
+ case 1 /* counter */:
+ field.get(&counter_);
+ break;
+ case 2 /* tracepoint */:
+ (*tracepoint_).ParseFromArray(field.data(), field.size());
+ break;
+ case 3 /* raw_event */:
+ (*raw_event_).ParseFromArray(field.data(), field.size());
+ break;
+ case 5 /* modifiers */:
+ modifiers_.emplace_back();
+ field.get(&modifiers_.back());
+ break;
+ case 4 /* name */:
+ ::protozero::internal::gen_helpers::DeserializeString(field, &name_);
break;
default:
field.SerializeAndAppendTo(&unknown_fields_);
@@ -21748,66 +21607,65 @@ bool AndroidPolledStateConfig::ParseFromArray(const void* raw, size_t size) {
return !packed_error && !dec.bytes_left();
}
-std::string AndroidPolledStateConfig::SerializeAsString() const {
+std::string FollowerEvent::SerializeAsString() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsString();
}
-std::vector<uint8_t> AndroidPolledStateConfig::SerializeAsArray() const {
+std::vector<uint8_t> FollowerEvent::SerializeAsArray() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsArray();
}
-void AndroidPolledStateConfig::Serialize(::protozero::Message* msg) const {
- // Field 1: poll_ms
+void FollowerEvent::Serialize(::protozero::Message* msg) const {
+ // Field 1: counter
if (_has_field_[1]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(1, poll_ms_, msg);
+ ::protozero::internal::gen_helpers::SerializeVarInt(1, counter_, msg);
+ }
+
+ // Field 2: tracepoint
+ if (_has_field_[2]) {
+ (*tracepoint_).Serialize(msg->BeginNestedMessage<::protozero::Message>(2));
+ }
+
+ // Field 3: raw_event
+ if (_has_field_[3]) {
+ (*raw_event_).Serialize(msg->BeginNestedMessage<::protozero::Message>(3));
+ }
+
+ // Field 5: modifiers
+ for (auto& it : modifiers_) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(5, it, msg);
+ }
+
+ // Field 4: name
+ if (_has_field_[4]) {
+ ::protozero::internal::gen_helpers::SerializeString(4, name_, msg);
}
protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
}
-} // namespace perfetto
-} // namespace protos
-} // namespace gen
-#if defined(__GNUC__) || defined(__clang__)
-#pragma GCC diagnostic pop
-#endif
-// gen_amalgamated begin source: gen/protos/perfetto/config/android/android_sdk_sysprop_guard_config.gen.cc
-// gen_amalgamated expanded: #include "perfetto/protozero/gen_field_helpers.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/message.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/packed_repeated_fields.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/proto_decoder.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/scattered_heap_buffer.h"
-// DO NOT EDIT. Autogenerated by Perfetto cppgen_plugin
-#if defined(__GNUC__) || defined(__clang__)
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wfloat-equal"
-#endif
-// gen_amalgamated expanded: #include "protos/perfetto/config/android/android_sdk_sysprop_guard_config.gen.h"
-
-namespace perfetto {
-namespace protos {
-namespace gen {
-AndroidSdkSyspropGuardConfig::AndroidSdkSyspropGuardConfig() = default;
-AndroidSdkSyspropGuardConfig::~AndroidSdkSyspropGuardConfig() = default;
-AndroidSdkSyspropGuardConfig::AndroidSdkSyspropGuardConfig(const AndroidSdkSyspropGuardConfig&) = default;
-AndroidSdkSyspropGuardConfig& AndroidSdkSyspropGuardConfig::operator=(const AndroidSdkSyspropGuardConfig&) = default;
-AndroidSdkSyspropGuardConfig::AndroidSdkSyspropGuardConfig(AndroidSdkSyspropGuardConfig&&) noexcept = default;
-AndroidSdkSyspropGuardConfig& AndroidSdkSyspropGuardConfig::operator=(AndroidSdkSyspropGuardConfig&&) = default;
+PerfEvents_RawEvent::PerfEvents_RawEvent() = default;
+PerfEvents_RawEvent::~PerfEvents_RawEvent() = default;
+PerfEvents_RawEvent::PerfEvents_RawEvent(const PerfEvents_RawEvent&) = default;
+PerfEvents_RawEvent& PerfEvents_RawEvent::operator=(const PerfEvents_RawEvent&) = default;
+PerfEvents_RawEvent::PerfEvents_RawEvent(PerfEvents_RawEvent&&) noexcept = default;
+PerfEvents_RawEvent& PerfEvents_RawEvent::operator=(PerfEvents_RawEvent&&) = default;
-bool AndroidSdkSyspropGuardConfig::operator==(const AndroidSdkSyspropGuardConfig& other) const {
+bool PerfEvents_RawEvent::operator==(const PerfEvents_RawEvent& other) const {
return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
- && ::protozero::internal::gen_helpers::EqualsField(surfaceflinger_skia_track_events_, other.surfaceflinger_skia_track_events_)
- && ::protozero::internal::gen_helpers::EqualsField(hwui_skia_track_events_, other.hwui_skia_track_events_)
- && ::protozero::internal::gen_helpers::EqualsField(hwui_package_name_filter_, other.hwui_package_name_filter_);
+ && ::protozero::internal::gen_helpers::EqualsField(type_, other.type_)
+ && ::protozero::internal::gen_helpers::EqualsField(config_, other.config_)
+ && ::protozero::internal::gen_helpers::EqualsField(config1_, other.config1_)
+ && ::protozero::internal::gen_helpers::EqualsField(config2_, other.config2_)
+ && ::protozero::internal::gen_helpers::EqualsField(pmu_name_, other.pmu_name_);
}
-bool AndroidSdkSyspropGuardConfig::ParseFromArray(const void* raw, size_t size) {
- hwui_package_name_filter_.clear();
+bool PerfEvents_RawEvent::ParseFromArray(const void* raw, size_t size) {
unknown_fields_.clear();
bool packed_error = false;
@@ -21817,15 +21675,20 @@ bool AndroidSdkSyspropGuardConfig::ParseFromArray(const void* raw, size_t size)
_has_field_.set(field.id());
}
switch (field.id()) {
- case 1 /* surfaceflinger_skia_track_events */:
- field.get(&surfaceflinger_skia_track_events_);
+ case 1 /* type */:
+ field.get(&type_);
break;
- case 2 /* hwui_skia_track_events */:
- field.get(&hwui_skia_track_events_);
+ case 2 /* config */:
+ field.get(&config_);
break;
- case 3 /* hwui_package_name_filter */:
- hwui_package_name_filter_.emplace_back();
- ::protozero::internal::gen_helpers::DeserializeString(field, &hwui_package_name_filter_.back());
+ case 3 /* config1 */:
+ field.get(&config1_);
+ break;
+ case 4 /* config2 */:
+ field.get(&config2_);
+ break;
+ case 5 /* pmu_name */:
+ ::protozero::internal::gen_helpers::DeserializeString(field, &pmu_name_);
break;
default:
field.SerializeAndAppendTo(&unknown_fields_);
@@ -21835,75 +21698,62 @@ bool AndroidSdkSyspropGuardConfig::ParseFromArray(const void* raw, size_t size)
return !packed_error && !dec.bytes_left();
}
-std::string AndroidSdkSyspropGuardConfig::SerializeAsString() const {
+std::string PerfEvents_RawEvent::SerializeAsString() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsString();
}
-std::vector<uint8_t> AndroidSdkSyspropGuardConfig::SerializeAsArray() const {
+std::vector<uint8_t> PerfEvents_RawEvent::SerializeAsArray() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsArray();
}
-void AndroidSdkSyspropGuardConfig::Serialize(::protozero::Message* msg) const {
- // Field 1: surfaceflinger_skia_track_events
+void PerfEvents_RawEvent::Serialize(::protozero::Message* msg) const {
+ // Field 1: type
if (_has_field_[1]) {
- ::protozero::internal::gen_helpers::SerializeTinyVarInt(1, surfaceflinger_skia_track_events_, msg);
+ ::protozero::internal::gen_helpers::SerializeVarInt(1, type_, msg);
}
- // Field 2: hwui_skia_track_events
+ // Field 2: config
if (_has_field_[2]) {
- ::protozero::internal::gen_helpers::SerializeTinyVarInt(2, hwui_skia_track_events_, msg);
+ ::protozero::internal::gen_helpers::SerializeVarInt(2, config_, msg);
}
- // Field 3: hwui_package_name_filter
- for (auto& it : hwui_package_name_filter_) {
- ::protozero::internal::gen_helpers::SerializeString(3, it, msg);
+ // Field 3: config1
+ if (_has_field_[3]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(3, config1_, msg);
+ }
+
+ // Field 4: config2
+ if (_has_field_[4]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(4, config2_, msg);
+ }
+
+ // Field 5: pmu_name
+ if (_has_field_[5]) {
+ ::protozero::internal::gen_helpers::SerializeString(5, pmu_name_, msg);
}
protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
}
-} // namespace perfetto
-} // namespace protos
-} // namespace gen
-#if defined(__GNUC__) || defined(__clang__)
-#pragma GCC diagnostic pop
-#endif
-// gen_amalgamated begin source: gen/protos/perfetto/config/android/android_system_property_config.gen.cc
-// gen_amalgamated expanded: #include "perfetto/protozero/gen_field_helpers.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/message.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/packed_repeated_fields.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/proto_decoder.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/scattered_heap_buffer.h"
-// DO NOT EDIT. Autogenerated by Perfetto cppgen_plugin
-#if defined(__GNUC__) || defined(__clang__)
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wfloat-equal"
-#endif
-// gen_amalgamated expanded: #include "protos/perfetto/config/android/android_system_property_config.gen.h"
-
-namespace perfetto {
-namespace protos {
-namespace gen {
-AndroidSystemPropertyConfig::AndroidSystemPropertyConfig() = default;
-AndroidSystemPropertyConfig::~AndroidSystemPropertyConfig() = default;
-AndroidSystemPropertyConfig::AndroidSystemPropertyConfig(const AndroidSystemPropertyConfig&) = default;
-AndroidSystemPropertyConfig& AndroidSystemPropertyConfig::operator=(const AndroidSystemPropertyConfig&) = default;
-AndroidSystemPropertyConfig::AndroidSystemPropertyConfig(AndroidSystemPropertyConfig&&) noexcept = default;
-AndroidSystemPropertyConfig& AndroidSystemPropertyConfig::operator=(AndroidSystemPropertyConfig&&) = default;
+PerfEvents_Tracepoint::PerfEvents_Tracepoint() = default;
+PerfEvents_Tracepoint::~PerfEvents_Tracepoint() = default;
+PerfEvents_Tracepoint::PerfEvents_Tracepoint(const PerfEvents_Tracepoint&) = default;
+PerfEvents_Tracepoint& PerfEvents_Tracepoint::operator=(const PerfEvents_Tracepoint&) = default;
+PerfEvents_Tracepoint::PerfEvents_Tracepoint(PerfEvents_Tracepoint&&) noexcept = default;
+PerfEvents_Tracepoint& PerfEvents_Tracepoint::operator=(PerfEvents_Tracepoint&&) = default;
-bool AndroidSystemPropertyConfig::operator==(const AndroidSystemPropertyConfig& other) const {
+bool PerfEvents_Tracepoint::operator==(const PerfEvents_Tracepoint& other) const {
return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
- && ::protozero::internal::gen_helpers::EqualsField(poll_ms_, other.poll_ms_)
- && ::protozero::internal::gen_helpers::EqualsField(property_name_, other.property_name_);
+ && ::protozero::internal::gen_helpers::EqualsField(name_, other.name_)
+ && ::protozero::internal::gen_helpers::EqualsField(filter_, other.filter_);
}
-bool AndroidSystemPropertyConfig::ParseFromArray(const void* raw, size_t size) {
- property_name_.clear();
+bool PerfEvents_Tracepoint::ParseFromArray(const void* raw, size_t size) {
unknown_fields_.clear();
bool packed_error = false;
@@ -21913,12 +21763,11 @@ bool AndroidSystemPropertyConfig::ParseFromArray(const void* raw, size_t size) {
_has_field_.set(field.id());
}
switch (field.id()) {
- case 1 /* poll_ms */:
- field.get(&poll_ms_);
+ case 1 /* name */:
+ ::protozero::internal::gen_helpers::DeserializeString(field, &name_);
break;
- case 2 /* property_name */:
- property_name_.emplace_back();
- ::protozero::internal::gen_helpers::DeserializeString(field, &property_name_.back());
+ case 2 /* filter */:
+ ::protozero::internal::gen_helpers::DeserializeString(field, &filter_);
break;
default:
field.SerializeAndAppendTo(&unknown_fields_);
@@ -21928,70 +21777,45 @@ bool AndroidSystemPropertyConfig::ParseFromArray(const void* raw, size_t size) {
return !packed_error && !dec.bytes_left();
}
-std::string AndroidSystemPropertyConfig::SerializeAsString() const {
+std::string PerfEvents_Tracepoint::SerializeAsString() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsString();
}
-std::vector<uint8_t> AndroidSystemPropertyConfig::SerializeAsArray() const {
+std::vector<uint8_t> PerfEvents_Tracepoint::SerializeAsArray() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsArray();
}
-void AndroidSystemPropertyConfig::Serialize(::protozero::Message* msg) const {
- // Field 1: poll_ms
+void PerfEvents_Tracepoint::Serialize(::protozero::Message* msg) const {
+ // Field 1: name
if (_has_field_[1]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(1, poll_ms_, msg);
+ ::protozero::internal::gen_helpers::SerializeString(1, name_, msg);
}
- // Field 2: property_name
- for (auto& it : property_name_) {
- ::protozero::internal::gen_helpers::SerializeString(2, it, msg);
+ // Field 2: filter
+ if (_has_field_[2]) {
+ ::protozero::internal::gen_helpers::SerializeString(2, filter_, msg);
}
protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
}
-} // namespace perfetto
-} // namespace protos
-} // namespace gen
-#if defined(__GNUC__) || defined(__clang__)
-#pragma GCC diagnostic pop
-#endif
-// gen_amalgamated begin source: gen/protos/perfetto/config/android/app_wakelock_config.gen.cc
-// gen_amalgamated expanded: #include "perfetto/protozero/gen_field_helpers.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/message.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/packed_repeated_fields.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/proto_decoder.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/scattered_heap_buffer.h"
-// DO NOT EDIT. Autogenerated by Perfetto cppgen_plugin
-#if defined(__GNUC__) || defined(__clang__)
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wfloat-equal"
-#endif
-// gen_amalgamated expanded: #include "protos/perfetto/config/android/app_wakelock_config.gen.h"
-
-namespace perfetto {
-namespace protos {
-namespace gen {
-AppWakelocksConfig::AppWakelocksConfig() = default;
-AppWakelocksConfig::~AppWakelocksConfig() = default;
-AppWakelocksConfig::AppWakelocksConfig(const AppWakelocksConfig&) = default;
-AppWakelocksConfig& AppWakelocksConfig::operator=(const AppWakelocksConfig&) = default;
-AppWakelocksConfig::AppWakelocksConfig(AppWakelocksConfig&&) noexcept = default;
-AppWakelocksConfig& AppWakelocksConfig::operator=(AppWakelocksConfig&&) = default;
+PerfEvents::PerfEvents() = default;
+PerfEvents::~PerfEvents() = default;
+PerfEvents::PerfEvents(const PerfEvents&) = default;
+PerfEvents& PerfEvents::operator=(const PerfEvents&) = default;
+PerfEvents::PerfEvents(PerfEvents&&) noexcept = default;
+PerfEvents& PerfEvents::operator=(PerfEvents&&) = default;
-bool AppWakelocksConfig::operator==(const AppWakelocksConfig& other) const {
- return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
- && ::protozero::internal::gen_helpers::EqualsField(write_delay_ms_, other.write_delay_ms_)
- && ::protozero::internal::gen_helpers::EqualsField(filter_duration_below_ms_, other.filter_duration_below_ms_)
- && ::protozero::internal::gen_helpers::EqualsField(drop_owner_pid_, other.drop_owner_pid_);
+bool PerfEvents::operator==(const PerfEvents& other) const {
+ return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_);
}
-bool AppWakelocksConfig::ParseFromArray(const void* raw, size_t size) {
+bool PerfEvents::ParseFromArray(const void* raw, size_t size) {
unknown_fields_.clear();
bool packed_error = false;
@@ -22001,15 +21825,6 @@ bool AppWakelocksConfig::ParseFromArray(const void* raw, size_t size) {
_has_field_.set(field.id());
}
switch (field.id()) {
- case 1 /* write_delay_ms */:
- field.get(&write_delay_ms_);
- break;
- case 2 /* filter_duration_below_ms */:
- field.get(&filter_duration_below_ms_);
- break;
- case 3 /* drop_owner_pid */:
- field.get(&drop_owner_pid_);
- break;
default:
field.SerializeAndAppendTo(&unknown_fields_);
break;
@@ -22018,73 +21833,45 @@ bool AppWakelocksConfig::ParseFromArray(const void* raw, size_t size) {
return !packed_error && !dec.bytes_left();
}
-std::string AppWakelocksConfig::SerializeAsString() const {
+std::string PerfEvents::SerializeAsString() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsString();
}
-std::vector<uint8_t> AppWakelocksConfig::SerializeAsArray() const {
+std::vector<uint8_t> PerfEvents::SerializeAsArray() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsArray();
}
-void AppWakelocksConfig::Serialize(::protozero::Message* msg) const {
- // Field 1: write_delay_ms
- if (_has_field_[1]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(1, write_delay_ms_, msg);
- }
-
- // Field 2: filter_duration_below_ms
- if (_has_field_[2]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(2, filter_duration_below_ms_, msg);
- }
-
- // Field 3: drop_owner_pid
- if (_has_field_[3]) {
- ::protozero::internal::gen_helpers::SerializeTinyVarInt(3, drop_owner_pid_, msg);
- }
-
+void PerfEvents::Serialize(::protozero::Message* msg) const {
protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
}
-} // namespace perfetto
-} // namespace protos
-} // namespace gen
-#if defined(__GNUC__) || defined(__clang__)
-#pragma GCC diagnostic pop
-#endif
-// gen_amalgamated begin source: gen/protos/perfetto/config/android/cpu_per_uid_config.gen.cc
-// gen_amalgamated expanded: #include "perfetto/protozero/gen_field_helpers.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/message.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/packed_repeated_fields.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/proto_decoder.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/scattered_heap_buffer.h"
-// DO NOT EDIT. Autogenerated by Perfetto cppgen_plugin
-#if defined(__GNUC__) || defined(__clang__)
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wfloat-equal"
-#endif
-// gen_amalgamated expanded: #include "protos/perfetto/config/android/cpu_per_uid_config.gen.h"
-
-namespace perfetto {
-namespace protos {
-namespace gen {
-CpuPerUidConfig::CpuPerUidConfig() = default;
-CpuPerUidConfig::~CpuPerUidConfig() = default;
-CpuPerUidConfig::CpuPerUidConfig(const CpuPerUidConfig&) = default;
-CpuPerUidConfig& CpuPerUidConfig::operator=(const CpuPerUidConfig&) = default;
-CpuPerUidConfig::CpuPerUidConfig(CpuPerUidConfig&&) noexcept = default;
-CpuPerUidConfig& CpuPerUidConfig::operator=(CpuPerUidConfig&&) = default;
+PerfEvents_Timebase::PerfEvents_Timebase() = default;
+PerfEvents_Timebase::~PerfEvents_Timebase() = default;
+PerfEvents_Timebase::PerfEvents_Timebase(const PerfEvents_Timebase&) = default;
+PerfEvents_Timebase& PerfEvents_Timebase::operator=(const PerfEvents_Timebase&) = default;
+PerfEvents_Timebase::PerfEvents_Timebase(PerfEvents_Timebase&&) noexcept = default;
+PerfEvents_Timebase& PerfEvents_Timebase::operator=(PerfEvents_Timebase&&) = default;
-bool CpuPerUidConfig::operator==(const CpuPerUidConfig& other) const {
+bool PerfEvents_Timebase::operator==(const PerfEvents_Timebase& other) const {
return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
- && ::protozero::internal::gen_helpers::EqualsField(poll_ms_, other.poll_ms_);
+ && ::protozero::internal::gen_helpers::EqualsField(frequency_, other.frequency_)
+ && ::protozero::internal::gen_helpers::EqualsField(period_, other.period_)
+ && ::protozero::internal::gen_helpers::EqualsField(poll_period_ms_, other.poll_period_ms_)
+ && ::protozero::internal::gen_helpers::EqualsField(counter_, other.counter_)
+ && ::protozero::internal::gen_helpers::EqualsField(tracepoint_, other.tracepoint_)
+ && ::protozero::internal::gen_helpers::EqualsField(raw_event_, other.raw_event_)
+ && ::protozero::internal::gen_helpers::EqualsField(modifiers_, other.modifiers_)
+ && ::protozero::internal::gen_helpers::EqualsField(timestamp_clock_, other.timestamp_clock_)
+ && ::protozero::internal::gen_helpers::EqualsField(name_, other.name_);
}
-bool CpuPerUidConfig::ParseFromArray(const void* raw, size_t size) {
+bool PerfEvents_Timebase::ParseFromArray(const void* raw, size_t size) {
+ modifiers_.clear();
unknown_fields_.clear();
bool packed_error = false;
@@ -22094,8 +21881,33 @@ bool CpuPerUidConfig::ParseFromArray(const void* raw, size_t size) {
_has_field_.set(field.id());
}
switch (field.id()) {
- case 1 /* poll_ms */:
- field.get(&poll_ms_);
+ case 2 /* frequency */:
+ field.get(&frequency_);
+ break;
+ case 1 /* period */:
+ field.get(&period_);
+ break;
+ case 6 /* poll_period_ms */:
+ field.get(&poll_period_ms_);
+ break;
+ case 4 /* counter */:
+ field.get(&counter_);
+ break;
+ case 3 /* tracepoint */:
+ (*tracepoint_).ParseFromArray(field.data(), field.size());
+ break;
+ case 5 /* raw_event */:
+ (*raw_event_).ParseFromArray(field.data(), field.size());
+ break;
+ case 12 /* modifiers */:
+ modifiers_.emplace_back();
+ field.get(&modifiers_.back());
+ break;
+ case 11 /* timestamp_clock */:
+ field.get(×tamp_clock_);
+ break;
+ case 10 /* name */:
+ ::protozero::internal::gen_helpers::DeserializeString(field, &name_);
break;
default:
field.SerializeAndAppendTo(&unknown_fields_);
@@ -22105,22 +21917,62 @@ bool CpuPerUidConfig::ParseFromArray(const void* raw, size_t size) {
return !packed_error && !dec.bytes_left();
}
-std::string CpuPerUidConfig::SerializeAsString() const {
+std::string PerfEvents_Timebase::SerializeAsString() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsString();
}
-std::vector<uint8_t> CpuPerUidConfig::SerializeAsArray() const {
+std::vector<uint8_t> PerfEvents_Timebase::SerializeAsArray() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsArray();
}
-void CpuPerUidConfig::Serialize(::protozero::Message* msg) const {
- // Field 1: poll_ms
+void PerfEvents_Timebase::Serialize(::protozero::Message* msg) const {
+ // Field 2: frequency
+ if (_has_field_[2]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(2, frequency_, msg);
+ }
+
+ // Field 1: period
if (_has_field_[1]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(1, poll_ms_, msg);
+ ::protozero::internal::gen_helpers::SerializeVarInt(1, period_, msg);
+ }
+
+ // Field 6: poll_period_ms
+ if (_has_field_[6]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(6, poll_period_ms_, msg);
+ }
+
+ // Field 4: counter
+ if (_has_field_[4]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(4, counter_, msg);
+ }
+
+ // Field 3: tracepoint
+ if (_has_field_[3]) {
+ (*tracepoint_).Serialize(msg->BeginNestedMessage<::protozero::Message>(3));
+ }
+
+ // Field 5: raw_event
+ if (_has_field_[5]) {
+ (*raw_event_).Serialize(msg->BeginNestedMessage<::protozero::Message>(5));
+ }
+
+ // Field 12: modifiers
+ for (auto& it : modifiers_) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(12, it, msg);
+ }
+
+ // Field 11: timestamp_clock
+ if (_has_field_[11]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(11, timestamp_clock_, msg);
+ }
+
+ // Field 10: name
+ if (_has_field_[10]) {
+ ::protozero::internal::gen_helpers::SerializeString(10, name_, msg);
}
protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
@@ -22132,7 +21984,7 @@ void CpuPerUidConfig::Serialize(::protozero::Message* msg) const {
#if defined(__GNUC__) || defined(__clang__)
#pragma GCC diagnostic pop
#endif
-// gen_amalgamated begin source: gen/protos/perfetto/config/android/display_video_config.gen.cc
+// gen_amalgamated begin source: gen/protos/perfetto/common/sys_stats_counters.gen.cc
// gen_amalgamated expanded: #include "perfetto/protozero/gen_field_helpers.h"
// gen_amalgamated expanded: #include "perfetto/protozero/message.h"
// gen_amalgamated expanded: #include "perfetto/protozero/packed_repeated_fields.h"
@@ -22143,109 +21995,18 @@ void CpuPerUidConfig::Serialize(::protozero::Message* msg) const {
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wfloat-equal"
#endif
-// gen_amalgamated expanded: #include "protos/perfetto/config/android/display_video_config.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/common/sys_stats_counters.gen.h"
namespace perfetto {
namespace protos {
namespace gen {
-
-DisplayVideoConfig::DisplayVideoConfig() = default;
-DisplayVideoConfig::~DisplayVideoConfig() = default;
-DisplayVideoConfig::DisplayVideoConfig(const DisplayVideoConfig&) = default;
-DisplayVideoConfig& DisplayVideoConfig::operator=(const DisplayVideoConfig&) = default;
-DisplayVideoConfig::DisplayVideoConfig(DisplayVideoConfig&&) noexcept = default;
-DisplayVideoConfig& DisplayVideoConfig::operator=(DisplayVideoConfig&&) = default;
-
-bool DisplayVideoConfig::operator==(const DisplayVideoConfig& other) const {
- return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
- && ::protozero::internal::gen_helpers::EqualsField(scale_, other.scale_)
- && ::protozero::internal::gen_helpers::EqualsField(format_, other.format_)
- && ::protozero::internal::gen_helpers::EqualsField(key_frame_interval_secs_, other.key_frame_interval_secs_)
- && ::protozero::internal::gen_helpers::EqualsField(max_stream_size_bytes_, other.max_stream_size_bytes_)
- && ::protozero::internal::gen_helpers::EqualsField(bitrate_bps_, other.bitrate_bps_);
-}
-
-bool DisplayVideoConfig::ParseFromArray(const void* raw, size_t size) {
- unknown_fields_.clear();
- bool packed_error = false;
-
- ::protozero::ProtoDecoder dec(raw, size);
- for (auto field = dec.ReadField(); field.valid(); field = dec.ReadField()) {
- if (field.id() < _has_field_.size()) {
- _has_field_.set(field.id());
- }
- switch (field.id()) {
- case 1 /* scale */:
- field.get(&scale_);
- break;
- case 2 /* format */:
- field.get(&format_);
- break;
- case 3 /* key_frame_interval_secs */:
- field.get(&key_frame_interval_secs_);
- break;
- case 4 /* max_stream_size_bytes */:
- field.get(&max_stream_size_bytes_);
- break;
- case 5 /* bitrate_bps */:
- field.get(&bitrate_bps_);
- break;
- default:
- field.SerializeAndAppendTo(&unknown_fields_);
- break;
- }
- }
- return !packed_error && !dec.bytes_left();
-}
-
-std::string DisplayVideoConfig::SerializeAsString() const {
- ::protozero::internal::gen_helpers::MessageSerializer msg;
- Serialize(msg.get());
- return msg.SerializeAsString();
-}
-
-std::vector<uint8_t> DisplayVideoConfig::SerializeAsArray() const {
- ::protozero::internal::gen_helpers::MessageSerializer msg;
- Serialize(msg.get());
- return msg.SerializeAsArray();
-}
-
-void DisplayVideoConfig::Serialize(::protozero::Message* msg) const {
- // Field 1: scale
- if (_has_field_[1]) {
- ::protozero::internal::gen_helpers::SerializeFixed(1, scale_, msg);
- }
-
- // Field 2: format
- if (_has_field_[2]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(2, format_, msg);
- }
-
- // Field 3: key_frame_interval_secs
- if (_has_field_[3]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(3, key_frame_interval_secs_, msg);
- }
-
- // Field 4: max_stream_size_bytes
- if (_has_field_[4]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(4, max_stream_size_bytes_, msg);
- }
-
- // Field 5: bitrate_bps
- if (_has_field_[5]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(5, bitrate_bps_, msg);
- }
-
- protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
-}
-
} // namespace perfetto
} // namespace protos
} // namespace gen
#if defined(__GNUC__) || defined(__clang__)
#pragma GCC diagnostic pop
#endif
-// gen_amalgamated begin source: gen/protos/perfetto/config/android/inputmethod_config.gen.cc
+// gen_amalgamated begin source: gen/protos/perfetto/common/system_info.gen.cc
// gen_amalgamated expanded: #include "perfetto/protozero/gen_field_helpers.h"
// gen_amalgamated expanded: #include "perfetto/protozero/message.h"
// gen_amalgamated expanded: #include "perfetto/protozero/packed_repeated_fields.h"
@@ -22256,27 +22017,43 @@ void DisplayVideoConfig::Serialize(::protozero::Message* msg) const {
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wfloat-equal"
#endif
-// gen_amalgamated expanded: #include "protos/perfetto/config/android/inputmethod_config.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/common/system_info.gen.h"
namespace perfetto {
namespace protos {
namespace gen {
-InputMethodConfig::InputMethodConfig() = default;
-InputMethodConfig::~InputMethodConfig() = default;
-InputMethodConfig::InputMethodConfig(const InputMethodConfig&) = default;
-InputMethodConfig& InputMethodConfig::operator=(const InputMethodConfig&) = default;
-InputMethodConfig::InputMethodConfig(InputMethodConfig&&) noexcept = default;
-InputMethodConfig& InputMethodConfig::operator=(InputMethodConfig&&) = default;
+SystemInfo::SystemInfo() = default;
+SystemInfo::~SystemInfo() = default;
+SystemInfo::SystemInfo(const SystemInfo&) = default;
+SystemInfo& SystemInfo::operator=(const SystemInfo&) = default;
+SystemInfo::SystemInfo(SystemInfo&&) noexcept = default;
+SystemInfo& SystemInfo::operator=(SystemInfo&&) = default;
-bool InputMethodConfig::operator==(const InputMethodConfig& other) const {
+bool SystemInfo::operator==(const SystemInfo& other) const {
return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
- && ::protozero::internal::gen_helpers::EqualsField(client_, other.client_)
- && ::protozero::internal::gen_helpers::EqualsField(service_, other.service_)
- && ::protozero::internal::gen_helpers::EqualsField(manager_service_, other.manager_service_);
+ && ::protozero::internal::gen_helpers::EqualsField(utsname_, other.utsname_)
+ && ::protozero::internal::gen_helpers::EqualsField(android_build_fingerprint_, other.android_build_fingerprint_)
+ && ::protozero::internal::gen_helpers::EqualsField(android_device_manufacturer_, other.android_device_manufacturer_)
+ && ::protozero::internal::gen_helpers::EqualsField(android_soc_model_, other.android_soc_model_)
+ && ::protozero::internal::gen_helpers::EqualsField(device_tree_compatibles_, other.device_tree_compatibles_)
+ && ::protozero::internal::gen_helpers::EqualsField(android_guest_soc_model_, other.android_guest_soc_model_)
+ && ::protozero::internal::gen_helpers::EqualsField(android_hardware_revision_, other.android_hardware_revision_)
+ && ::protozero::internal::gen_helpers::EqualsField(android_storage_model_, other.android_storage_model_)
+ && ::protozero::internal::gen_helpers::EqualsField(android_ram_model_, other.android_ram_model_)
+ && ::protozero::internal::gen_helpers::EqualsField(android_serial_console_, other.android_serial_console_)
+ && ::protozero::internal::gen_helpers::EqualsField(tracing_service_version_, other.tracing_service_version_)
+ && ::protozero::internal::gen_helpers::EqualsField(android_sdk_version_, other.android_sdk_version_)
+ && ::protozero::internal::gen_helpers::EqualsField(page_size_, other.page_size_)
+ && ::protozero::internal::gen_helpers::EqualsField(num_cpus_, other.num_cpus_)
+ && ::protozero::internal::gen_helpers::EqualsField(timezone_off_mins_, other.timezone_off_mins_)
+ && ::protozero::internal::gen_helpers::EqualsField(hz_, other.hz_)
+ && ::protozero::internal::gen_helpers::EqualsField(system_ram_bytes_, other.system_ram_bytes_)
+ && ::protozero::internal::gen_helpers::EqualsField(machine_name_, other.machine_name_);
}
-bool InputMethodConfig::ParseFromArray(const void* raw, size_t size) {
+bool SystemInfo::ParseFromArray(const void* raw, size_t size) {
+ device_tree_compatibles_.clear();
unknown_fields_.clear();
bool packed_error = false;
@@ -22286,14 +22063,60 @@ bool InputMethodConfig::ParseFromArray(const void* raw, size_t size) {
_has_field_.set(field.id());
}
switch (field.id()) {
- case 1 /* client */:
- field.get(&client_);
+ case 1 /* utsname */:
+ (*utsname_).ParseFromArray(field.data(), field.size());
break;
- case 2 /* service */:
- field.get(&service_);
+ case 2 /* android_build_fingerprint */:
+ ::protozero::internal::gen_helpers::DeserializeString(field, &android_build_fingerprint_);
break;
- case 3 /* manager_service */:
- field.get(&manager_service_);
+ case 14 /* android_device_manufacturer */:
+ ::protozero::internal::gen_helpers::DeserializeString(field, &android_device_manufacturer_);
+ break;
+ case 9 /* android_soc_model */:
+ ::protozero::internal::gen_helpers::DeserializeString(field, &android_soc_model_);
+ break;
+ case 18 /* device_tree_compatibles */:
+ device_tree_compatibles_.emplace_back();
+ ::protozero::internal::gen_helpers::DeserializeString(field, &device_tree_compatibles_.back());
+ break;
+ case 13 /* android_guest_soc_model */:
+ ::protozero::internal::gen_helpers::DeserializeString(field, &android_guest_soc_model_);
+ break;
+ case 10 /* android_hardware_revision */:
+ ::protozero::internal::gen_helpers::DeserializeString(field, &android_hardware_revision_);
+ break;
+ case 11 /* android_storage_model */:
+ ::protozero::internal::gen_helpers::DeserializeString(field, &android_storage_model_);
+ break;
+ case 12 /* android_ram_model */:
+ ::protozero::internal::gen_helpers::DeserializeString(field, &android_ram_model_);
+ break;
+ case 15 /* android_serial_console */:
+ ::protozero::internal::gen_helpers::DeserializeString(field, &android_serial_console_);
+ break;
+ case 4 /* tracing_service_version */:
+ ::protozero::internal::gen_helpers::DeserializeString(field, &tracing_service_version_);
+ break;
+ case 5 /* android_sdk_version */:
+ field.get(&android_sdk_version_);
+ break;
+ case 6 /* page_size */:
+ field.get(&page_size_);
+ break;
+ case 8 /* num_cpus */:
+ field.get(&num_cpus_);
+ break;
+ case 7 /* timezone_off_mins */:
+ field.get(&timezone_off_mins_);
+ break;
+ case 3 /* hz */:
+ field.get(&hz_);
+ break;
+ case 16 /* system_ram_bytes */:
+ field.get(&system_ram_bytes_);
+ break;
+ case 17 /* machine_name */:
+ ::protozero::internal::gen_helpers::DeserializeString(field, &machine_name_);
break;
default:
field.SerializeAndAppendTo(&unknown_fields_);
@@ -22303,155 +22126,129 @@ bool InputMethodConfig::ParseFromArray(const void* raw, size_t size) {
return !packed_error && !dec.bytes_left();
}
-std::string InputMethodConfig::SerializeAsString() const {
+std::string SystemInfo::SerializeAsString() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsString();
}
-std::vector<uint8_t> InputMethodConfig::SerializeAsArray() const {
+std::vector<uint8_t> SystemInfo::SerializeAsArray() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsArray();
}
-void InputMethodConfig::Serialize(::protozero::Message* msg) const {
- // Field 1: client
+void SystemInfo::Serialize(::protozero::Message* msg) const {
+ // Field 1: utsname
if (_has_field_[1]) {
- ::protozero::internal::gen_helpers::SerializeTinyVarInt(1, client_, msg);
+ (*utsname_).Serialize(msg->BeginNestedMessage<::protozero::Message>(1));
}
- // Field 2: service
+ // Field 2: android_build_fingerprint
if (_has_field_[2]) {
- ::protozero::internal::gen_helpers::SerializeTinyVarInt(2, service_, msg);
+ ::protozero::internal::gen_helpers::SerializeString(2, android_build_fingerprint_, msg);
}
- // Field 3: manager_service
- if (_has_field_[3]) {
- ::protozero::internal::gen_helpers::SerializeTinyVarInt(3, manager_service_, msg);
+ // Field 14: android_device_manufacturer
+ if (_has_field_[14]) {
+ ::protozero::internal::gen_helpers::SerializeString(14, android_device_manufacturer_, msg);
}
- protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
-}
+ // Field 9: android_soc_model
+ if (_has_field_[9]) {
+ ::protozero::internal::gen_helpers::SerializeString(9, android_soc_model_, msg);
+ }
-} // namespace perfetto
-} // namespace protos
-} // namespace gen
-#if defined(__GNUC__) || defined(__clang__)
-#pragma GCC diagnostic pop
-#endif
-// gen_amalgamated begin source: gen/protos/perfetto/config/android/kernel_wakelocks_config.gen.cc
-// gen_amalgamated expanded: #include "perfetto/protozero/gen_field_helpers.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/message.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/packed_repeated_fields.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/proto_decoder.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/scattered_heap_buffer.h"
-// DO NOT EDIT. Autogenerated by Perfetto cppgen_plugin
-#if defined(__GNUC__) || defined(__clang__)
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wfloat-equal"
-#endif
-// gen_amalgamated expanded: #include "protos/perfetto/config/android/kernel_wakelocks_config.gen.h"
+ // Field 18: device_tree_compatibles
+ for (auto& it : device_tree_compatibles_) {
+ ::protozero::internal::gen_helpers::SerializeString(18, it, msg);
+ }
-namespace perfetto {
-namespace protos {
-namespace gen {
+ // Field 13: android_guest_soc_model
+ if (_has_field_[13]) {
+ ::protozero::internal::gen_helpers::SerializeString(13, android_guest_soc_model_, msg);
+ }
-KernelWakelocksConfig::KernelWakelocksConfig() = default;
-KernelWakelocksConfig::~KernelWakelocksConfig() = default;
-KernelWakelocksConfig::KernelWakelocksConfig(const KernelWakelocksConfig&) = default;
-KernelWakelocksConfig& KernelWakelocksConfig::operator=(const KernelWakelocksConfig&) = default;
-KernelWakelocksConfig::KernelWakelocksConfig(KernelWakelocksConfig&&) noexcept = default;
-KernelWakelocksConfig& KernelWakelocksConfig::operator=(KernelWakelocksConfig&&) = default;
+ // Field 10: android_hardware_revision
+ if (_has_field_[10]) {
+ ::protozero::internal::gen_helpers::SerializeString(10, android_hardware_revision_, msg);
+ }
-bool KernelWakelocksConfig::operator==(const KernelWakelocksConfig& other) const {
- return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
- && ::protozero::internal::gen_helpers::EqualsField(poll_ms_, other.poll_ms_);
-}
+ // Field 11: android_storage_model
+ if (_has_field_[11]) {
+ ::protozero::internal::gen_helpers::SerializeString(11, android_storage_model_, msg);
+ }
-bool KernelWakelocksConfig::ParseFromArray(const void* raw, size_t size) {
- unknown_fields_.clear();
- bool packed_error = false;
+ // Field 12: android_ram_model
+ if (_has_field_[12]) {
+ ::protozero::internal::gen_helpers::SerializeString(12, android_ram_model_, msg);
+ }
- ::protozero::ProtoDecoder dec(raw, size);
- for (auto field = dec.ReadField(); field.valid(); field = dec.ReadField()) {
- if (field.id() < _has_field_.size()) {
- _has_field_.set(field.id());
- }
- switch (field.id()) {
- case 1 /* poll_ms */:
- field.get(&poll_ms_);
- break;
- default:
- field.SerializeAndAppendTo(&unknown_fields_);
- break;
- }
+ // Field 15: android_serial_console
+ if (_has_field_[15]) {
+ ::protozero::internal::gen_helpers::SerializeString(15, android_serial_console_, msg);
}
- return !packed_error && !dec.bytes_left();
-}
-std::string KernelWakelocksConfig::SerializeAsString() const {
- ::protozero::internal::gen_helpers::MessageSerializer msg;
- Serialize(msg.get());
- return msg.SerializeAsString();
-}
+ // Field 4: tracing_service_version
+ if (_has_field_[4]) {
+ ::protozero::internal::gen_helpers::SerializeString(4, tracing_service_version_, msg);
+ }
-std::vector<uint8_t> KernelWakelocksConfig::SerializeAsArray() const {
- ::protozero::internal::gen_helpers::MessageSerializer msg;
- Serialize(msg.get());
- return msg.SerializeAsArray();
-}
+ // Field 5: android_sdk_version
+ if (_has_field_[5]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(5, android_sdk_version_, msg);
+ }
-void KernelWakelocksConfig::Serialize(::protozero::Message* msg) const {
- // Field 1: poll_ms
- if (_has_field_[1]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(1, poll_ms_, msg);
+ // Field 6: page_size
+ if (_has_field_[6]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(6, page_size_, msg);
+ }
+
+ // Field 8: num_cpus
+ if (_has_field_[8]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(8, num_cpus_, msg);
+ }
+
+ // Field 7: timezone_off_mins
+ if (_has_field_[7]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(7, timezone_off_mins_, msg);
+ }
+
+ // Field 3: hz
+ if (_has_field_[3]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(3, hz_, msg);
+ }
+
+ // Field 16: system_ram_bytes
+ if (_has_field_[16]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(16, system_ram_bytes_, msg);
+ }
+
+ // Field 17: machine_name
+ if (_has_field_[17]) {
+ ::protozero::internal::gen_helpers::SerializeString(17, machine_name_, msg);
}
protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
}
-} // namespace perfetto
-} // namespace protos
-} // namespace gen
-#if defined(__GNUC__) || defined(__clang__)
-#pragma GCC diagnostic pop
-#endif
-// gen_amalgamated begin source: gen/protos/perfetto/config/android/network_trace_config.gen.cc
-// gen_amalgamated expanded: #include "perfetto/protozero/gen_field_helpers.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/message.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/packed_repeated_fields.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/proto_decoder.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/scattered_heap_buffer.h"
-// DO NOT EDIT. Autogenerated by Perfetto cppgen_plugin
-#if defined(__GNUC__) || defined(__clang__)
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wfloat-equal"
-#endif
-// gen_amalgamated expanded: #include "protos/perfetto/config/android/network_trace_config.gen.h"
-
-namespace perfetto {
-namespace protos {
-namespace gen {
-NetworkPacketTraceConfig::NetworkPacketTraceConfig() = default;
-NetworkPacketTraceConfig::~NetworkPacketTraceConfig() = default;
-NetworkPacketTraceConfig::NetworkPacketTraceConfig(const NetworkPacketTraceConfig&) = default;
-NetworkPacketTraceConfig& NetworkPacketTraceConfig::operator=(const NetworkPacketTraceConfig&) = default;
-NetworkPacketTraceConfig::NetworkPacketTraceConfig(NetworkPacketTraceConfig&&) noexcept = default;
-NetworkPacketTraceConfig& NetworkPacketTraceConfig::operator=(NetworkPacketTraceConfig&&) = default;
+Utsname::Utsname() = default;
+Utsname::~Utsname() = default;
+Utsname::Utsname(const Utsname&) = default;
+Utsname& Utsname::operator=(const Utsname&) = default;
+Utsname::Utsname(Utsname&&) noexcept = default;
+Utsname& Utsname::operator=(Utsname&&) = default;
-bool NetworkPacketTraceConfig::operator==(const NetworkPacketTraceConfig& other) const {
+bool Utsname::operator==(const Utsname& other) const {
return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
- && ::protozero::internal::gen_helpers::EqualsField(poll_ms_, other.poll_ms_)
- && ::protozero::internal::gen_helpers::EqualsField(aggregation_threshold_, other.aggregation_threshold_)
- && ::protozero::internal::gen_helpers::EqualsField(intern_limit_, other.intern_limit_)
- && ::protozero::internal::gen_helpers::EqualsField(drop_local_port_, other.drop_local_port_)
- && ::protozero::internal::gen_helpers::EqualsField(drop_remote_port_, other.drop_remote_port_)
- && ::protozero::internal::gen_helpers::EqualsField(drop_tcp_flags_, other.drop_tcp_flags_);
+ && ::protozero::internal::gen_helpers::EqualsField(sysname_, other.sysname_)
+ && ::protozero::internal::gen_helpers::EqualsField(version_, other.version_)
+ && ::protozero::internal::gen_helpers::EqualsField(release_, other.release_)
+ && ::protozero::internal::gen_helpers::EqualsField(machine_, other.machine_);
}
-bool NetworkPacketTraceConfig::ParseFromArray(const void* raw, size_t size) {
+bool Utsname::ParseFromArray(const void* raw, size_t size) {
unknown_fields_.clear();
bool packed_error = false;
@@ -22461,23 +22258,17 @@ bool NetworkPacketTraceConfig::ParseFromArray(const void* raw, size_t size) {
_has_field_.set(field.id());
}
switch (field.id()) {
- case 1 /* poll_ms */:
- field.get(&poll_ms_);
- break;
- case 2 /* aggregation_threshold */:
- field.get(&aggregation_threshold_);
- break;
- case 3 /* intern_limit */:
- field.get(&intern_limit_);
+ case 1 /* sysname */:
+ ::protozero::internal::gen_helpers::DeserializeString(field, &sysname_);
break;
- case 4 /* drop_local_port */:
- field.get(&drop_local_port_);
+ case 2 /* version */:
+ ::protozero::internal::gen_helpers::DeserializeString(field, &version_);
break;
- case 5 /* drop_remote_port */:
- field.get(&drop_remote_port_);
+ case 3 /* release */:
+ ::protozero::internal::gen_helpers::DeserializeString(field, &release_);
break;
- case 6 /* drop_tcp_flags */:
- field.get(&drop_tcp_flags_);
+ case 4 /* machine */:
+ ::protozero::internal::gen_helpers::DeserializeString(field, &machine_);
break;
default:
field.SerializeAndAppendTo(&unknown_fields_);
@@ -22487,47 +22278,37 @@ bool NetworkPacketTraceConfig::ParseFromArray(const void* raw, size_t size) {
return !packed_error && !dec.bytes_left();
}
-std::string NetworkPacketTraceConfig::SerializeAsString() const {
+std::string Utsname::SerializeAsString() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsString();
}
-std::vector<uint8_t> NetworkPacketTraceConfig::SerializeAsArray() const {
+std::vector<uint8_t> Utsname::SerializeAsArray() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsArray();
}
-void NetworkPacketTraceConfig::Serialize(::protozero::Message* msg) const {
- // Field 1: poll_ms
+void Utsname::Serialize(::protozero::Message* msg) const {
+ // Field 1: sysname
if (_has_field_[1]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(1, poll_ms_, msg);
+ ::protozero::internal::gen_helpers::SerializeString(1, sysname_, msg);
}
- // Field 2: aggregation_threshold
+ // Field 2: version
if (_has_field_[2]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(2, aggregation_threshold_, msg);
+ ::protozero::internal::gen_helpers::SerializeString(2, version_, msg);
}
- // Field 3: intern_limit
+ // Field 3: release
if (_has_field_[3]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(3, intern_limit_, msg);
+ ::protozero::internal::gen_helpers::SerializeString(3, release_, msg);
}
- // Field 4: drop_local_port
+ // Field 4: machine
if (_has_field_[4]) {
- ::protozero::internal::gen_helpers::SerializeTinyVarInt(4, drop_local_port_, msg);
- }
-
- // Field 5: drop_remote_port
- if (_has_field_[5]) {
- ::protozero::internal::gen_helpers::SerializeTinyVarInt(5, drop_remote_port_, msg);
- }
-
- // Field 6: drop_tcp_flags
- if (_has_field_[6]) {
- ::protozero::internal::gen_helpers::SerializeTinyVarInt(6, drop_tcp_flags_, msg);
+ ::protozero::internal::gen_helpers::SerializeString(4, machine_, msg);
}
protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
@@ -22539,7 +22320,7 @@ void NetworkPacketTraceConfig::Serialize(::protozero::Message* msg) const {
#if defined(__GNUC__) || defined(__clang__)
#pragma GCC diagnostic pop
#endif
-// gen_amalgamated begin source: gen/protos/perfetto/config/android/packages_list_config.gen.cc
+// gen_amalgamated begin source: gen/protos/perfetto/common/trace_attributes.gen.cc
// gen_amalgamated expanded: #include "perfetto/protozero/gen_field_helpers.h"
// gen_amalgamated expanded: #include "perfetto/protozero/message.h"
// gen_amalgamated expanded: #include "perfetto/protozero/packed_repeated_fields.h"
@@ -22550,29 +22331,29 @@ void NetworkPacketTraceConfig::Serialize(::protozero::Message* msg) const {
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wfloat-equal"
#endif
-// gen_amalgamated expanded: #include "protos/perfetto/config/android/packages_list_config.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/common/trace_attributes.gen.h"
namespace perfetto {
namespace protos {
namespace gen {
-PackagesListConfig::PackagesListConfig() = default;
-PackagesListConfig::~PackagesListConfig() = default;
-PackagesListConfig::PackagesListConfig(const PackagesListConfig&) = default;
-PackagesListConfig& PackagesListConfig::operator=(const PackagesListConfig&) = default;
-PackagesListConfig::PackagesListConfig(PackagesListConfig&&) noexcept = default;
-PackagesListConfig& PackagesListConfig::operator=(PackagesListConfig&&) = default;
+TraceAttributes::TraceAttributes() = default;
+TraceAttributes::~TraceAttributes() = default;
+TraceAttributes::TraceAttributes(const TraceAttributes&) = default;
+TraceAttributes& TraceAttributes::operator=(const TraceAttributes&) = default;
+TraceAttributes::TraceAttributes(TraceAttributes&&) noexcept = default;
+TraceAttributes& TraceAttributes::operator=(TraceAttributes&&) = default;
-bool PackagesListConfig::operator==(const PackagesListConfig& other) const {
+bool TraceAttributes::operator==(const TraceAttributes& other) const {
return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
- && ::protozero::internal::gen_helpers::EqualsField(package_name_filter_, other.package_name_filter_)
- && ::protozero::internal::gen_helpers::EqualsField(package_name_regex_filter_, other.package_name_regex_filter_)
- && ::protozero::internal::gen_helpers::EqualsField(only_write_on_cpu_use_every_ms_, other.only_write_on_cpu_use_every_ms_);
+ && ::protozero::internal::gen_helpers::EqualsField(attribute_, other.attribute_);
}
-bool PackagesListConfig::ParseFromArray(const void* raw, size_t size) {
- package_name_filter_.clear();
- package_name_regex_filter_.clear();
+int TraceAttributes::attribute_size() const { return static_cast<int>(attribute_.size()); }
+void TraceAttributes::clear_attribute() { attribute_.clear(); }
+TraceAttributes_Attribute* TraceAttributes::add_attribute() { attribute_.emplace_back(); return &attribute_.back(); }
+bool TraceAttributes::ParseFromArray(const void* raw, size_t size) {
+ attribute_.clear();
unknown_fields_.clear();
bool packed_error = false;
@@ -22582,16 +22363,9 @@ bool PackagesListConfig::ParseFromArray(const void* raw, size_t size) {
_has_field_.set(field.id());
}
switch (field.id()) {
- case 1 /* package_name_filter */:
- package_name_filter_.emplace_back();
- ::protozero::internal::gen_helpers::DeserializeString(field, &package_name_filter_.back());
- break;
- case 3 /* package_name_regex_filter */:
- package_name_regex_filter_.emplace_back();
- ::protozero::internal::gen_helpers::DeserializeString(field, &package_name_regex_filter_.back());
- break;
- case 2 /* only_write_on_cpu_use_every_ms */:
- field.get(&only_write_on_cpu_use_every_ms_);
+ case 1 /* attribute */:
+ attribute_.emplace_back();
+ attribute_.back().ParseFromArray(field.data(), field.size());
break;
default:
field.SerializeAndAppendTo(&unknown_fields_);
@@ -22601,77 +22375,43 @@ bool PackagesListConfig::ParseFromArray(const void* raw, size_t size) {
return !packed_error && !dec.bytes_left();
}
-std::string PackagesListConfig::SerializeAsString() const {
+std::string TraceAttributes::SerializeAsString() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsString();
}
-std::vector<uint8_t> PackagesListConfig::SerializeAsArray() const {
+std::vector<uint8_t> TraceAttributes::SerializeAsArray() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsArray();
}
-void PackagesListConfig::Serialize(::protozero::Message* msg) const {
- // Field 1: package_name_filter
- for (auto& it : package_name_filter_) {
- ::protozero::internal::gen_helpers::SerializeString(1, it, msg);
- }
-
- // Field 3: package_name_regex_filter
- for (auto& it : package_name_regex_filter_) {
- ::protozero::internal::gen_helpers::SerializeString(3, it, msg);
- }
-
- // Field 2: only_write_on_cpu_use_every_ms
- if (_has_field_[2]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(2, only_write_on_cpu_use_every_ms_, msg);
+void TraceAttributes::Serialize(::protozero::Message* msg) const {
+ // Field 1: attribute
+ for (auto& it : attribute_) {
+ it.Serialize(msg->BeginNestedMessage<::protozero::Message>(1));
}
protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
}
-} // namespace perfetto
-} // namespace protos
-} // namespace gen
-#if defined(__GNUC__) || defined(__clang__)
-#pragma GCC diagnostic pop
-#endif
-// gen_amalgamated begin source: gen/protos/perfetto/config/android/pixel_modem_config.gen.cc
-// gen_amalgamated expanded: #include "perfetto/protozero/gen_field_helpers.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/message.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/packed_repeated_fields.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/proto_decoder.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/scattered_heap_buffer.h"
-// DO NOT EDIT. Autogenerated by Perfetto cppgen_plugin
-#if defined(__GNUC__) || defined(__clang__)
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wfloat-equal"
-#endif
-// gen_amalgamated expanded: #include "protos/perfetto/config/android/pixel_modem_config.gen.h"
-
-namespace perfetto {
-namespace protos {
-namespace gen {
-PixelModemConfig::PixelModemConfig() = default;
-PixelModemConfig::~PixelModemConfig() = default;
-PixelModemConfig::PixelModemConfig(const PixelModemConfig&) = default;
-PixelModemConfig& PixelModemConfig::operator=(const PixelModemConfig&) = default;
-PixelModemConfig::PixelModemConfig(PixelModemConfig&&) noexcept = default;
-PixelModemConfig& PixelModemConfig::operator=(PixelModemConfig&&) = default;
+TraceAttributes_Attribute::TraceAttributes_Attribute() = default;
+TraceAttributes_Attribute::~TraceAttributes_Attribute() = default;
+TraceAttributes_Attribute::TraceAttributes_Attribute(const TraceAttributes_Attribute&) = default;
+TraceAttributes_Attribute& TraceAttributes_Attribute::operator=(const TraceAttributes_Attribute&) = default;
+TraceAttributes_Attribute::TraceAttributes_Attribute(TraceAttributes_Attribute&&) noexcept = default;
+TraceAttributes_Attribute& TraceAttributes_Attribute::operator=(TraceAttributes_Attribute&&) = default;
-bool PixelModemConfig::operator==(const PixelModemConfig& other) const {
+bool TraceAttributes_Attribute::operator==(const TraceAttributes_Attribute& other) const {
return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
- && ::protozero::internal::gen_helpers::EqualsField(event_group_, other.event_group_)
- && ::protozero::internal::gen_helpers::EqualsField(pigweed_hash_allow_list_, other.pigweed_hash_allow_list_)
- && ::protozero::internal::gen_helpers::EqualsField(pigweed_hash_deny_list_, other.pigweed_hash_deny_list_);
+ && ::protozero::internal::gen_helpers::EqualsField(key_, other.key_)
+ && ::protozero::internal::gen_helpers::EqualsField(long_value_, other.long_value_)
+ && ::protozero::internal::gen_helpers::EqualsField(string_value_, other.string_value_);
}
-bool PixelModemConfig::ParseFromArray(const void* raw, size_t size) {
- pigweed_hash_allow_list_.clear();
- pigweed_hash_deny_list_.clear();
+bool TraceAttributes_Attribute::ParseFromArray(const void* raw, size_t size) {
unknown_fields_.clear();
bool packed_error = false;
@@ -22681,16 +22421,14 @@ bool PixelModemConfig::ParseFromArray(const void* raw, size_t size) {
_has_field_.set(field.id());
}
switch (field.id()) {
- case 1 /* event_group */:
- field.get(&event_group_);
+ case 1 /* key */:
+ ::protozero::internal::gen_helpers::DeserializeString(field, &key_);
break;
- case 2 /* pigweed_hash_allow_list */:
- pigweed_hash_allow_list_.emplace_back();
- field.get(&pigweed_hash_allow_list_.back());
+ case 2 /* long_value */:
+ field.get(&long_value_);
break;
- case 3 /* pigweed_hash_deny_list */:
- pigweed_hash_deny_list_.emplace_back();
- field.get(&pigweed_hash_deny_list_.back());
+ case 3 /* string_value */:
+ ::protozero::internal::gen_helpers::DeserializeString(field, &string_value_);
break;
default:
field.SerializeAndAppendTo(&unknown_fields_);
@@ -22700,32 +22438,32 @@ bool PixelModemConfig::ParseFromArray(const void* raw, size_t size) {
return !packed_error && !dec.bytes_left();
}
-std::string PixelModemConfig::SerializeAsString() const {
+std::string TraceAttributes_Attribute::SerializeAsString() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsString();
}
-std::vector<uint8_t> PixelModemConfig::SerializeAsArray() const {
+std::vector<uint8_t> TraceAttributes_Attribute::SerializeAsArray() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsArray();
}
-void PixelModemConfig::Serialize(::protozero::Message* msg) const {
- // Field 1: event_group
+void TraceAttributes_Attribute::Serialize(::protozero::Message* msg) const {
+ // Field 1: key
if (_has_field_[1]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(1, event_group_, msg);
+ ::protozero::internal::gen_helpers::SerializeString(1, key_, msg);
}
- // Field 2: pigweed_hash_allow_list
- for (auto& it : pigweed_hash_allow_list_) {
- ::protozero::internal::gen_helpers::SerializeVarInt(2, it, msg);
+ // Field 2: long_value
+ if (_has_field_[2]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(2, long_value_, msg);
}
- // Field 3: pigweed_hash_deny_list
- for (auto& it : pigweed_hash_deny_list_) {
- ::protozero::internal::gen_helpers::SerializeVarInt(3, it, msg);
+ // Field 3: string_value
+ if (_has_field_[3]) {
+ ::protozero::internal::gen_helpers::SerializeString(3, string_value_, msg);
}
protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
@@ -22737,7 +22475,7 @@ void PixelModemConfig::Serialize(::protozero::Message* msg) const {
#if defined(__GNUC__) || defined(__clang__)
#pragma GCC diagnostic pop
#endif
-// gen_amalgamated begin source: gen/protos/perfetto/config/android/protolog_config.gen.cc
+// gen_amalgamated begin source: gen/protos/perfetto/common/trace_stats.gen.cc
// gen_amalgamated expanded: #include "perfetto/protozero/gen_field_helpers.h"
// gen_amalgamated expanded: #include "perfetto/protozero/message.h"
// gen_amalgamated expanded: #include "perfetto/protozero/packed_repeated_fields.h"
@@ -22748,44 +22486,112 @@ void PixelModemConfig::Serialize(::protozero::Message* msg) const {
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wfloat-equal"
#endif
-// gen_amalgamated expanded: #include "protos/perfetto/config/android/protolog_config.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/common/trace_stats.gen.h"
namespace perfetto {
namespace protos {
namespace gen {
-ProtoLogGroup::ProtoLogGroup() = default;
-ProtoLogGroup::~ProtoLogGroup() = default;
-ProtoLogGroup::ProtoLogGroup(const ProtoLogGroup&) = default;
-ProtoLogGroup& ProtoLogGroup::operator=(const ProtoLogGroup&) = default;
-ProtoLogGroup::ProtoLogGroup(ProtoLogGroup&&) noexcept = default;
-ProtoLogGroup& ProtoLogGroup::operator=(ProtoLogGroup&&) = default;
+TraceStats::TraceStats() = default;
+TraceStats::~TraceStats() = default;
+TraceStats::TraceStats(const TraceStats&) = default;
+TraceStats& TraceStats::operator=(const TraceStats&) = default;
+TraceStats::TraceStats(TraceStats&&) noexcept = default;
+TraceStats& TraceStats::operator=(TraceStats&&) = default;
-bool ProtoLogGroup::operator==(const ProtoLogGroup& other) const {
+bool TraceStats::operator==(const TraceStats& other) const {
return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
- && ::protozero::internal::gen_helpers::EqualsField(group_name_, other.group_name_)
- && ::protozero::internal::gen_helpers::EqualsField(log_from_, other.log_from_)
- && ::protozero::internal::gen_helpers::EqualsField(collect_stacktrace_, other.collect_stacktrace_);
-}
-
-bool ProtoLogGroup::ParseFromArray(const void* raw, size_t size) {
- unknown_fields_.clear();
- bool packed_error = false;
-
- ::protozero::ProtoDecoder dec(raw, size);
- for (auto field = dec.ReadField(); field.valid(); field = dec.ReadField()) {
- if (field.id() < _has_field_.size()) {
- _has_field_.set(field.id());
+ && ::protozero::internal::gen_helpers::EqualsField(buffer_stats_, other.buffer_stats_)
+ && ::protozero::internal::gen_helpers::EqualsField(chunk_payload_histogram_def_, other.chunk_payload_histogram_def_)
+ && ::protozero::internal::gen_helpers::EqualsField(writer_stats_, other.writer_stats_)
+ && ::protozero::internal::gen_helpers::EqualsField(producers_connected_, other.producers_connected_)
+ && ::protozero::internal::gen_helpers::EqualsField(producers_seen_, other.producers_seen_)
+ && ::protozero::internal::gen_helpers::EqualsField(data_sources_registered_, other.data_sources_registered_)
+ && ::protozero::internal::gen_helpers::EqualsField(data_sources_seen_, other.data_sources_seen_)
+ && ::protozero::internal::gen_helpers::EqualsField(tracing_sessions_, other.tracing_sessions_)
+ && ::protozero::internal::gen_helpers::EqualsField(total_buffers_, other.total_buffers_)
+ && ::protozero::internal::gen_helpers::EqualsField(chunks_discarded_, other.chunks_discarded_)
+ && ::protozero::internal::gen_helpers::EqualsField(patches_discarded_, other.patches_discarded_)
+ && ::protozero::internal::gen_helpers::EqualsField(invalid_packets_, other.invalid_packets_)
+ && ::protozero::internal::gen_helpers::EqualsField(filter_stats_, other.filter_stats_)
+ && ::protozero::internal::gen_helpers::EqualsField(flushes_requested_, other.flushes_requested_)
+ && ::protozero::internal::gen_helpers::EqualsField(flushes_succeeded_, other.flushes_succeeded_)
+ && ::protozero::internal::gen_helpers::EqualsField(flushes_failed_, other.flushes_failed_)
+ && ::protozero::internal::gen_helpers::EqualsField(final_flush_outcome_, other.final_flush_outcome_);
+}
+
+int TraceStats::buffer_stats_size() const { return static_cast<int>(buffer_stats_.size()); }
+void TraceStats::clear_buffer_stats() { buffer_stats_.clear(); }
+TraceStats_BufferStats* TraceStats::add_buffer_stats() { buffer_stats_.emplace_back(); return &buffer_stats_.back(); }
+int TraceStats::writer_stats_size() const { return static_cast<int>(writer_stats_.size()); }
+void TraceStats::clear_writer_stats() { writer_stats_.clear(); }
+TraceStats_WriterStats* TraceStats::add_writer_stats() { writer_stats_.emplace_back(); return &writer_stats_.back(); }
+bool TraceStats::ParseFromArray(const void* raw, size_t size) {
+ buffer_stats_.clear();
+ chunk_payload_histogram_def_.clear();
+ writer_stats_.clear();
+ unknown_fields_.clear();
+ bool packed_error = false;
+
+ ::protozero::ProtoDecoder dec(raw, size);
+ for (auto field = dec.ReadField(); field.valid(); field = dec.ReadField()) {
+ if (field.id() < _has_field_.size()) {
+ _has_field_.set(field.id());
}
switch (field.id()) {
- case 1 /* group_name */:
- ::protozero::internal::gen_helpers::DeserializeString(field, &group_name_);
+ case 1 /* buffer_stats */:
+ buffer_stats_.emplace_back();
+ buffer_stats_.back().ParseFromArray(field.data(), field.size());
break;
- case 2 /* log_from */:
- field.get(&log_from_);
+ case 17 /* chunk_payload_histogram_def */:
+ chunk_payload_histogram_def_.emplace_back();
+ field.get(&chunk_payload_histogram_def_.back());
break;
- case 3 /* collect_stacktrace */:
- field.get(&collect_stacktrace_);
+ case 18 /* writer_stats */:
+ writer_stats_.emplace_back();
+ writer_stats_.back().ParseFromArray(field.data(), field.size());
+ break;
+ case 2 /* producers_connected */:
+ field.get(&producers_connected_);
+ break;
+ case 3 /* producers_seen */:
+ field.get(&producers_seen_);
+ break;
+ case 4 /* data_sources_registered */:
+ field.get(&data_sources_registered_);
+ break;
+ case 5 /* data_sources_seen */:
+ field.get(&data_sources_seen_);
+ break;
+ case 6 /* tracing_sessions */:
+ field.get(&tracing_sessions_);
+ break;
+ case 7 /* total_buffers */:
+ field.get(&total_buffers_);
+ break;
+ case 8 /* chunks_discarded */:
+ field.get(&chunks_discarded_);
+ break;
+ case 9 /* patches_discarded */:
+ field.get(&patches_discarded_);
+ break;
+ case 10 /* invalid_packets */:
+ field.get(&invalid_packets_);
+ break;
+ case 11 /* filter_stats */:
+ (*filter_stats_).ParseFromArray(field.data(), field.size());
+ break;
+ case 12 /* flushes_requested */:
+ field.get(&flushes_requested_);
+ break;
+ case 13 /* flushes_succeeded */:
+ field.get(&flushes_succeeded_);
+ break;
+ case 14 /* flushes_failed */:
+ field.get(&flushes_failed_);
+ break;
+ case 15 /* final_flush_outcome */:
+ field.get(&final_flush_outcome_);
break;
default:
field.SerializeAndAppendTo(&unknown_fields_);
@@ -22795,57 +22601,127 @@ bool ProtoLogGroup::ParseFromArray(const void* raw, size_t size) {
return !packed_error && !dec.bytes_left();
}
-std::string ProtoLogGroup::SerializeAsString() const {
+std::string TraceStats::SerializeAsString() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsString();
}
-std::vector<uint8_t> ProtoLogGroup::SerializeAsArray() const {
+std::vector<uint8_t> TraceStats::SerializeAsArray() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsArray();
}
-void ProtoLogGroup::Serialize(::protozero::Message* msg) const {
- // Field 1: group_name
- if (_has_field_[1]) {
- ::protozero::internal::gen_helpers::SerializeString(1, group_name_, msg);
+void TraceStats::Serialize(::protozero::Message* msg) const {
+ // Field 1: buffer_stats
+ for (auto& it : buffer_stats_) {
+ it.Serialize(msg->BeginNestedMessage<::protozero::Message>(1));
}
- // Field 2: log_from
+ // Field 17: chunk_payload_histogram_def
+ for (auto& it : chunk_payload_histogram_def_) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(17, it, msg);
+ }
+
+ // Field 18: writer_stats
+ for (auto& it : writer_stats_) {
+ it.Serialize(msg->BeginNestedMessage<::protozero::Message>(18));
+ }
+
+ // Field 2: producers_connected
if (_has_field_[2]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(2, log_from_, msg);
+ ::protozero::internal::gen_helpers::SerializeVarInt(2, producers_connected_, msg);
}
- // Field 3: collect_stacktrace
+ // Field 3: producers_seen
if (_has_field_[3]) {
- ::protozero::internal::gen_helpers::SerializeTinyVarInt(3, collect_stacktrace_, msg);
+ ::protozero::internal::gen_helpers::SerializeVarInt(3, producers_seen_, msg);
+ }
+
+ // Field 4: data_sources_registered
+ if (_has_field_[4]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(4, data_sources_registered_, msg);
+ }
+
+ // Field 5: data_sources_seen
+ if (_has_field_[5]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(5, data_sources_seen_, msg);
+ }
+
+ // Field 6: tracing_sessions
+ if (_has_field_[6]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(6, tracing_sessions_, msg);
+ }
+
+ // Field 7: total_buffers
+ if (_has_field_[7]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(7, total_buffers_, msg);
+ }
+
+ // Field 8: chunks_discarded
+ if (_has_field_[8]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(8, chunks_discarded_, msg);
+ }
+
+ // Field 9: patches_discarded
+ if (_has_field_[9]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(9, patches_discarded_, msg);
+ }
+
+ // Field 10: invalid_packets
+ if (_has_field_[10]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(10, invalid_packets_, msg);
+ }
+
+ // Field 11: filter_stats
+ if (_has_field_[11]) {
+ (*filter_stats_).Serialize(msg->BeginNestedMessage<::protozero::Message>(11));
+ }
+
+ // Field 12: flushes_requested
+ if (_has_field_[12]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(12, flushes_requested_, msg);
+ }
+
+ // Field 13: flushes_succeeded
+ if (_has_field_[13]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(13, flushes_succeeded_, msg);
+ }
+
+ // Field 14: flushes_failed
+ if (_has_field_[14]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(14, flushes_failed_, msg);
+ }
+
+ // Field 15: final_flush_outcome
+ if (_has_field_[15]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(15, final_flush_outcome_, msg);
}
protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
}
-ProtoLogConfig::ProtoLogConfig() = default;
-ProtoLogConfig::~ProtoLogConfig() = default;
-ProtoLogConfig::ProtoLogConfig(const ProtoLogConfig&) = default;
-ProtoLogConfig& ProtoLogConfig::operator=(const ProtoLogConfig&) = default;
-ProtoLogConfig::ProtoLogConfig(ProtoLogConfig&&) noexcept = default;
-ProtoLogConfig& ProtoLogConfig::operator=(ProtoLogConfig&&) = default;
+TraceStats_FilterStats::TraceStats_FilterStats() = default;
+TraceStats_FilterStats::~TraceStats_FilterStats() = default;
+TraceStats_FilterStats::TraceStats_FilterStats(const TraceStats_FilterStats&) = default;
+TraceStats_FilterStats& TraceStats_FilterStats::operator=(const TraceStats_FilterStats&) = default;
+TraceStats_FilterStats::TraceStats_FilterStats(TraceStats_FilterStats&&) noexcept = default;
+TraceStats_FilterStats& TraceStats_FilterStats::operator=(TraceStats_FilterStats&&) = default;
-bool ProtoLogConfig::operator==(const ProtoLogConfig& other) const {
+bool TraceStats_FilterStats::operator==(const TraceStats_FilterStats& other) const {
return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
- && ::protozero::internal::gen_helpers::EqualsField(group_overrides_, other.group_overrides_)
- && ::protozero::internal::gen_helpers::EqualsField(tracing_mode_, other.tracing_mode_)
- && ::protozero::internal::gen_helpers::EqualsField(default_log_from_level_, other.default_log_from_level_);
+ && ::protozero::internal::gen_helpers::EqualsField(input_packets_, other.input_packets_)
+ && ::protozero::internal::gen_helpers::EqualsField(input_bytes_, other.input_bytes_)
+ && ::protozero::internal::gen_helpers::EqualsField(output_bytes_, other.output_bytes_)
+ && ::protozero::internal::gen_helpers::EqualsField(errors_, other.errors_)
+ && ::protozero::internal::gen_helpers::EqualsField(time_taken_ns_, other.time_taken_ns_)
+ && ::protozero::internal::gen_helpers::EqualsField(bytes_discarded_per_buffer_, other.bytes_discarded_per_buffer_);
}
-int ProtoLogConfig::group_overrides_size() const { return static_cast<int>(group_overrides_.size()); }
-void ProtoLogConfig::clear_group_overrides() { group_overrides_.clear(); }
-ProtoLogGroup* ProtoLogConfig::add_group_overrides() { group_overrides_.emplace_back(); return &group_overrides_.back(); }
-bool ProtoLogConfig::ParseFromArray(const void* raw, size_t size) {
- group_overrides_.clear();
+bool TraceStats_FilterStats::ParseFromArray(const void* raw, size_t size) {
+ bytes_discarded_per_buffer_.clear();
unknown_fields_.clear();
bool packed_error = false;
@@ -22855,15 +22731,24 @@ bool ProtoLogConfig::ParseFromArray(const void* raw, size_t size) {
_has_field_.set(field.id());
}
switch (field.id()) {
- case 1 /* group_overrides */:
- group_overrides_.emplace_back();
- group_overrides_.back().ParseFromArray(field.data(), field.size());
+ case 1 /* input_packets */:
+ field.get(&input_packets_);
break;
- case 2 /* tracing_mode */:
- field.get(&tracing_mode_);
+ case 2 /* input_bytes */:
+ field.get(&input_bytes_);
break;
- case 3 /* default_log_from_level */:
- field.get(&default_log_from_level_);
+ case 3 /* output_bytes */:
+ field.get(&output_bytes_);
+ break;
+ case 4 /* errors */:
+ field.get(&errors_);
+ break;
+ case 5 /* time_taken_ns */:
+ field.get(&time_taken_ns_);
+ break;
+ case 20 /* bytes_discarded_per_buffer */:
+ bytes_discarded_per_buffer_.emplace_back();
+ field.get(&bytes_discarded_per_buffer_.back());
break;
default:
field.SerializeAndAppendTo(&unknown_fields_);
@@ -22873,75 +22758,71 @@ bool ProtoLogConfig::ParseFromArray(const void* raw, size_t size) {
return !packed_error && !dec.bytes_left();
}
-std::string ProtoLogConfig::SerializeAsString() const {
+std::string TraceStats_FilterStats::SerializeAsString() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsString();
}
-std::vector<uint8_t> ProtoLogConfig::SerializeAsArray() const {
+std::vector<uint8_t> TraceStats_FilterStats::SerializeAsArray() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsArray();
}
-void ProtoLogConfig::Serialize(::protozero::Message* msg) const {
- // Field 1: group_overrides
- for (auto& it : group_overrides_) {
- it.Serialize(msg->BeginNestedMessage<::protozero::Message>(1));
+void TraceStats_FilterStats::Serialize(::protozero::Message* msg) const {
+ // Field 1: input_packets
+ if (_has_field_[1]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(1, input_packets_, msg);
}
- // Field 2: tracing_mode
+ // Field 2: input_bytes
if (_has_field_[2]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(2, tracing_mode_, msg);
+ ::protozero::internal::gen_helpers::SerializeVarInt(2, input_bytes_, msg);
}
- // Field 3: default_log_from_level
+ // Field 3: output_bytes
if (_has_field_[3]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(3, default_log_from_level_, msg);
+ ::protozero::internal::gen_helpers::SerializeVarInt(3, output_bytes_, msg);
+ }
+
+ // Field 4: errors
+ if (_has_field_[4]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(4, errors_, msg);
+ }
+
+ // Field 5: time_taken_ns
+ if (_has_field_[5]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(5, time_taken_ns_, msg);
+ }
+
+ // Field 20: bytes_discarded_per_buffer
+ for (auto& it : bytes_discarded_per_buffer_) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(20, it, msg);
}
protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
}
-} // namespace perfetto
-} // namespace protos
-} // namespace gen
-#if defined(__GNUC__) || defined(__clang__)
-#pragma GCC diagnostic pop
-#endif
-// gen_amalgamated begin source: gen/protos/perfetto/config/android/surfaceflinger_layers_config.gen.cc
-// gen_amalgamated expanded: #include "perfetto/protozero/gen_field_helpers.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/message.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/packed_repeated_fields.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/proto_decoder.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/scattered_heap_buffer.h"
-// DO NOT EDIT. Autogenerated by Perfetto cppgen_plugin
-#if defined(__GNUC__) || defined(__clang__)
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wfloat-equal"
-#endif
-// gen_amalgamated expanded: #include "protos/perfetto/config/android/surfaceflinger_layers_config.gen.h"
-
-namespace perfetto {
-namespace protos {
-namespace gen {
-SurfaceFlingerLayersConfig::SurfaceFlingerLayersConfig() = default;
-SurfaceFlingerLayersConfig::~SurfaceFlingerLayersConfig() = default;
-SurfaceFlingerLayersConfig::SurfaceFlingerLayersConfig(const SurfaceFlingerLayersConfig&) = default;
-SurfaceFlingerLayersConfig& SurfaceFlingerLayersConfig::operator=(const SurfaceFlingerLayersConfig&) = default;
-SurfaceFlingerLayersConfig::SurfaceFlingerLayersConfig(SurfaceFlingerLayersConfig&&) noexcept = default;
-SurfaceFlingerLayersConfig& SurfaceFlingerLayersConfig::operator=(SurfaceFlingerLayersConfig&&) = default;
+TraceStats_WriterStats::TraceStats_WriterStats() = default;
+TraceStats_WriterStats::~TraceStats_WriterStats() = default;
+TraceStats_WriterStats::TraceStats_WriterStats(const TraceStats_WriterStats&) = default;
+TraceStats_WriterStats& TraceStats_WriterStats::operator=(const TraceStats_WriterStats&) = default;
+TraceStats_WriterStats::TraceStats_WriterStats(TraceStats_WriterStats&&) noexcept = default;
+TraceStats_WriterStats& TraceStats_WriterStats::operator=(TraceStats_WriterStats&&) = default;
-bool SurfaceFlingerLayersConfig::operator==(const SurfaceFlingerLayersConfig& other) const {
+bool TraceStats_WriterStats::operator==(const TraceStats_WriterStats& other) const {
return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
- && ::protozero::internal::gen_helpers::EqualsField(mode_, other.mode_)
- && ::protozero::internal::gen_helpers::EqualsField(trace_flags_, other.trace_flags_);
+ && ::protozero::internal::gen_helpers::EqualsField(sequence_id_, other.sequence_id_)
+ && ::protozero::internal::gen_helpers::EqualsField(buffer_, other.buffer_)
+ && ::protozero::internal::gen_helpers::EqualsField(chunk_payload_histogram_counts_, other.chunk_payload_histogram_counts_)
+ && ::protozero::internal::gen_helpers::EqualsField(chunk_payload_histogram_sum_, other.chunk_payload_histogram_sum_);
}
-bool SurfaceFlingerLayersConfig::ParseFromArray(const void* raw, size_t size) {
- trace_flags_.clear();
+bool TraceStats_WriterStats::ParseFromArray(const void* raw, size_t size) {
+ chunk_payload_histogram_counts_.clear();
+ chunk_payload_histogram_sum_.clear();
unknown_fields_.clear();
bool packed_error = false;
@@ -22951,12 +22832,19 @@ bool SurfaceFlingerLayersConfig::ParseFromArray(const void* raw, size_t size) {
_has_field_.set(field.id());
}
switch (field.id()) {
- case 1 /* mode */:
- field.get(&mode_);
+ case 1 /* sequence_id */:
+ field.get(&sequence_id_);
break;
- case 2 /* trace_flags */:
- trace_flags_.emplace_back();
- field.get(&trace_flags_.back());
+ case 4 /* buffer */:
+ field.get(&buffer_);
+ break;
+ case 2 /* chunk_payload_histogram_counts */:
+ if (!::protozero::internal::gen_helpers::DeserializePackedRepeated<::protozero::proto_utils::ProtoWireType::kVarInt, uint64_t>(field, &chunk_payload_histogram_counts_)) {
+ packed_error = true;}
+ break;
+ case 3 /* chunk_payload_histogram_sum */:
+ if (!::protozero::internal::gen_helpers::DeserializePackedRepeated<::protozero::proto_utils::ProtoWireType::kVarInt, int64_t>(field, &chunk_payload_histogram_sum_)) {
+ packed_error = true;}
break;
default:
field.SerializeAndAppendTo(&unknown_fields_);
@@ -22966,68 +22854,84 @@ bool SurfaceFlingerLayersConfig::ParseFromArray(const void* raw, size_t size) {
return !packed_error && !dec.bytes_left();
}
-std::string SurfaceFlingerLayersConfig::SerializeAsString() const {
+std::string TraceStats_WriterStats::SerializeAsString() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsString();
}
-std::vector<uint8_t> SurfaceFlingerLayersConfig::SerializeAsArray() const {
+std::vector<uint8_t> TraceStats_WriterStats::SerializeAsArray() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsArray();
}
-void SurfaceFlingerLayersConfig::Serialize(::protozero::Message* msg) const {
- // Field 1: mode
+void TraceStats_WriterStats::Serialize(::protozero::Message* msg) const {
+ // Field 1: sequence_id
if (_has_field_[1]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(1, mode_, msg);
+ ::protozero::internal::gen_helpers::SerializeVarInt(1, sequence_id_, msg);
}
- // Field 2: trace_flags
- for (auto& it : trace_flags_) {
- ::protozero::internal::gen_helpers::SerializeVarInt(2, it, msg);
+ // Field 4: buffer
+ if (_has_field_[4]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(4, buffer_, msg);
+ }
+
+ // Field 2: chunk_payload_histogram_counts
+ {
+ ::protozero::PackedVarInt pack;
+ for (auto& it : chunk_payload_histogram_counts_)
+ pack.Append(it);
+ msg->AppendBytes(2, pack.data(), pack.size());
+ }
+
+ // Field 3: chunk_payload_histogram_sum
+ {
+ ::protozero::PackedVarInt pack;
+ for (auto& it : chunk_payload_histogram_sum_)
+ pack.Append(it);
+ msg->AppendBytes(3, pack.data(), pack.size());
}
protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
}
-} // namespace perfetto
-} // namespace protos
-} // namespace gen
-#if defined(__GNUC__) || defined(__clang__)
-#pragma GCC diagnostic pop
-#endif
-// gen_amalgamated begin source: gen/protos/perfetto/config/android/surfaceflinger_transactions_config.gen.cc
-// gen_amalgamated expanded: #include "perfetto/protozero/gen_field_helpers.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/message.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/packed_repeated_fields.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/proto_decoder.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/scattered_heap_buffer.h"
-// DO NOT EDIT. Autogenerated by Perfetto cppgen_plugin
-#if defined(__GNUC__) || defined(__clang__)
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wfloat-equal"
-#endif
-// gen_amalgamated expanded: #include "protos/perfetto/config/android/surfaceflinger_transactions_config.gen.h"
-
-namespace perfetto {
-namespace protos {
-namespace gen {
-SurfaceFlingerTransactionsConfig::SurfaceFlingerTransactionsConfig() = default;
-SurfaceFlingerTransactionsConfig::~SurfaceFlingerTransactionsConfig() = default;
-SurfaceFlingerTransactionsConfig::SurfaceFlingerTransactionsConfig(const SurfaceFlingerTransactionsConfig&) = default;
-SurfaceFlingerTransactionsConfig& SurfaceFlingerTransactionsConfig::operator=(const SurfaceFlingerTransactionsConfig&) = default;
-SurfaceFlingerTransactionsConfig::SurfaceFlingerTransactionsConfig(SurfaceFlingerTransactionsConfig&&) noexcept = default;
-SurfaceFlingerTransactionsConfig& SurfaceFlingerTransactionsConfig::operator=(SurfaceFlingerTransactionsConfig&&) = default;
+TraceStats_BufferStats::TraceStats_BufferStats() = default;
+TraceStats_BufferStats::~TraceStats_BufferStats() = default;
+TraceStats_BufferStats::TraceStats_BufferStats(const TraceStats_BufferStats&) = default;
+TraceStats_BufferStats& TraceStats_BufferStats::operator=(const TraceStats_BufferStats&) = default;
+TraceStats_BufferStats::TraceStats_BufferStats(TraceStats_BufferStats&&) noexcept = default;
+TraceStats_BufferStats& TraceStats_BufferStats::operator=(TraceStats_BufferStats&&) = default;
-bool SurfaceFlingerTransactionsConfig::operator==(const SurfaceFlingerTransactionsConfig& other) const {
+bool TraceStats_BufferStats::operator==(const TraceStats_BufferStats& other) const {
return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
- && ::protozero::internal::gen_helpers::EqualsField(mode_, other.mode_);
+ && ::protozero::internal::gen_helpers::EqualsField(buffer_size_, other.buffer_size_)
+ && ::protozero::internal::gen_helpers::EqualsField(bytes_written_, other.bytes_written_)
+ && ::protozero::internal::gen_helpers::EqualsField(bytes_overwritten_, other.bytes_overwritten_)
+ && ::protozero::internal::gen_helpers::EqualsField(bytes_read_, other.bytes_read_)
+ && ::protozero::internal::gen_helpers::EqualsField(padding_bytes_written_, other.padding_bytes_written_)
+ && ::protozero::internal::gen_helpers::EqualsField(padding_bytes_cleared_, other.padding_bytes_cleared_)
+ && ::protozero::internal::gen_helpers::EqualsField(chunks_written_, other.chunks_written_)
+ && ::protozero::internal::gen_helpers::EqualsField(chunks_rewritten_, other.chunks_rewritten_)
+ && ::protozero::internal::gen_helpers::EqualsField(chunks_relocated_, other.chunks_relocated_)
+ && ::protozero::internal::gen_helpers::EqualsField(chunks_overwritten_, other.chunks_overwritten_)
+ && ::protozero::internal::gen_helpers::EqualsField(chunks_discarded_, other.chunks_discarded_)
+ && ::protozero::internal::gen_helpers::EqualsField(chunks_read_, other.chunks_read_)
+ && ::protozero::internal::gen_helpers::EqualsField(chunks_committed_out_of_order_, other.chunks_committed_out_of_order_)
+ && ::protozero::internal::gen_helpers::EqualsField(write_wrap_count_, other.write_wrap_count_)
+ && ::protozero::internal::gen_helpers::EqualsField(compactions_, other.compactions_)
+ && ::protozero::internal::gen_helpers::EqualsField(compactions_skipped_, other.compactions_skipped_)
+ && ::protozero::internal::gen_helpers::EqualsField(patches_succeeded_, other.patches_succeeded_)
+ && ::protozero::internal::gen_helpers::EqualsField(patches_failed_, other.patches_failed_)
+ && ::protozero::internal::gen_helpers::EqualsField(readaheads_succeeded_, other.readaheads_succeeded_)
+ && ::protozero::internal::gen_helpers::EqualsField(readaheads_failed_, other.readaheads_failed_)
+ && ::protozero::internal::gen_helpers::EqualsField(abi_violations_, other.abi_violations_)
+ && ::protozero::internal::gen_helpers::EqualsField(trace_writer_packet_loss_, other.trace_writer_packet_loss_)
+ && ::protozero::internal::gen_helpers::EqualsField(oversized_packets_dropped_, other.oversized_packets_dropped_);
}
-bool SurfaceFlingerTransactionsConfig::ParseFromArray(const void* raw, size_t size) {
+bool TraceStats_BufferStats::ParseFromArray(const void* raw, size_t size) {
unknown_fields_.clear();
bool packed_error = false;
@@ -23037,8 +22941,74 @@ bool SurfaceFlingerTransactionsConfig::ParseFromArray(const void* raw, size_t si
_has_field_.set(field.id());
}
switch (field.id()) {
- case 1 /* mode */:
- field.get(&mode_);
+ case 12 /* buffer_size */:
+ field.get(&buffer_size_);
+ break;
+ case 1 /* bytes_written */:
+ field.get(&bytes_written_);
+ break;
+ case 13 /* bytes_overwritten */:
+ field.get(&bytes_overwritten_);
+ break;
+ case 14 /* bytes_read */:
+ field.get(&bytes_read_);
+ break;
+ case 15 /* padding_bytes_written */:
+ field.get(&padding_bytes_written_);
+ break;
+ case 16 /* padding_bytes_cleared */:
+ field.get(&padding_bytes_cleared_);
+ break;
+ case 2 /* chunks_written */:
+ field.get(&chunks_written_);
+ break;
+ case 10 /* chunks_rewritten */:
+ field.get(&chunks_rewritten_);
+ break;
+ case 20 /* chunks_relocated */:
+ field.get(&chunks_relocated_);
+ break;
+ case 3 /* chunks_overwritten */:
+ field.get(&chunks_overwritten_);
+ break;
+ case 18 /* chunks_discarded */:
+ field.get(&chunks_discarded_);
+ break;
+ case 17 /* chunks_read */:
+ field.get(&chunks_read_);
+ break;
+ case 11 /* chunks_committed_out_of_order */:
+ field.get(&chunks_committed_out_of_order_);
+ break;
+ case 4 /* write_wrap_count */:
+ field.get(&write_wrap_count_);
+ break;
+ case 23 /* compactions */:
+ field.get(&compactions_);
+ break;
+ case 24 /* compactions_skipped */:
+ field.get(&compactions_skipped_);
+ break;
+ case 5 /* patches_succeeded */:
+ field.get(&patches_succeeded_);
+ break;
+ case 6 /* patches_failed */:
+ field.get(&patches_failed_);
+ break;
+ case 7 /* readaheads_succeeded */:
+ field.get(&readaheads_succeeded_);
+ break;
+ case 8 /* readaheads_failed */:
+ field.get(&readaheads_failed_);
+ break;
+ case 9 /* abi_violations */:
+ field.get(&abi_violations_);
+ break;
+ case 19 /* trace_writer_packet_loss */:
+ field.get(&trace_writer_packet_loss_);
+ break;
+ case 22 /* oversized_packets_dropped */:
+ field.get(&oversized_packets_dropped_);
break;
default:
field.SerializeAndAppendTo(&unknown_fields_);
@@ -23048,101 +23018,132 @@ bool SurfaceFlingerTransactionsConfig::ParseFromArray(const void* raw, size_t si
return !packed_error && !dec.bytes_left();
}
-std::string SurfaceFlingerTransactionsConfig::SerializeAsString() const {
+std::string TraceStats_BufferStats::SerializeAsString() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsString();
}
-std::vector<uint8_t> SurfaceFlingerTransactionsConfig::SerializeAsArray() const {
+std::vector<uint8_t> TraceStats_BufferStats::SerializeAsArray() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsArray();
}
-void SurfaceFlingerTransactionsConfig::Serialize(::protozero::Message* msg) const {
- // Field 1: mode
+void TraceStats_BufferStats::Serialize(::protozero::Message* msg) const {
+ // Field 12: buffer_size
+ if (_has_field_[12]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(12, buffer_size_, msg);
+ }
+
+ // Field 1: bytes_written
if (_has_field_[1]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(1, mode_, msg);
+ ::protozero::internal::gen_helpers::SerializeVarInt(1, bytes_written_, msg);
}
- protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
-}
+ // Field 13: bytes_overwritten
+ if (_has_field_[13]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(13, bytes_overwritten_, msg);
+ }
-} // namespace perfetto
-} // namespace protos
-} // namespace gen
-#if defined(__GNUC__) || defined(__clang__)
-#pragma GCC diagnostic pop
-#endif
-// gen_amalgamated begin source: gen/protos/perfetto/config/android/user_list_config.gen.cc
-// gen_amalgamated expanded: #include "perfetto/protozero/gen_field_helpers.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/message.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/packed_repeated_fields.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/proto_decoder.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/scattered_heap_buffer.h"
-// DO NOT EDIT. Autogenerated by Perfetto cppgen_plugin
-#if defined(__GNUC__) || defined(__clang__)
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wfloat-equal"
-#endif
-// gen_amalgamated expanded: #include "protos/perfetto/config/android/user_list_config.gen.h"
+ // Field 14: bytes_read
+ if (_has_field_[14]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(14, bytes_read_, msg);
+ }
-namespace perfetto {
-namespace protos {
-namespace gen {
+ // Field 15: padding_bytes_written
+ if (_has_field_[15]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(15, padding_bytes_written_, msg);
+ }
-AndroidUserListConfig::AndroidUserListConfig() = default;
-AndroidUserListConfig::~AndroidUserListConfig() = default;
-AndroidUserListConfig::AndroidUserListConfig(const AndroidUserListConfig&) = default;
-AndroidUserListConfig& AndroidUserListConfig::operator=(const AndroidUserListConfig&) = default;
-AndroidUserListConfig::AndroidUserListConfig(AndroidUserListConfig&&) noexcept = default;
-AndroidUserListConfig& AndroidUserListConfig::operator=(AndroidUserListConfig&&) = default;
+ // Field 16: padding_bytes_cleared
+ if (_has_field_[16]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(16, padding_bytes_cleared_, msg);
+ }
-bool AndroidUserListConfig::operator==(const AndroidUserListConfig& other) const {
- return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
- && ::protozero::internal::gen_helpers::EqualsField(user_type_filter_, other.user_type_filter_);
-}
+ // Field 2: chunks_written
+ if (_has_field_[2]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(2, chunks_written_, msg);
+ }
-bool AndroidUserListConfig::ParseFromArray(const void* raw, size_t size) {
- user_type_filter_.clear();
- unknown_fields_.clear();
- bool packed_error = false;
+ // Field 10: chunks_rewritten
+ if (_has_field_[10]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(10, chunks_rewritten_, msg);
+ }
- ::protozero::ProtoDecoder dec(raw, size);
- for (auto field = dec.ReadField(); field.valid(); field = dec.ReadField()) {
- if (field.id() < _has_field_.size()) {
- _has_field_.set(field.id());
- }
- switch (field.id()) {
- case 1 /* user_type_filter */:
- user_type_filter_.emplace_back();
- ::protozero::internal::gen_helpers::DeserializeString(field, &user_type_filter_.back());
- break;
- default:
- field.SerializeAndAppendTo(&unknown_fields_);
- break;
- }
+ // Field 20: chunks_relocated
+ if (_has_field_[20]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(20, chunks_relocated_, msg);
}
- return !packed_error && !dec.bytes_left();
-}
-std::string AndroidUserListConfig::SerializeAsString() const {
- ::protozero::internal::gen_helpers::MessageSerializer msg;
- Serialize(msg.get());
- return msg.SerializeAsString();
-}
+ // Field 3: chunks_overwritten
+ if (_has_field_[3]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(3, chunks_overwritten_, msg);
+ }
-std::vector<uint8_t> AndroidUserListConfig::SerializeAsArray() const {
- ::protozero::internal::gen_helpers::MessageSerializer msg;
- Serialize(msg.get());
- return msg.SerializeAsArray();
-}
+ // Field 18: chunks_discarded
+ if (_has_field_[18]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(18, chunks_discarded_, msg);
+ }
-void AndroidUserListConfig::Serialize(::protozero::Message* msg) const {
- // Field 1: user_type_filter
- for (auto& it : user_type_filter_) {
- ::protozero::internal::gen_helpers::SerializeString(1, it, msg);
+ // Field 17: chunks_read
+ if (_has_field_[17]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(17, chunks_read_, msg);
+ }
+
+ // Field 11: chunks_committed_out_of_order
+ if (_has_field_[11]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(11, chunks_committed_out_of_order_, msg);
+ }
+
+ // Field 4: write_wrap_count
+ if (_has_field_[4]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(4, write_wrap_count_, msg);
+ }
+
+ // Field 23: compactions
+ if (_has_field_[23]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(23, compactions_, msg);
+ }
+
+ // Field 24: compactions_skipped
+ if (_has_field_[24]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(24, compactions_skipped_, msg);
+ }
+
+ // Field 5: patches_succeeded
+ if (_has_field_[5]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(5, patches_succeeded_, msg);
+ }
+
+ // Field 6: patches_failed
+ if (_has_field_[6]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(6, patches_failed_, msg);
+ }
+
+ // Field 7: readaheads_succeeded
+ if (_has_field_[7]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(7, readaheads_succeeded_, msg);
+ }
+
+ // Field 8: readaheads_failed
+ if (_has_field_[8]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(8, readaheads_failed_, msg);
+ }
+
+ // Field 9: abi_violations
+ if (_has_field_[9]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(9, abi_violations_, msg);
+ }
+
+ // Field 19: trace_writer_packet_loss
+ if (_has_field_[19]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(19, trace_writer_packet_loss_, msg);
+ }
+
+ // Field 22: oversized_packets_dropped
+ if (_has_field_[22]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(22, oversized_packets_dropped_, msg);
}
protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
@@ -23154,7 +23155,7 @@ void AndroidUserListConfig::Serialize(::protozero::Message* msg) const {
#if defined(__GNUC__) || defined(__clang__)
#pragma GCC diagnostic pop
#endif
-// gen_amalgamated begin source: gen/protos/perfetto/config/android/windowmanager_config.gen.cc
+// gen_amalgamated begin source: gen/protos/perfetto/common/tracing_service_capabilities.gen.cc
// gen_amalgamated expanded: #include "perfetto/protozero/gen_field_helpers.h"
// gen_amalgamated expanded: #include "perfetto/protozero/message.h"
// gen_amalgamated expanded: #include "perfetto/protozero/packed_repeated_fields.h"
@@ -23165,27 +23166,30 @@ void AndroidUserListConfig::Serialize(::protozero::Message* msg) const {
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wfloat-equal"
#endif
-// gen_amalgamated expanded: #include "protos/perfetto/config/android/windowmanager_config.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/common/tracing_service_capabilities.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/common/observable_events.gen.h"
namespace perfetto {
namespace protos {
namespace gen {
-WindowManagerConfig::WindowManagerConfig() = default;
-WindowManagerConfig::~WindowManagerConfig() = default;
-WindowManagerConfig::WindowManagerConfig(const WindowManagerConfig&) = default;
-WindowManagerConfig& WindowManagerConfig::operator=(const WindowManagerConfig&) = default;
-WindowManagerConfig::WindowManagerConfig(WindowManagerConfig&&) noexcept = default;
-WindowManagerConfig& WindowManagerConfig::operator=(WindowManagerConfig&&) = default;
+TracingServiceCapabilities::TracingServiceCapabilities() = default;
+TracingServiceCapabilities::~TracingServiceCapabilities() = default;
+TracingServiceCapabilities::TracingServiceCapabilities(const TracingServiceCapabilities&) = default;
+TracingServiceCapabilities& TracingServiceCapabilities::operator=(const TracingServiceCapabilities&) = default;
+TracingServiceCapabilities::TracingServiceCapabilities(TracingServiceCapabilities&&) noexcept = default;
+TracingServiceCapabilities& TracingServiceCapabilities::operator=(TracingServiceCapabilities&&) = default;
-bool WindowManagerConfig::operator==(const WindowManagerConfig& other) const {
+bool TracingServiceCapabilities::operator==(const TracingServiceCapabilities& other) const {
return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
- && ::protozero::internal::gen_helpers::EqualsField(log_frequency_, other.log_frequency_)
- && ::protozero::internal::gen_helpers::EqualsField(log_level_, other.log_level_)
- && ::protozero::internal::gen_helpers::EqualsField(log_mode_, other.log_mode_);
+ && ::protozero::internal::gen_helpers::EqualsField(has_query_capabilities_, other.has_query_capabilities_)
+ && ::protozero::internal::gen_helpers::EqualsField(observable_events_, other.observable_events_)
+ && ::protozero::internal::gen_helpers::EqualsField(has_trace_config_output_path_, other.has_trace_config_output_path_)
+ && ::protozero::internal::gen_helpers::EqualsField(has_clone_session_, other.has_clone_session_);
}
-bool WindowManagerConfig::ParseFromArray(const void* raw, size_t size) {
+bool TracingServiceCapabilities::ParseFromArray(const void* raw, size_t size) {
+ observable_events_.clear();
unknown_fields_.clear();
bool packed_error = false;
@@ -23195,14 +23199,18 @@ bool WindowManagerConfig::ParseFromArray(const void* raw, size_t size) {
_has_field_.set(field.id());
}
switch (field.id()) {
- case 1 /* log_frequency */:
- field.get(&log_frequency_);
+ case 1 /* has_query_capabilities */:
+ field.get(&has_query_capabilities_);
break;
- case 2 /* log_level */:
- field.get(&log_level_);
+ case 2 /* observable_events */:
+ observable_events_.emplace_back();
+ field.get(&observable_events_.back());
break;
- case 3 /* log_mode */:
- field.get(&log_mode_);
+ case 3 /* has_trace_config_output_path */:
+ field.get(&has_trace_config_output_path_);
+ break;
+ case 4 /* has_clone_session */:
+ field.get(&has_clone_session_);
break;
default:
field.SerializeAndAppendTo(&unknown_fields_);
@@ -23212,32 +23220,37 @@ bool WindowManagerConfig::ParseFromArray(const void* raw, size_t size) {
return !packed_error && !dec.bytes_left();
}
-std::string WindowManagerConfig::SerializeAsString() const {
+std::string TracingServiceCapabilities::SerializeAsString() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsString();
}
-std::vector<uint8_t> WindowManagerConfig::SerializeAsArray() const {
+std::vector<uint8_t> TracingServiceCapabilities::SerializeAsArray() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsArray();
}
-void WindowManagerConfig::Serialize(::protozero::Message* msg) const {
- // Field 1: log_frequency
+void TracingServiceCapabilities::Serialize(::protozero::Message* msg) const {
+ // Field 1: has_query_capabilities
if (_has_field_[1]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(1, log_frequency_, msg);
+ ::protozero::internal::gen_helpers::SerializeTinyVarInt(1, has_query_capabilities_, msg);
}
- // Field 2: log_level
- if (_has_field_[2]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(2, log_level_, msg);
+ // Field 2: observable_events
+ for (auto& it : observable_events_) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(2, it, msg);
}
- // Field 3: log_mode
+ // Field 3: has_trace_config_output_path
if (_has_field_[3]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(3, log_mode_, msg);
+ ::protozero::internal::gen_helpers::SerializeTinyVarInt(3, has_trace_config_output_path_, msg);
+ }
+
+ // Field 4: has_clone_session
+ if (_has_field_[4]) {
+ ::protozero::internal::gen_helpers::SerializeTinyVarInt(4, has_clone_session_, msg);
}
protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
@@ -23249,7 +23262,7 @@ void WindowManagerConfig::Serialize(::protozero::Message* msg) const {
#if defined(__GNUC__) || defined(__clang__)
#pragma GCC diagnostic pop
#endif
-// gen_amalgamated begin source: gen/protos/perfetto/config/ftrace/frozen_ftrace_config.gen.cc
+// gen_amalgamated begin source: gen/protos/perfetto/common/tracing_service_state.gen.cc
// gen_amalgamated expanded: #include "perfetto/protozero/gen_field_helpers.h"
// gen_amalgamated expanded: #include "perfetto/protozero/message.h"
// gen_amalgamated expanded: #include "perfetto/protozero/packed_repeated_fields.h"
@@ -23260,25 +23273,48 @@ void WindowManagerConfig::Serialize(::protozero::Message* msg) const {
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wfloat-equal"
#endif
-// gen_amalgamated expanded: #include "protos/perfetto/config/ftrace/frozen_ftrace_config.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/common/tracing_service_state.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/common/data_source_descriptor.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/protovm/vm_program.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/common/track_event_descriptor.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/common/gpu_counter_descriptor.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/common/ftrace_descriptor.gen.h"
namespace perfetto {
namespace protos {
namespace gen {
-FrozenFtraceConfig::FrozenFtraceConfig() = default;
-FrozenFtraceConfig::~FrozenFtraceConfig() = default;
-FrozenFtraceConfig::FrozenFtraceConfig(const FrozenFtraceConfig&) = default;
-FrozenFtraceConfig& FrozenFtraceConfig::operator=(const FrozenFtraceConfig&) = default;
-FrozenFtraceConfig::FrozenFtraceConfig(FrozenFtraceConfig&&) noexcept = default;
-FrozenFtraceConfig& FrozenFtraceConfig::operator=(FrozenFtraceConfig&&) = default;
+TracingServiceState::TracingServiceState() = default;
+TracingServiceState::~TracingServiceState() = default;
+TracingServiceState::TracingServiceState(const TracingServiceState&) = default;
+TracingServiceState& TracingServiceState::operator=(const TracingServiceState&) = default;
+TracingServiceState::TracingServiceState(TracingServiceState&&) noexcept = default;
+TracingServiceState& TracingServiceState::operator=(TracingServiceState&&) = default;
-bool FrozenFtraceConfig::operator==(const FrozenFtraceConfig& other) const {
+bool TracingServiceState::operator==(const TracingServiceState& other) const {
return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
- && ::protozero::internal::gen_helpers::EqualsField(instance_name_, other.instance_name_);
+ && ::protozero::internal::gen_helpers::EqualsField(producers_, other.producers_)
+ && ::protozero::internal::gen_helpers::EqualsField(data_sources_, other.data_sources_)
+ && ::protozero::internal::gen_helpers::EqualsField(tracing_sessions_, other.tracing_sessions_)
+ && ::protozero::internal::gen_helpers::EqualsField(supports_tracing_sessions_, other.supports_tracing_sessions_)
+ && ::protozero::internal::gen_helpers::EqualsField(num_sessions_, other.num_sessions_)
+ && ::protozero::internal::gen_helpers::EqualsField(num_sessions_started_, other.num_sessions_started_)
+ && ::protozero::internal::gen_helpers::EqualsField(tracing_service_version_, other.tracing_service_version_);
}
-bool FrozenFtraceConfig::ParseFromArray(const void* raw, size_t size) {
+int TracingServiceState::producers_size() const { return static_cast<int>(producers_.size()); }
+void TracingServiceState::clear_producers() { producers_.clear(); }
+TracingServiceState_Producer* TracingServiceState::add_producers() { producers_.emplace_back(); return &producers_.back(); }
+int TracingServiceState::data_sources_size() const { return static_cast<int>(data_sources_.size()); }
+void TracingServiceState::clear_data_sources() { data_sources_.clear(); }
+TracingServiceState_DataSource* TracingServiceState::add_data_sources() { data_sources_.emplace_back(); return &data_sources_.back(); }
+int TracingServiceState::tracing_sessions_size() const { return static_cast<int>(tracing_sessions_.size()); }
+void TracingServiceState::clear_tracing_sessions() { tracing_sessions_.clear(); }
+TracingServiceState_TracingSession* TracingServiceState::add_tracing_sessions() { tracing_sessions_.emplace_back(); return &tracing_sessions_.back(); }
+bool TracingServiceState::ParseFromArray(const void* raw, size_t size) {
+ producers_.clear();
+ data_sources_.clear();
+ tracing_sessions_.clear();
unknown_fields_.clear();
bool packed_error = false;
@@ -23288,8 +23324,29 @@ bool FrozenFtraceConfig::ParseFromArray(const void* raw, size_t size) {
_has_field_.set(field.id());
}
switch (field.id()) {
- case 1 /* instance_name */:
- ::protozero::internal::gen_helpers::DeserializeString(field, &instance_name_);
+ case 1 /* producers */:
+ producers_.emplace_back();
+ producers_.back().ParseFromArray(field.data(), field.size());
+ break;
+ case 2 /* data_sources */:
+ data_sources_.emplace_back();
+ data_sources_.back().ParseFromArray(field.data(), field.size());
+ break;
+ case 6 /* tracing_sessions */:
+ tracing_sessions_.emplace_back();
+ tracing_sessions_.back().ParseFromArray(field.data(), field.size());
+ break;
+ case 7 /* supports_tracing_sessions */:
+ field.get(&supports_tracing_sessions_);
+ break;
+ case 3 /* num_sessions */:
+ field.get(&num_sessions_);
+ break;
+ case 4 /* num_sessions_started */:
+ field.get(&num_sessions_started_);
+ break;
+ case 5 /* tracing_service_version */:
+ ::protozero::internal::gen_helpers::DeserializeString(field, &tracing_service_version_);
break;
default:
field.SerializeAndAppendTo(&unknown_fields_);
@@ -23299,108 +23356,82 @@ bool FrozenFtraceConfig::ParseFromArray(const void* raw, size_t size) {
return !packed_error && !dec.bytes_left();
}
-std::string FrozenFtraceConfig::SerializeAsString() const {
+std::string TracingServiceState::SerializeAsString() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsString();
}
-std::vector<uint8_t> FrozenFtraceConfig::SerializeAsArray() const {
+std::vector<uint8_t> TracingServiceState::SerializeAsArray() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsArray();
}
-void FrozenFtraceConfig::Serialize(::protozero::Message* msg) const {
- // Field 1: instance_name
- if (_has_field_[1]) {
- ::protozero::internal::gen_helpers::SerializeString(1, instance_name_, msg);
+void TracingServiceState::Serialize(::protozero::Message* msg) const {
+ // Field 1: producers
+ for (auto& it : producers_) {
+ it.Serialize(msg->BeginNestedMessage<::protozero::Message>(1));
+ }
+
+ // Field 2: data_sources
+ for (auto& it : data_sources_) {
+ it.Serialize(msg->BeginNestedMessage<::protozero::Message>(2));
+ }
+
+ // Field 6: tracing_sessions
+ for (auto& it : tracing_sessions_) {
+ it.Serialize(msg->BeginNestedMessage<::protozero::Message>(6));
+ }
+
+ // Field 7: supports_tracing_sessions
+ if (_has_field_[7]) {
+ ::protozero::internal::gen_helpers::SerializeTinyVarInt(7, supports_tracing_sessions_, msg);
+ }
+
+ // Field 3: num_sessions
+ if (_has_field_[3]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(3, num_sessions_, msg);
+ }
+
+ // Field 4: num_sessions_started
+ if (_has_field_[4]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(4, num_sessions_started_, msg);
+ }
+
+ // Field 5: tracing_service_version
+ if (_has_field_[5]) {
+ ::protozero::internal::gen_helpers::SerializeString(5, tracing_service_version_, msg);
}
protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
}
-} // namespace perfetto
-} // namespace protos
-} // namespace gen
-#if defined(__GNUC__) || defined(__clang__)
-#pragma GCC diagnostic pop
-#endif
-// gen_amalgamated begin source: gen/protos/perfetto/config/ftrace/ftrace_config.gen.cc
-// gen_amalgamated expanded: #include "perfetto/protozero/gen_field_helpers.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/message.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/packed_repeated_fields.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/proto_decoder.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/scattered_heap_buffer.h"
-// DO NOT EDIT. Autogenerated by Perfetto cppgen_plugin
-#if defined(__GNUC__) || defined(__clang__)
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wfloat-equal"
-#endif
-// gen_amalgamated expanded: #include "protos/perfetto/config/ftrace/ftrace_config.gen.h"
-
-namespace perfetto {
-namespace protos {
-namespace gen {
-FtraceConfig::FtraceConfig() = default;
-FtraceConfig::~FtraceConfig() = default;
-FtraceConfig::FtraceConfig(const FtraceConfig&) = default;
-FtraceConfig& FtraceConfig::operator=(const FtraceConfig&) = default;
-FtraceConfig::FtraceConfig(FtraceConfig&&) noexcept = default;
-FtraceConfig& FtraceConfig::operator=(FtraceConfig&&) = default;
+TracingServiceState_TracingSession::TracingServiceState_TracingSession() = default;
+TracingServiceState_TracingSession::~TracingServiceState_TracingSession() = default;
+TracingServiceState_TracingSession::TracingServiceState_TracingSession(const TracingServiceState_TracingSession&) = default;
+TracingServiceState_TracingSession& TracingServiceState_TracingSession::operator=(const TracingServiceState_TracingSession&) = default;
+TracingServiceState_TracingSession::TracingServiceState_TracingSession(TracingServiceState_TracingSession&&) noexcept = default;
+TracingServiceState_TracingSession& TracingServiceState_TracingSession::operator=(TracingServiceState_TracingSession&&) = default;
-bool FtraceConfig::operator==(const FtraceConfig& other) const {
+bool TracingServiceState_TracingSession::operator==(const TracingServiceState_TracingSession& other) const {
return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
- && ::protozero::internal::gen_helpers::EqualsField(ftrace_events_, other.ftrace_events_)
- && ::protozero::internal::gen_helpers::EqualsField(atrace_categories_, other.atrace_categories_)
- && ::protozero::internal::gen_helpers::EqualsField(atrace_apps_, other.atrace_apps_)
- && ::protozero::internal::gen_helpers::EqualsField(atrace_categories_prefer_sdk_, other.atrace_categories_prefer_sdk_)
- && ::protozero::internal::gen_helpers::EqualsField(atrace_userspace_only_, other.atrace_userspace_only_)
+ && ::protozero::internal::gen_helpers::EqualsField(id_, other.id_)
+ && ::protozero::internal::gen_helpers::EqualsField(consumer_uid_, other.consumer_uid_)
+ && ::protozero::internal::gen_helpers::EqualsField(state_, other.state_)
+ && ::protozero::internal::gen_helpers::EqualsField(unique_session_name_, other.unique_session_name_)
&& ::protozero::internal::gen_helpers::EqualsField(buffer_size_kb_, other.buffer_size_kb_)
- && ::protozero::internal::gen_helpers::EqualsField(buffer_size_lower_bound_, other.buffer_size_lower_bound_)
- && ::protozero::internal::gen_helpers::EqualsField(drain_period_ms_, other.drain_period_ms_)
- && ::protozero::internal::gen_helpers::EqualsField(drain_buffer_percent_, other.drain_buffer_percent_)
- && ::protozero::internal::gen_helpers::EqualsField(compact_sched_, other.compact_sched_)
- && ::protozero::internal::gen_helpers::EqualsField(print_filter_, other.print_filter_)
- && ::protozero::internal::gen_helpers::EqualsField(symbolize_ksyms_, other.symbolize_ksyms_)
- && ::protozero::internal::gen_helpers::EqualsField(ksyms_mem_policy_, other.ksyms_mem_policy_)
- && ::protozero::internal::gen_helpers::EqualsField(throttle_rss_stat_, other.throttle_rss_stat_)
- && ::protozero::internal::gen_helpers::EqualsField(denser_generic_event_encoding_, other.denser_generic_event_encoding_)
- && ::protozero::internal::gen_helpers::EqualsField(disable_generic_events_, other.disable_generic_events_)
- && ::protozero::internal::gen_helpers::EqualsField(syscall_events_, other.syscall_events_)
- && ::protozero::internal::gen_helpers::EqualsField(enable_function_graph_, other.enable_function_graph_)
- && ::protozero::internal::gen_helpers::EqualsField(function_filters_, other.function_filters_)
- && ::protozero::internal::gen_helpers::EqualsField(function_graph_roots_, other.function_graph_roots_)
- && ::protozero::internal::gen_helpers::EqualsField(function_graph_max_depth_, other.function_graph_max_depth_)
- && ::protozero::internal::gen_helpers::EqualsField(kprobe_events_, other.kprobe_events_)
- && ::protozero::internal::gen_helpers::EqualsField(preserve_ftrace_buffer_, other.preserve_ftrace_buffer_)
- && ::protozero::internal::gen_helpers::EqualsField(use_monotonic_raw_clock_, other.use_monotonic_raw_clock_)
- && ::protozero::internal::gen_helpers::EqualsField(instance_name_, other.instance_name_)
- && ::protozero::internal::gen_helpers::EqualsField(debug_ftrace_abi_, other.debug_ftrace_abi_)
- && ::protozero::internal::gen_helpers::EqualsField(tids_to_trace_, other.tids_to_trace_)
- && ::protozero::internal::gen_helpers::EqualsField(tracefs_options_, other.tracefs_options_)
- && ::protozero::internal::gen_helpers::EqualsField(tracing_cpumask_, other.tracing_cpumask_)
- && ::protozero::internal::gen_helpers::EqualsField(initialize_ksyms_synchronously_for_testing_, other.initialize_ksyms_synchronously_for_testing_);
+ && ::protozero::internal::gen_helpers::EqualsField(duration_ms_, other.duration_ms_)
+ && ::protozero::internal::gen_helpers::EqualsField(num_data_sources_, other.num_data_sources_)
+ && ::protozero::internal::gen_helpers::EqualsField(start_realtime_ns_, other.start_realtime_ns_)
+ && ::protozero::internal::gen_helpers::EqualsField(bugreport_score_, other.bugreport_score_)
+ && ::protozero::internal::gen_helpers::EqualsField(bugreport_filename_, other.bugreport_filename_)
+ && ::protozero::internal::gen_helpers::EqualsField(is_started_, other.is_started_);
}
-int FtraceConfig::kprobe_events_size() const { return static_cast<int>(kprobe_events_.size()); }
-void FtraceConfig::clear_kprobe_events() { kprobe_events_.clear(); }
-FtraceConfig_KprobeEvent* FtraceConfig::add_kprobe_events() { kprobe_events_.emplace_back(); return &kprobe_events_.back(); }
-int FtraceConfig::tracefs_options_size() const { return static_cast<int>(tracefs_options_.size()); }
-void FtraceConfig::clear_tracefs_options() { tracefs_options_.clear(); }
-FtraceConfig_TracefsOption* FtraceConfig::add_tracefs_options() { tracefs_options_.emplace_back(); return &tracefs_options_.back(); }
-bool FtraceConfig::ParseFromArray(const void* raw, size_t size) {
- ftrace_events_.clear();
- atrace_categories_.clear();
- atrace_apps_.clear();
- atrace_categories_prefer_sdk_.clear();
- syscall_events_.clear();
- function_filters_.clear();
- function_graph_roots_.clear();
- kprobe_events_.clear();
- tids_to_trace_.clear();
- tracefs_options_.clear();
+bool TracingServiceState_TracingSession::ParseFromArray(const void* raw, size_t size) {
+ buffer_size_kb_.clear();
unknown_fields_.clear();
bool packed_error = false;
@@ -23410,295 +23441,134 @@ bool FtraceConfig::ParseFromArray(const void* raw, size_t size) {
_has_field_.set(field.id());
}
switch (field.id()) {
- case 1 /* ftrace_events */:
- ftrace_events_.emplace_back();
- ::protozero::internal::gen_helpers::DeserializeString(field, &ftrace_events_.back());
- break;
- case 2 /* atrace_categories */:
- atrace_categories_.emplace_back();
- ::protozero::internal::gen_helpers::DeserializeString(field, &atrace_categories_.back());
- break;
- case 3 /* atrace_apps */:
- atrace_apps_.emplace_back();
- ::protozero::internal::gen_helpers::DeserializeString(field, &atrace_apps_.back());
- break;
- case 28 /* atrace_categories_prefer_sdk */:
- atrace_categories_prefer_sdk_.emplace_back();
- ::protozero::internal::gen_helpers::DeserializeString(field, &atrace_categories_prefer_sdk_.back());
- break;
- case 34 /* atrace_userspace_only */:
- field.get(&atrace_userspace_only_);
- break;
- case 10 /* buffer_size_kb */:
- field.get(&buffer_size_kb_);
- break;
- case 27 /* buffer_size_lower_bound */:
- field.get(&buffer_size_lower_bound_);
- break;
- case 11 /* drain_period_ms */:
- field.get(&drain_period_ms_);
- break;
- case 29 /* drain_buffer_percent */:
- field.get(&drain_buffer_percent_);
- break;
- case 12 /* compact_sched */:
- (*compact_sched_).ParseFromArray(field.data(), field.size());
- break;
- case 22 /* print_filter */:
- (*print_filter_).ParseFromArray(field.data(), field.size());
- break;
- case 13 /* symbolize_ksyms */:
- field.get(&symbolize_ksyms_);
+ case 1 /* id */:
+ field.get(&id_);
break;
- case 17 /* ksyms_mem_policy */:
- field.get(&ksyms_mem_policy_);
+ case 2 /* consumer_uid */:
+ field.get(&consumer_uid_);
break;
- case 15 /* throttle_rss_stat */:
- field.get(&throttle_rss_stat_);
+ case 3 /* state */:
+ ::protozero::internal::gen_helpers::DeserializeString(field, &state_);
break;
- case 32 /* denser_generic_event_encoding */:
- field.get(&denser_generic_event_encoding_);
+ case 4 /* unique_session_name */:
+ ::protozero::internal::gen_helpers::DeserializeString(field, &unique_session_name_);
break;
- case 16 /* disable_generic_events */:
- field.get(&disable_generic_events_);
+ case 5 /* buffer_size_kb */:
+ buffer_size_kb_.emplace_back();
+ field.get(&buffer_size_kb_.back());
break;
- case 18 /* syscall_events */:
- syscall_events_.emplace_back();
- ::protozero::internal::gen_helpers::DeserializeString(field, &syscall_events_.back());
+ case 6 /* duration_ms */:
+ field.get(&duration_ms_);
break;
- case 19 /* enable_function_graph */:
- field.get(&enable_function_graph_);
+ case 7 /* num_data_sources */:
+ field.get(&num_data_sources_);
break;
- case 20 /* function_filters */:
- function_filters_.emplace_back();
- ::protozero::internal::gen_helpers::DeserializeString(field, &function_filters_.back());
+ case 8 /* start_realtime_ns */:
+ field.get(&start_realtime_ns_);
break;
- case 21 /* function_graph_roots */:
- function_graph_roots_.emplace_back();
- ::protozero::internal::gen_helpers::DeserializeString(field, &function_graph_roots_.back());
+ case 9 /* bugreport_score */:
+ field.get(&bugreport_score_);
break;
- case 33 /* function_graph_max_depth */:
- field.get(&function_graph_max_depth_);
+ case 10 /* bugreport_filename */:
+ ::protozero::internal::gen_helpers::DeserializeString(field, &bugreport_filename_);
break;
- case 30 /* kprobe_events */:
- kprobe_events_.emplace_back();
- kprobe_events_.back().ParseFromArray(field.data(), field.size());
+ case 11 /* is_started */:
+ field.get(&is_started_);
break;
- case 23 /* preserve_ftrace_buffer */:
- field.get(&preserve_ftrace_buffer_);
- break;
- case 24 /* use_monotonic_raw_clock */:
- field.get(&use_monotonic_raw_clock_);
- break;
- case 25 /* instance_name */:
- ::protozero::internal::gen_helpers::DeserializeString(field, &instance_name_);
- break;
- case 31 /* debug_ftrace_abi */:
- field.get(&debug_ftrace_abi_);
- break;
- case 35 /* tids_to_trace */:
- tids_to_trace_.emplace_back();
- field.get(&tids_to_trace_.back());
- break;
- case 36 /* tracefs_options */:
- tracefs_options_.emplace_back();
- tracefs_options_.back().ParseFromArray(field.data(), field.size());
- break;
- case 37 /* tracing_cpumask */:
- ::protozero::internal::gen_helpers::DeserializeString(field, &tracing_cpumask_);
- break;
- case 14 /* initialize_ksyms_synchronously_for_testing */:
- field.get(&initialize_ksyms_synchronously_for_testing_);
- break;
- default:
- field.SerializeAndAppendTo(&unknown_fields_);
+ default:
+ field.SerializeAndAppendTo(&unknown_fields_);
break;
}
}
return !packed_error && !dec.bytes_left();
}
-std::string FtraceConfig::SerializeAsString() const {
+std::string TracingServiceState_TracingSession::SerializeAsString() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsString();
}
-std::vector<uint8_t> FtraceConfig::SerializeAsArray() const {
+std::vector<uint8_t> TracingServiceState_TracingSession::SerializeAsArray() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsArray();
}
-void FtraceConfig::Serialize(::protozero::Message* msg) const {
- // Field 1: ftrace_events
- for (auto& it : ftrace_events_) {
- ::protozero::internal::gen_helpers::SerializeString(1, it, msg);
- }
-
- // Field 2: atrace_categories
- for (auto& it : atrace_categories_) {
- ::protozero::internal::gen_helpers::SerializeString(2, it, msg);
- }
-
- // Field 3: atrace_apps
- for (auto& it : atrace_apps_) {
- ::protozero::internal::gen_helpers::SerializeString(3, it, msg);
- }
-
- // Field 28: atrace_categories_prefer_sdk
- for (auto& it : atrace_categories_prefer_sdk_) {
- ::protozero::internal::gen_helpers::SerializeString(28, it, msg);
- }
-
- // Field 34: atrace_userspace_only
- if (_has_field_[34]) {
- ::protozero::internal::gen_helpers::SerializeTinyVarInt(34, atrace_userspace_only_, msg);
- }
-
- // Field 10: buffer_size_kb
- if (_has_field_[10]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(10, buffer_size_kb_, msg);
- }
-
- // Field 27: buffer_size_lower_bound
- if (_has_field_[27]) {
- ::protozero::internal::gen_helpers::SerializeTinyVarInt(27, buffer_size_lower_bound_, msg);
- }
-
- // Field 11: drain_period_ms
- if (_has_field_[11]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(11, drain_period_ms_, msg);
- }
-
- // Field 29: drain_buffer_percent
- if (_has_field_[29]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(29, drain_buffer_percent_, msg);
- }
-
- // Field 12: compact_sched
- if (_has_field_[12]) {
- (*compact_sched_).Serialize(msg->BeginNestedMessage<::protozero::Message>(12));
- }
-
- // Field 22: print_filter
- if (_has_field_[22]) {
- (*print_filter_).Serialize(msg->BeginNestedMessage<::protozero::Message>(22));
- }
-
- // Field 13: symbolize_ksyms
- if (_has_field_[13]) {
- ::protozero::internal::gen_helpers::SerializeTinyVarInt(13, symbolize_ksyms_, msg);
- }
-
- // Field 17: ksyms_mem_policy
- if (_has_field_[17]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(17, ksyms_mem_policy_, msg);
- }
-
- // Field 15: throttle_rss_stat
- if (_has_field_[15]) {
- ::protozero::internal::gen_helpers::SerializeTinyVarInt(15, throttle_rss_stat_, msg);
- }
-
- // Field 32: denser_generic_event_encoding
- if (_has_field_[32]) {
- ::protozero::internal::gen_helpers::SerializeTinyVarInt(32, denser_generic_event_encoding_, msg);
- }
-
- // Field 16: disable_generic_events
- if (_has_field_[16]) {
- ::protozero::internal::gen_helpers::SerializeTinyVarInt(16, disable_generic_events_, msg);
- }
-
- // Field 18: syscall_events
- for (auto& it : syscall_events_) {
- ::protozero::internal::gen_helpers::SerializeString(18, it, msg);
- }
-
- // Field 19: enable_function_graph
- if (_has_field_[19]) {
- ::protozero::internal::gen_helpers::SerializeTinyVarInt(19, enable_function_graph_, msg);
- }
-
- // Field 20: function_filters
- for (auto& it : function_filters_) {
- ::protozero::internal::gen_helpers::SerializeString(20, it, msg);
- }
-
- // Field 21: function_graph_roots
- for (auto& it : function_graph_roots_) {
- ::protozero::internal::gen_helpers::SerializeString(21, it, msg);
+void TracingServiceState_TracingSession::Serialize(::protozero::Message* msg) const {
+ // Field 1: id
+ if (_has_field_[1]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(1, id_, msg);
}
- // Field 33: function_graph_max_depth
- if (_has_field_[33]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(33, function_graph_max_depth_, msg);
+ // Field 2: consumer_uid
+ if (_has_field_[2]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(2, consumer_uid_, msg);
}
- // Field 30: kprobe_events
- for (auto& it : kprobe_events_) {
- it.Serialize(msg->BeginNestedMessage<::protozero::Message>(30));
+ // Field 3: state
+ if (_has_field_[3]) {
+ ::protozero::internal::gen_helpers::SerializeString(3, state_, msg);
}
- // Field 23: preserve_ftrace_buffer
- if (_has_field_[23]) {
- ::protozero::internal::gen_helpers::SerializeTinyVarInt(23, preserve_ftrace_buffer_, msg);
+ // Field 4: unique_session_name
+ if (_has_field_[4]) {
+ ::protozero::internal::gen_helpers::SerializeString(4, unique_session_name_, msg);
}
- // Field 24: use_monotonic_raw_clock
- if (_has_field_[24]) {
- ::protozero::internal::gen_helpers::SerializeTinyVarInt(24, use_monotonic_raw_clock_, msg);
+ // Field 5: buffer_size_kb
+ for (auto& it : buffer_size_kb_) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(5, it, msg);
}
- // Field 25: instance_name
- if (_has_field_[25]) {
- ::protozero::internal::gen_helpers::SerializeString(25, instance_name_, msg);
+ // Field 6: duration_ms
+ if (_has_field_[6]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(6, duration_ms_, msg);
}
- // Field 31: debug_ftrace_abi
- if (_has_field_[31]) {
- ::protozero::internal::gen_helpers::SerializeTinyVarInt(31, debug_ftrace_abi_, msg);
+ // Field 7: num_data_sources
+ if (_has_field_[7]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(7, num_data_sources_, msg);
}
- // Field 35: tids_to_trace
- for (auto& it : tids_to_trace_) {
- ::protozero::internal::gen_helpers::SerializeVarInt(35, it, msg);
+ // Field 8: start_realtime_ns
+ if (_has_field_[8]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(8, start_realtime_ns_, msg);
}
- // Field 36: tracefs_options
- for (auto& it : tracefs_options_) {
- it.Serialize(msg->BeginNestedMessage<::protozero::Message>(36));
+ // Field 9: bugreport_score
+ if (_has_field_[9]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(9, bugreport_score_, msg);
}
- // Field 37: tracing_cpumask
- if (_has_field_[37]) {
- ::protozero::internal::gen_helpers::SerializeString(37, tracing_cpumask_, msg);
+ // Field 10: bugreport_filename
+ if (_has_field_[10]) {
+ ::protozero::internal::gen_helpers::SerializeString(10, bugreport_filename_, msg);
}
- // Field 14: initialize_ksyms_synchronously_for_testing
- if (_has_field_[14]) {
- ::protozero::internal::gen_helpers::SerializeTinyVarInt(14, initialize_ksyms_synchronously_for_testing_, msg);
+ // Field 11: is_started
+ if (_has_field_[11]) {
+ ::protozero::internal::gen_helpers::SerializeTinyVarInt(11, is_started_, msg);
}
protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
}
-FtraceConfig_TracefsOption::FtraceConfig_TracefsOption() = default;
-FtraceConfig_TracefsOption::~FtraceConfig_TracefsOption() = default;
-FtraceConfig_TracefsOption::FtraceConfig_TracefsOption(const FtraceConfig_TracefsOption&) = default;
-FtraceConfig_TracefsOption& FtraceConfig_TracefsOption::operator=(const FtraceConfig_TracefsOption&) = default;
-FtraceConfig_TracefsOption::FtraceConfig_TracefsOption(FtraceConfig_TracefsOption&&) noexcept = default;
-FtraceConfig_TracefsOption& FtraceConfig_TracefsOption::operator=(FtraceConfig_TracefsOption&&) = default;
+TracingServiceState_DataSource::TracingServiceState_DataSource() = default;
+TracingServiceState_DataSource::~TracingServiceState_DataSource() = default;
+TracingServiceState_DataSource::TracingServiceState_DataSource(const TracingServiceState_DataSource&) = default;
+TracingServiceState_DataSource& TracingServiceState_DataSource::operator=(const TracingServiceState_DataSource&) = default;
+TracingServiceState_DataSource::TracingServiceState_DataSource(TracingServiceState_DataSource&&) noexcept = default;
+TracingServiceState_DataSource& TracingServiceState_DataSource::operator=(TracingServiceState_DataSource&&) = default;
-bool FtraceConfig_TracefsOption::operator==(const FtraceConfig_TracefsOption& other) const {
+bool TracingServiceState_DataSource::operator==(const TracingServiceState_DataSource& other) const {
return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
- && ::protozero::internal::gen_helpers::EqualsField(name_, other.name_)
- && ::protozero::internal::gen_helpers::EqualsField(state_, other.state_);
+ && ::protozero::internal::gen_helpers::EqualsField(ds_descriptor_, other.ds_descriptor_)
+ && ::protozero::internal::gen_helpers::EqualsField(producer_id_, other.producer_id_);
}
-bool FtraceConfig_TracefsOption::ParseFromArray(const void* raw, size_t size) {
+bool TracingServiceState_DataSource::ParseFromArray(const void* raw, size_t size) {
unknown_fields_.clear();
bool packed_error = false;
@@ -23708,11 +23578,11 @@ bool FtraceConfig_TracefsOption::ParseFromArray(const void* raw, size_t size) {
_has_field_.set(field.id());
}
switch (field.id()) {
- case 1 /* name */:
- ::protozero::internal::gen_helpers::DeserializeString(field, &name_);
+ case 1 /* ds_descriptor */:
+ (*ds_descriptor_).ParseFromArray(field.data(), field.size());
break;
- case 2 /* state */:
- field.get(&state_);
+ case 2 /* producer_id */:
+ field.get(&producer_id_);
break;
default:
field.SerializeAndAppendTo(&unknown_fields_);
@@ -23722,47 +23592,53 @@ bool FtraceConfig_TracefsOption::ParseFromArray(const void* raw, size_t size) {
return !packed_error && !dec.bytes_left();
}
-std::string FtraceConfig_TracefsOption::SerializeAsString() const {
+std::string TracingServiceState_DataSource::SerializeAsString() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsString();
}
-std::vector<uint8_t> FtraceConfig_TracefsOption::SerializeAsArray() const {
+std::vector<uint8_t> TracingServiceState_DataSource::SerializeAsArray() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsArray();
}
-void FtraceConfig_TracefsOption::Serialize(::protozero::Message* msg) const {
- // Field 1: name
+void TracingServiceState_DataSource::Serialize(::protozero::Message* msg) const {
+ // Field 1: ds_descriptor
if (_has_field_[1]) {
- ::protozero::internal::gen_helpers::SerializeString(1, name_, msg);
+ (*ds_descriptor_).Serialize(msg->BeginNestedMessage<::protozero::Message>(1));
}
- // Field 2: state
+ // Field 2: producer_id
if (_has_field_[2]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(2, state_, msg);
+ ::protozero::internal::gen_helpers::SerializeVarInt(2, producer_id_, msg);
}
protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
}
-FtraceConfig_KprobeEvent::FtraceConfig_KprobeEvent() = default;
-FtraceConfig_KprobeEvent::~FtraceConfig_KprobeEvent() = default;
-FtraceConfig_KprobeEvent::FtraceConfig_KprobeEvent(const FtraceConfig_KprobeEvent&) = default;
-FtraceConfig_KprobeEvent& FtraceConfig_KprobeEvent::operator=(const FtraceConfig_KprobeEvent&) = default;
-FtraceConfig_KprobeEvent::FtraceConfig_KprobeEvent(FtraceConfig_KprobeEvent&&) noexcept = default;
-FtraceConfig_KprobeEvent& FtraceConfig_KprobeEvent::operator=(FtraceConfig_KprobeEvent&&) = default;
+TracingServiceState_Producer::TracingServiceState_Producer() = default;
+TracingServiceState_Producer::~TracingServiceState_Producer() = default;
+TracingServiceState_Producer::TracingServiceState_Producer(const TracingServiceState_Producer&) = default;
+TracingServiceState_Producer& TracingServiceState_Producer::operator=(const TracingServiceState_Producer&) = default;
+TracingServiceState_Producer::TracingServiceState_Producer(TracingServiceState_Producer&&) noexcept = default;
+TracingServiceState_Producer& TracingServiceState_Producer::operator=(TracingServiceState_Producer&&) = default;
-bool FtraceConfig_KprobeEvent::operator==(const FtraceConfig_KprobeEvent& other) const {
+bool TracingServiceState_Producer::operator==(const TracingServiceState_Producer& other) const {
return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
- && ::protozero::internal::gen_helpers::EqualsField(probe_, other.probe_)
- && ::protozero::internal::gen_helpers::EqualsField(type_, other.type_);
+ && ::protozero::internal::gen_helpers::EqualsField(id_, other.id_)
+ && ::protozero::internal::gen_helpers::EqualsField(name_, other.name_)
+ && ::protozero::internal::gen_helpers::EqualsField(pid_, other.pid_)
+ && ::protozero::internal::gen_helpers::EqualsField(uid_, other.uid_)
+ && ::protozero::internal::gen_helpers::EqualsField(sdk_version_, other.sdk_version_)
+ && ::protozero::internal::gen_helpers::EqualsField(frozen_, other.frozen_)
+ && ::protozero::internal::gen_helpers::EqualsField(machine_id_, other.machine_id_)
+ && ::protozero::internal::gen_helpers::EqualsField(machine_name_, other.machine_name_);
}
-bool FtraceConfig_KprobeEvent::ParseFromArray(const void* raw, size_t size) {
+bool TracingServiceState_Producer::ParseFromArray(const void* raw, size_t size) {
unknown_fields_.clear();
bool packed_error = false;
@@ -23772,11 +23648,29 @@ bool FtraceConfig_KprobeEvent::ParseFromArray(const void* raw, size_t size) {
_has_field_.set(field.id());
}
switch (field.id()) {
- case 1 /* probe */:
- ::protozero::internal::gen_helpers::DeserializeString(field, &probe_);
+ case 1 /* id */:
+ field.get(&id_);
break;
- case 2 /* type */:
- field.get(&type_);
+ case 2 /* name */:
+ ::protozero::internal::gen_helpers::DeserializeString(field, &name_);
+ break;
+ case 5 /* pid */:
+ field.get(&pid_);
+ break;
+ case 3 /* uid */:
+ field.get(&uid_);
+ break;
+ case 4 /* sdk_version */:
+ ::protozero::internal::gen_helpers::DeserializeString(field, &sdk_version_);
+ break;
+ case 6 /* frozen */:
+ field.get(&frozen_);
+ break;
+ case 7 /* machine_id */:
+ field.get(&machine_id_);
+ break;
+ case 8 /* machine_name */:
+ ::protozero::internal::gen_helpers::DeserializeString(field, &machine_name_);
break;
default:
field.SerializeAndAppendTo(&unknown_fields_);
@@ -23786,108 +23680,102 @@ bool FtraceConfig_KprobeEvent::ParseFromArray(const void* raw, size_t size) {
return !packed_error && !dec.bytes_left();
}
-std::string FtraceConfig_KprobeEvent::SerializeAsString() const {
+std::string TracingServiceState_Producer::SerializeAsString() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsString();
}
-std::vector<uint8_t> FtraceConfig_KprobeEvent::SerializeAsArray() const {
+std::vector<uint8_t> TracingServiceState_Producer::SerializeAsArray() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsArray();
}
-void FtraceConfig_KprobeEvent::Serialize(::protozero::Message* msg) const {
- // Field 1: probe
+void TracingServiceState_Producer::Serialize(::protozero::Message* msg) const {
+ // Field 1: id
if (_has_field_[1]) {
- ::protozero::internal::gen_helpers::SerializeString(1, probe_, msg);
+ ::protozero::internal::gen_helpers::SerializeVarInt(1, id_, msg);
}
- // Field 2: type
+ // Field 2: name
if (_has_field_[2]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(2, type_, msg);
+ ::protozero::internal::gen_helpers::SerializeString(2, name_, msg);
}
- protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
-}
-
-
-FtraceConfig_PrintFilter::FtraceConfig_PrintFilter() = default;
-FtraceConfig_PrintFilter::~FtraceConfig_PrintFilter() = default;
-FtraceConfig_PrintFilter::FtraceConfig_PrintFilter(const FtraceConfig_PrintFilter&) = default;
-FtraceConfig_PrintFilter& FtraceConfig_PrintFilter::operator=(const FtraceConfig_PrintFilter&) = default;
-FtraceConfig_PrintFilter::FtraceConfig_PrintFilter(FtraceConfig_PrintFilter&&) noexcept = default;
-FtraceConfig_PrintFilter& FtraceConfig_PrintFilter::operator=(FtraceConfig_PrintFilter&&) = default;
-
-bool FtraceConfig_PrintFilter::operator==(const FtraceConfig_PrintFilter& other) const {
- return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
- && ::protozero::internal::gen_helpers::EqualsField(rules_, other.rules_);
-}
+ // Field 5: pid
+ if (_has_field_[5]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(5, pid_, msg);
+ }
-int FtraceConfig_PrintFilter::rules_size() const { return static_cast<int>(rules_.size()); }
-void FtraceConfig_PrintFilter::clear_rules() { rules_.clear(); }
-FtraceConfig_PrintFilter_Rule* FtraceConfig_PrintFilter::add_rules() { rules_.emplace_back(); return &rules_.back(); }
-bool FtraceConfig_PrintFilter::ParseFromArray(const void* raw, size_t size) {
- rules_.clear();
- unknown_fields_.clear();
- bool packed_error = false;
+ // Field 3: uid
+ if (_has_field_[3]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(3, uid_, msg);
+ }
- ::protozero::ProtoDecoder dec(raw, size);
- for (auto field = dec.ReadField(); field.valid(); field = dec.ReadField()) {
- if (field.id() < _has_field_.size()) {
- _has_field_.set(field.id());
- }
- switch (field.id()) {
- case 1 /* rules */:
- rules_.emplace_back();
- rules_.back().ParseFromArray(field.data(), field.size());
- break;
- default:
- field.SerializeAndAppendTo(&unknown_fields_);
- break;
- }
+ // Field 4: sdk_version
+ if (_has_field_[4]) {
+ ::protozero::internal::gen_helpers::SerializeString(4, sdk_version_, msg);
}
- return !packed_error && !dec.bytes_left();
-}
-std::string FtraceConfig_PrintFilter::SerializeAsString() const {
- ::protozero::internal::gen_helpers::MessageSerializer msg;
- Serialize(msg.get());
- return msg.SerializeAsString();
-}
+ // Field 6: frozen
+ if (_has_field_[6]) {
+ ::protozero::internal::gen_helpers::SerializeTinyVarInt(6, frozen_, msg);
+ }
-std::vector<uint8_t> FtraceConfig_PrintFilter::SerializeAsArray() const {
- ::protozero::internal::gen_helpers::MessageSerializer msg;
- Serialize(msg.get());
- return msg.SerializeAsArray();
-}
+ // Field 7: machine_id
+ if (_has_field_[7]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(7, machine_id_, msg);
+ }
-void FtraceConfig_PrintFilter::Serialize(::protozero::Message* msg) const {
- // Field 1: rules
- for (auto& it : rules_) {
- it.Serialize(msg->BeginNestedMessage<::protozero::Message>(1));
+ // Field 8: machine_name
+ if (_has_field_[8]) {
+ ::protozero::internal::gen_helpers::SerializeString(8, machine_name_, msg);
}
protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
}
+} // namespace perfetto
+} // namespace protos
+} // namespace gen
+#if defined(__GNUC__) || defined(__clang__)
+#pragma GCC diagnostic pop
+#endif
+// gen_amalgamated begin source: gen/protos/perfetto/common/track_event_descriptor.gen.cc
+// gen_amalgamated expanded: #include "perfetto/protozero/gen_field_helpers.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/message.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/packed_repeated_fields.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/proto_decoder.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/scattered_heap_buffer.h"
+// DO NOT EDIT. Autogenerated by Perfetto cppgen_plugin
+#if defined(__GNUC__) || defined(__clang__)
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wfloat-equal"
+#endif
+// gen_amalgamated expanded: #include "protos/perfetto/common/track_event_descriptor.gen.h"
+
+namespace perfetto {
+namespace protos {
+namespace gen {
-FtraceConfig_PrintFilter_Rule::FtraceConfig_PrintFilter_Rule() = default;
-FtraceConfig_PrintFilter_Rule::~FtraceConfig_PrintFilter_Rule() = default;
-FtraceConfig_PrintFilter_Rule::FtraceConfig_PrintFilter_Rule(const FtraceConfig_PrintFilter_Rule&) = default;
-FtraceConfig_PrintFilter_Rule& FtraceConfig_PrintFilter_Rule::operator=(const FtraceConfig_PrintFilter_Rule&) = default;
-FtraceConfig_PrintFilter_Rule::FtraceConfig_PrintFilter_Rule(FtraceConfig_PrintFilter_Rule&&) noexcept = default;
-FtraceConfig_PrintFilter_Rule& FtraceConfig_PrintFilter_Rule::operator=(FtraceConfig_PrintFilter_Rule&&) = default;
+TrackEventDescriptor::TrackEventDescriptor() = default;
+TrackEventDescriptor::~TrackEventDescriptor() = default;
+TrackEventDescriptor::TrackEventDescriptor(const TrackEventDescriptor&) = default;
+TrackEventDescriptor& TrackEventDescriptor::operator=(const TrackEventDescriptor&) = default;
+TrackEventDescriptor::TrackEventDescriptor(TrackEventDescriptor&&) noexcept = default;
+TrackEventDescriptor& TrackEventDescriptor::operator=(TrackEventDescriptor&&) = default;
-bool FtraceConfig_PrintFilter_Rule::operator==(const FtraceConfig_PrintFilter_Rule& other) const {
+bool TrackEventDescriptor::operator==(const TrackEventDescriptor& other) const {
return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
- && ::protozero::internal::gen_helpers::EqualsField(prefix_, other.prefix_)
- && ::protozero::internal::gen_helpers::EqualsField(atrace_msg_, other.atrace_msg_)
- && ::protozero::internal::gen_helpers::EqualsField(allow_, other.allow_);
+ && ::protozero::internal::gen_helpers::EqualsField(available_categories_, other.available_categories_);
}
-bool FtraceConfig_PrintFilter_Rule::ParseFromArray(const void* raw, size_t size) {
+int TrackEventDescriptor::available_categories_size() const { return static_cast<int>(available_categories_.size()); }
+void TrackEventDescriptor::clear_available_categories() { available_categories_.clear(); }
+TrackEventCategory* TrackEventDescriptor::add_available_categories() { available_categories_.emplace_back(); return &available_categories_.back(); }
+bool TrackEventDescriptor::ParseFromArray(const void* raw, size_t size) {
+ available_categories_.clear();
unknown_fields_.clear();
bool packed_error = false;
@@ -23897,14 +23785,9 @@ bool FtraceConfig_PrintFilter_Rule::ParseFromArray(const void* raw, size_t size)
_has_field_.set(field.id());
}
switch (field.id()) {
- case 1 /* prefix */:
- ::protozero::internal::gen_helpers::DeserializeString(field, &prefix_);
- break;
- case 3 /* atrace_msg */:
- (*atrace_msg_).ParseFromArray(field.data(), field.size());
- break;
- case 2 /* allow */:
- field.get(&allow_);
+ case 1 /* available_categories */:
+ available_categories_.emplace_back();
+ available_categories_.back().ParseFromArray(field.data(), field.size());
break;
default:
field.SerializeAndAppendTo(&unknown_fields_);
@@ -23914,52 +23797,44 @@ bool FtraceConfig_PrintFilter_Rule::ParseFromArray(const void* raw, size_t size)
return !packed_error && !dec.bytes_left();
}
-std::string FtraceConfig_PrintFilter_Rule::SerializeAsString() const {
+std::string TrackEventDescriptor::SerializeAsString() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsString();
}
-std::vector<uint8_t> FtraceConfig_PrintFilter_Rule::SerializeAsArray() const {
+std::vector<uint8_t> TrackEventDescriptor::SerializeAsArray() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsArray();
}
-void FtraceConfig_PrintFilter_Rule::Serialize(::protozero::Message* msg) const {
- // Field 1: prefix
- if (_has_field_[1]) {
- ::protozero::internal::gen_helpers::SerializeString(1, prefix_, msg);
- }
-
- // Field 3: atrace_msg
- if (_has_field_[3]) {
- (*atrace_msg_).Serialize(msg->BeginNestedMessage<::protozero::Message>(3));
- }
-
- // Field 2: allow
- if (_has_field_[2]) {
- ::protozero::internal::gen_helpers::SerializeTinyVarInt(2, allow_, msg);
+void TrackEventDescriptor::Serialize(::protozero::Message* msg) const {
+ // Field 1: available_categories
+ for (auto& it : available_categories_) {
+ it.Serialize(msg->BeginNestedMessage<::protozero::Message>(1));
}
protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
}
-FtraceConfig_PrintFilter_Rule_AtraceMessage::FtraceConfig_PrintFilter_Rule_AtraceMessage() = default;
-FtraceConfig_PrintFilter_Rule_AtraceMessage::~FtraceConfig_PrintFilter_Rule_AtraceMessage() = default;
-FtraceConfig_PrintFilter_Rule_AtraceMessage::FtraceConfig_PrintFilter_Rule_AtraceMessage(const FtraceConfig_PrintFilter_Rule_AtraceMessage&) = default;
-FtraceConfig_PrintFilter_Rule_AtraceMessage& FtraceConfig_PrintFilter_Rule_AtraceMessage::operator=(const FtraceConfig_PrintFilter_Rule_AtraceMessage&) = default;
-FtraceConfig_PrintFilter_Rule_AtraceMessage::FtraceConfig_PrintFilter_Rule_AtraceMessage(FtraceConfig_PrintFilter_Rule_AtraceMessage&&) noexcept = default;
-FtraceConfig_PrintFilter_Rule_AtraceMessage& FtraceConfig_PrintFilter_Rule_AtraceMessage::operator=(FtraceConfig_PrintFilter_Rule_AtraceMessage&&) = default;
+TrackEventCategory::TrackEventCategory() = default;
+TrackEventCategory::~TrackEventCategory() = default;
+TrackEventCategory::TrackEventCategory(const TrackEventCategory&) = default;
+TrackEventCategory& TrackEventCategory::operator=(const TrackEventCategory&) = default;
+TrackEventCategory::TrackEventCategory(TrackEventCategory&&) noexcept = default;
+TrackEventCategory& TrackEventCategory::operator=(TrackEventCategory&&) = default;
-bool FtraceConfig_PrintFilter_Rule_AtraceMessage::operator==(const FtraceConfig_PrintFilter_Rule_AtraceMessage& other) const {
+bool TrackEventCategory::operator==(const TrackEventCategory& other) const {
return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
- && ::protozero::internal::gen_helpers::EqualsField(type_, other.type_)
- && ::protozero::internal::gen_helpers::EqualsField(prefix_, other.prefix_);
+ && ::protozero::internal::gen_helpers::EqualsField(name_, other.name_)
+ && ::protozero::internal::gen_helpers::EqualsField(description_, other.description_)
+ && ::protozero::internal::gen_helpers::EqualsField(tags_, other.tags_);
}
-bool FtraceConfig_PrintFilter_Rule_AtraceMessage::ParseFromArray(const void* raw, size_t size) {
+bool TrackEventCategory::ParseFromArray(const void* raw, size_t size) {
+ tags_.clear();
unknown_fields_.clear();
bool packed_error = false;
@@ -23969,11 +23844,15 @@ bool FtraceConfig_PrintFilter_Rule_AtraceMessage::ParseFromArray(const void* raw
_has_field_.set(field.id());
}
switch (field.id()) {
- case 1 /* type */:
- ::protozero::internal::gen_helpers::DeserializeString(field, &type_);
+ case 1 /* name */:
+ ::protozero::internal::gen_helpers::DeserializeString(field, &name_);
break;
- case 2 /* prefix */:
- ::protozero::internal::gen_helpers::DeserializeString(field, &prefix_);
+ case 2 /* description */:
+ ::protozero::internal::gen_helpers::DeserializeString(field, &description_);
+ break;
+ case 3 /* tags */:
+ tags_.emplace_back();
+ ::protozero::internal::gen_helpers::DeserializeString(field, &tags_.back());
break;
default:
field.SerializeAndAppendTo(&unknown_fields_);
@@ -23983,46 +23862,95 @@ bool FtraceConfig_PrintFilter_Rule_AtraceMessage::ParseFromArray(const void* raw
return !packed_error && !dec.bytes_left();
}
-std::string FtraceConfig_PrintFilter_Rule_AtraceMessage::SerializeAsString() const {
+std::string TrackEventCategory::SerializeAsString() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsString();
}
-std::vector<uint8_t> FtraceConfig_PrintFilter_Rule_AtraceMessage::SerializeAsArray() const {
+std::vector<uint8_t> TrackEventCategory::SerializeAsArray() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsArray();
}
-void FtraceConfig_PrintFilter_Rule_AtraceMessage::Serialize(::protozero::Message* msg) const {
- // Field 1: type
+void TrackEventCategory::Serialize(::protozero::Message* msg) const {
+ // Field 1: name
if (_has_field_[1]) {
- ::protozero::internal::gen_helpers::SerializeString(1, type_, msg);
+ ::protozero::internal::gen_helpers::SerializeString(1, name_, msg);
}
- // Field 2: prefix
+ // Field 2: description
if (_has_field_[2]) {
- ::protozero::internal::gen_helpers::SerializeString(2, prefix_, msg);
+ ::protozero::internal::gen_helpers::SerializeString(2, description_, msg);
+ }
+
+ // Field 3: tags
+ for (auto& it : tags_) {
+ ::protozero::internal::gen_helpers::SerializeString(3, it, msg);
}
protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
}
+} // namespace perfetto
+} // namespace protos
+} // namespace gen
+#if defined(__GNUC__) || defined(__clang__)
+#pragma GCC diagnostic pop
+#endif
+// gen_amalgamated begin source: gen/protos/perfetto/common/semantic_type.gen.cc
+// gen_amalgamated expanded: #include "perfetto/protozero/gen_field_helpers.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/message.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/packed_repeated_fields.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/proto_decoder.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/scattered_heap_buffer.h"
+// DO NOT EDIT. Autogenerated by Perfetto cppgen_plugin
+#if defined(__GNUC__) || defined(__clang__)
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wfloat-equal"
+#endif
+// gen_amalgamated expanded: #include "protos/perfetto/common/semantic_type.gen.h"
-FtraceConfig_CompactSchedConfig::FtraceConfig_CompactSchedConfig() = default;
-FtraceConfig_CompactSchedConfig::~FtraceConfig_CompactSchedConfig() = default;
-FtraceConfig_CompactSchedConfig::FtraceConfig_CompactSchedConfig(const FtraceConfig_CompactSchedConfig&) = default;
-FtraceConfig_CompactSchedConfig& FtraceConfig_CompactSchedConfig::operator=(const FtraceConfig_CompactSchedConfig&) = default;
-FtraceConfig_CompactSchedConfig::FtraceConfig_CompactSchedConfig(FtraceConfig_CompactSchedConfig&&) noexcept = default;
-FtraceConfig_CompactSchedConfig& FtraceConfig_CompactSchedConfig::operator=(FtraceConfig_CompactSchedConfig&&) = default;
-
-bool FtraceConfig_CompactSchedConfig::operator==(const FtraceConfig_CompactSchedConfig& other) const {
+namespace perfetto {
+namespace protos {
+namespace gen {
+} // namespace perfetto
+} // namespace protos
+} // namespace gen
+#if defined(__GNUC__) || defined(__clang__)
+#pragma GCC diagnostic pop
+#endif
+// gen_amalgamated begin source: gen/protos/perfetto/config/android/android_aflags_config.gen.cc
+// gen_amalgamated expanded: #include "perfetto/protozero/gen_field_helpers.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/message.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/packed_repeated_fields.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/proto_decoder.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/scattered_heap_buffer.h"
+// DO NOT EDIT. Autogenerated by Perfetto cppgen_plugin
+#if defined(__GNUC__) || defined(__clang__)
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wfloat-equal"
+#endif
+// gen_amalgamated expanded: #include "protos/perfetto/config/android/android_aflags_config.gen.h"
+
+namespace perfetto {
+namespace protos {
+namespace gen {
+
+AndroidAflagsConfig::AndroidAflagsConfig() = default;
+AndroidAflagsConfig::~AndroidAflagsConfig() = default;
+AndroidAflagsConfig::AndroidAflagsConfig(const AndroidAflagsConfig&) = default;
+AndroidAflagsConfig& AndroidAflagsConfig::operator=(const AndroidAflagsConfig&) = default;
+AndroidAflagsConfig::AndroidAflagsConfig(AndroidAflagsConfig&&) noexcept = default;
+AndroidAflagsConfig& AndroidAflagsConfig::operator=(AndroidAflagsConfig&&) = default;
+
+bool AndroidAflagsConfig::operator==(const AndroidAflagsConfig& other) const {
return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
- && ::protozero::internal::gen_helpers::EqualsField(enabled_, other.enabled_);
+ && ::protozero::internal::gen_helpers::EqualsField(poll_ms_, other.poll_ms_);
}
-bool FtraceConfig_CompactSchedConfig::ParseFromArray(const void* raw, size_t size) {
+bool AndroidAflagsConfig::ParseFromArray(const void* raw, size_t size) {
unknown_fields_.clear();
bool packed_error = false;
@@ -24032,8 +23960,8 @@ bool FtraceConfig_CompactSchedConfig::ParseFromArray(const void* raw, size_t siz
_has_field_.set(field.id());
}
switch (field.id()) {
- case 1 /* enabled */:
- field.get(&enabled_);
+ case 1 /* poll_ms */:
+ field.get(&poll_ms_);
break;
default:
field.SerializeAndAppendTo(&unknown_fields_);
@@ -24043,22 +23971,22 @@ bool FtraceConfig_CompactSchedConfig::ParseFromArray(const void* raw, size_t siz
return !packed_error && !dec.bytes_left();
}
-std::string FtraceConfig_CompactSchedConfig::SerializeAsString() const {
+std::string AndroidAflagsConfig::SerializeAsString() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsString();
}
-std::vector<uint8_t> FtraceConfig_CompactSchedConfig::SerializeAsArray() const {
+std::vector<uint8_t> AndroidAflagsConfig::SerializeAsArray() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsArray();
}
-void FtraceConfig_CompactSchedConfig::Serialize(::protozero::Message* msg) const {
- // Field 1: enabled
+void AndroidAflagsConfig::Serialize(::protozero::Message* msg) const {
+ // Field 1: poll_ms
if (_has_field_[1]) {
- ::protozero::internal::gen_helpers::SerializeTinyVarInt(1, enabled_, msg);
+ ::protozero::internal::gen_helpers::SerializeVarInt(1, poll_ms_, msg);
}
protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
@@ -24070,7 +23998,7 @@ void FtraceConfig_CompactSchedConfig::Serialize(::protozero::Message* msg) const
#if defined(__GNUC__) || defined(__clang__)
#pragma GCC diagnostic pop
#endif
-// gen_amalgamated begin source: gen/protos/perfetto/config/gpu/gpu_counter_config.gen.cc
+// gen_amalgamated begin source: gen/protos/perfetto/config/android/android_game_intervention_list_config.gen.cc
// gen_amalgamated expanded: #include "perfetto/protozero/gen_field_helpers.h"
// gen_amalgamated expanded: #include "perfetto/protozero/message.h"
// gen_amalgamated expanded: #include "perfetto/protozero/packed_repeated_fields.h"
@@ -24081,32 +24009,26 @@ void FtraceConfig_CompactSchedConfig::Serialize(::protozero::Message* msg) const
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wfloat-equal"
#endif
-// gen_amalgamated expanded: #include "protos/perfetto/config/gpu/gpu_counter_config.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/config/android/android_game_intervention_list_config.gen.h"
namespace perfetto {
namespace protos {
namespace gen {
-GpuCounterConfig::GpuCounterConfig() = default;
-GpuCounterConfig::~GpuCounterConfig() = default;
-GpuCounterConfig::GpuCounterConfig(const GpuCounterConfig&) = default;
-GpuCounterConfig& GpuCounterConfig::operator=(const GpuCounterConfig&) = default;
-GpuCounterConfig::GpuCounterConfig(GpuCounterConfig&&) noexcept = default;
-GpuCounterConfig& GpuCounterConfig::operator=(GpuCounterConfig&&) = default;
+AndroidGameInterventionListConfig::AndroidGameInterventionListConfig() = default;
+AndroidGameInterventionListConfig::~AndroidGameInterventionListConfig() = default;
+AndroidGameInterventionListConfig::AndroidGameInterventionListConfig(const AndroidGameInterventionListConfig&) = default;
+AndroidGameInterventionListConfig& AndroidGameInterventionListConfig::operator=(const AndroidGameInterventionListConfig&) = default;
+AndroidGameInterventionListConfig::AndroidGameInterventionListConfig(AndroidGameInterventionListConfig&&) noexcept = default;
+AndroidGameInterventionListConfig& AndroidGameInterventionListConfig::operator=(AndroidGameInterventionListConfig&&) = default;
-bool GpuCounterConfig::operator==(const GpuCounterConfig& other) const {
+bool AndroidGameInterventionListConfig::operator==(const AndroidGameInterventionListConfig& other) const {
return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
- && ::protozero::internal::gen_helpers::EqualsField(counter_period_ns_, other.counter_period_ns_)
- && ::protozero::internal::gen_helpers::EqualsField(counter_ids_, other.counter_ids_)
- && ::protozero::internal::gen_helpers::EqualsField(counter_names_, other.counter_names_)
- && ::protozero::internal::gen_helpers::EqualsField(instrumented_sampling_, other.instrumented_sampling_)
- && ::protozero::internal::gen_helpers::EqualsField(instrumented_sampling_config_, other.instrumented_sampling_config_)
- && ::protozero::internal::gen_helpers::EqualsField(fix_gpu_clock_, other.fix_gpu_clock_);
+ && ::protozero::internal::gen_helpers::EqualsField(package_name_filter_, other.package_name_filter_);
}
-bool GpuCounterConfig::ParseFromArray(const void* raw, size_t size) {
- counter_ids_.clear();
- counter_names_.clear();
+bool AndroidGameInterventionListConfig::ParseFromArray(const void* raw, size_t size) {
+ package_name_filter_.clear();
unknown_fields_.clear();
bool packed_error = false;
@@ -24116,25 +24038,9 @@ bool GpuCounterConfig::ParseFromArray(const void* raw, size_t size) {
_has_field_.set(field.id());
}
switch (field.id()) {
- case 1 /* counter_period_ns */:
- field.get(&counter_period_ns_);
- break;
- case 2 /* counter_ids */:
- counter_ids_.emplace_back();
- field.get(&counter_ids_.back());
- break;
- case 6 /* counter_names */:
- counter_names_.emplace_back();
- ::protozero::internal::gen_helpers::DeserializeString(field, &counter_names_.back());
- break;
- case 3 /* instrumented_sampling */:
- field.get(&instrumented_sampling_);
- break;
- case 5 /* instrumented_sampling_config */:
- (*instrumented_sampling_config_).ParseFromArray(field.data(), field.size());
- break;
- case 4 /* fix_gpu_clock */:
- field.get(&fix_gpu_clock_);
+ case 1 /* package_name_filter */:
+ package_name_filter_.emplace_back();
+ ::protozero::internal::gen_helpers::DeserializeString(field, &package_name_filter_.back());
break;
default:
field.SerializeAndAppendTo(&unknown_fields_);
@@ -24144,79 +24050,71 @@ bool GpuCounterConfig::ParseFromArray(const void* raw, size_t size) {
return !packed_error && !dec.bytes_left();
}
-std::string GpuCounterConfig::SerializeAsString() const {
+std::string AndroidGameInterventionListConfig::SerializeAsString() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsString();
}
-std::vector<uint8_t> GpuCounterConfig::SerializeAsArray() const {
+std::vector<uint8_t> AndroidGameInterventionListConfig::SerializeAsArray() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsArray();
}
-void GpuCounterConfig::Serialize(::protozero::Message* msg) const {
- // Field 1: counter_period_ns
- if (_has_field_[1]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(1, counter_period_ns_, msg);
- }
-
- // Field 2: counter_ids
- for (auto& it : counter_ids_) {
- ::protozero::internal::gen_helpers::SerializeVarInt(2, it, msg);
- }
-
- // Field 6: counter_names
- for (auto& it : counter_names_) {
- ::protozero::internal::gen_helpers::SerializeString(6, it, msg);
- }
-
- // Field 3: instrumented_sampling
- if (_has_field_[3]) {
- ::protozero::internal::gen_helpers::SerializeTinyVarInt(3, instrumented_sampling_, msg);
- }
-
- // Field 5: instrumented_sampling_config
- if (_has_field_[5]) {
- (*instrumented_sampling_config_).Serialize(msg->BeginNestedMessage<::protozero::Message>(5));
- }
-
- // Field 4: fix_gpu_clock
- if (_has_field_[4]) {
- ::protozero::internal::gen_helpers::SerializeTinyVarInt(4, fix_gpu_clock_, msg);
+void AndroidGameInterventionListConfig::Serialize(::protozero::Message* msg) const {
+ // Field 1: package_name_filter
+ for (auto& it : package_name_filter_) {
+ ::protozero::internal::gen_helpers::SerializeString(1, it, msg);
}
protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
}
+} // namespace perfetto
+} // namespace protos
+} // namespace gen
+#if defined(__GNUC__) || defined(__clang__)
+#pragma GCC diagnostic pop
+#endif
+// gen_amalgamated begin source: gen/protos/perfetto/config/android/android_input_event_config.gen.cc
+// gen_amalgamated expanded: #include "perfetto/protozero/gen_field_helpers.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/message.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/packed_repeated_fields.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/proto_decoder.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/scattered_heap_buffer.h"
+// DO NOT EDIT. Autogenerated by Perfetto cppgen_plugin
+#if defined(__GNUC__) || defined(__clang__)
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wfloat-equal"
+#endif
+// gen_amalgamated expanded: #include "protos/perfetto/config/android/android_input_event_config.gen.h"
-GpuCounterConfig_InstrumentedSamplingConfig::GpuCounterConfig_InstrumentedSamplingConfig() = default;
-GpuCounterConfig_InstrumentedSamplingConfig::~GpuCounterConfig_InstrumentedSamplingConfig() = default;
-GpuCounterConfig_InstrumentedSamplingConfig::GpuCounterConfig_InstrumentedSamplingConfig(const GpuCounterConfig_InstrumentedSamplingConfig&) = default;
-GpuCounterConfig_InstrumentedSamplingConfig& GpuCounterConfig_InstrumentedSamplingConfig::operator=(const GpuCounterConfig_InstrumentedSamplingConfig&) = default;
-GpuCounterConfig_InstrumentedSamplingConfig::GpuCounterConfig_InstrumentedSamplingConfig(GpuCounterConfig_InstrumentedSamplingConfig&&) noexcept = default;
-GpuCounterConfig_InstrumentedSamplingConfig& GpuCounterConfig_InstrumentedSamplingConfig::operator=(GpuCounterConfig_InstrumentedSamplingConfig&&) = default;
+namespace perfetto {
+namespace protos {
+namespace gen {
-bool GpuCounterConfig_InstrumentedSamplingConfig::operator==(const GpuCounterConfig_InstrumentedSamplingConfig& other) const {
+AndroidInputEventConfig::AndroidInputEventConfig() = default;
+AndroidInputEventConfig::~AndroidInputEventConfig() = default;
+AndroidInputEventConfig::AndroidInputEventConfig(const AndroidInputEventConfig&) = default;
+AndroidInputEventConfig& AndroidInputEventConfig::operator=(const AndroidInputEventConfig&) = default;
+AndroidInputEventConfig::AndroidInputEventConfig(AndroidInputEventConfig&&) noexcept = default;
+AndroidInputEventConfig& AndroidInputEventConfig::operator=(AndroidInputEventConfig&&) = default;
+
+bool AndroidInputEventConfig::operator==(const AndroidInputEventConfig& other) const {
return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
- && ::protozero::internal::gen_helpers::EqualsField(activity_name_filters_, other.activity_name_filters_)
- && ::protozero::internal::gen_helpers::EqualsField(activity_tx_include_globs_, other.activity_tx_include_globs_)
- && ::protozero::internal::gen_helpers::EqualsField(activity_tx_exclude_globs_, other.activity_tx_exclude_globs_)
- && ::protozero::internal::gen_helpers::EqualsField(activity_ranges_, other.activity_ranges_);
+ && ::protozero::internal::gen_helpers::EqualsField(mode_, other.mode_)
+ && ::protozero::internal::gen_helpers::EqualsField(rules_, other.rules_)
+ && ::protozero::internal::gen_helpers::EqualsField(trace_dispatcher_input_events_, other.trace_dispatcher_input_events_)
+ && ::protozero::internal::gen_helpers::EqualsField(trace_dispatcher_window_dispatch_, other.trace_dispatcher_window_dispatch_)
+ && ::protozero::internal::gen_helpers::EqualsField(trace_evdev_events_, other.trace_evdev_events_);
}
-int GpuCounterConfig_InstrumentedSamplingConfig::activity_name_filters_size() const { return static_cast<int>(activity_name_filters_.size()); }
-void GpuCounterConfig_InstrumentedSamplingConfig::clear_activity_name_filters() { activity_name_filters_.clear(); }
-GpuCounterConfig_InstrumentedSamplingConfig_ActivityNameFilter* GpuCounterConfig_InstrumentedSamplingConfig::add_activity_name_filters() { activity_name_filters_.emplace_back(); return &activity_name_filters_.back(); }
-int GpuCounterConfig_InstrumentedSamplingConfig::activity_ranges_size() const { return static_cast<int>(activity_ranges_.size()); }
-void GpuCounterConfig_InstrumentedSamplingConfig::clear_activity_ranges() { activity_ranges_.clear(); }
-GpuCounterConfig_InstrumentedSamplingConfig_ActivityRange* GpuCounterConfig_InstrumentedSamplingConfig::add_activity_ranges() { activity_ranges_.emplace_back(); return &activity_ranges_.back(); }
-bool GpuCounterConfig_InstrumentedSamplingConfig::ParseFromArray(const void* raw, size_t size) {
- activity_name_filters_.clear();
- activity_tx_include_globs_.clear();
- activity_tx_exclude_globs_.clear();
- activity_ranges_.clear();
+int AndroidInputEventConfig::rules_size() const { return static_cast<int>(rules_.size()); }
+void AndroidInputEventConfig::clear_rules() { rules_.clear(); }
+AndroidInputEventConfig_TraceRule* AndroidInputEventConfig::add_rules() { rules_.emplace_back(); return &rules_.back(); }
+bool AndroidInputEventConfig::ParseFromArray(const void* raw, size_t size) {
+ rules_.clear();
unknown_fields_.clear();
bool packed_error = false;
@@ -24226,21 +24124,21 @@ bool GpuCounterConfig_InstrumentedSamplingConfig::ParseFromArray(const void* raw
_has_field_.set(field.id());
}
switch (field.id()) {
- case 3 /* activity_name_filters */:
- activity_name_filters_.emplace_back();
- activity_name_filters_.back().ParseFromArray(field.data(), field.size());
+ case 1 /* mode */:
+ field.get(&mode_);
break;
- case 6 /* activity_tx_include_globs */:
- activity_tx_include_globs_.emplace_back();
- ::protozero::internal::gen_helpers::DeserializeString(field, &activity_tx_include_globs_.back());
+ case 2 /* rules */:
+ rules_.emplace_back();
+ rules_.back().ParseFromArray(field.data(), field.size());
break;
- case 7 /* activity_tx_exclude_globs */:
- activity_tx_exclude_globs_.emplace_back();
- ::protozero::internal::gen_helpers::DeserializeString(field, &activity_tx_exclude_globs_.back());
+ case 3 /* trace_dispatcher_input_events */:
+ field.get(&trace_dispatcher_input_events_);
break;
- case 5 /* activity_ranges */:
- activity_ranges_.emplace_back();
- activity_ranges_.back().ParseFromArray(field.data(), field.size());
+ case 4 /* trace_dispatcher_window_dispatch */:
+ field.get(&trace_dispatcher_window_dispatch_);
+ break;
+ case 5 /* trace_evdev_events */:
+ field.get(&trace_evdev_events_);
break;
default:
field.SerializeAndAppendTo(&unknown_fields_);
@@ -24250,57 +24148,67 @@ bool GpuCounterConfig_InstrumentedSamplingConfig::ParseFromArray(const void* raw
return !packed_error && !dec.bytes_left();
}
-std::string GpuCounterConfig_InstrumentedSamplingConfig::SerializeAsString() const {
+std::string AndroidInputEventConfig::SerializeAsString() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsString();
}
-std::vector<uint8_t> GpuCounterConfig_InstrumentedSamplingConfig::SerializeAsArray() const {
+std::vector<uint8_t> AndroidInputEventConfig::SerializeAsArray() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsArray();
}
-void GpuCounterConfig_InstrumentedSamplingConfig::Serialize(::protozero::Message* msg) const {
- // Field 3: activity_name_filters
- for (auto& it : activity_name_filters_) {
- it.Serialize(msg->BeginNestedMessage<::protozero::Message>(3));
+void AndroidInputEventConfig::Serialize(::protozero::Message* msg) const {
+ // Field 1: mode
+ if (_has_field_[1]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(1, mode_, msg);
}
- // Field 6: activity_tx_include_globs
- for (auto& it : activity_tx_include_globs_) {
- ::protozero::internal::gen_helpers::SerializeString(6, it, msg);
+ // Field 2: rules
+ for (auto& it : rules_) {
+ it.Serialize(msg->BeginNestedMessage<::protozero::Message>(2));
}
- // Field 7: activity_tx_exclude_globs
- for (auto& it : activity_tx_exclude_globs_) {
- ::protozero::internal::gen_helpers::SerializeString(7, it, msg);
+ // Field 3: trace_dispatcher_input_events
+ if (_has_field_[3]) {
+ ::protozero::internal::gen_helpers::SerializeTinyVarInt(3, trace_dispatcher_input_events_, msg);
}
- // Field 5: activity_ranges
- for (auto& it : activity_ranges_) {
- it.Serialize(msg->BeginNestedMessage<::protozero::Message>(5));
+ // Field 4: trace_dispatcher_window_dispatch
+ if (_has_field_[4]) {
+ ::protozero::internal::gen_helpers::SerializeTinyVarInt(4, trace_dispatcher_window_dispatch_, msg);
+ }
+
+ // Field 5: trace_evdev_events
+ if (_has_field_[5]) {
+ ::protozero::internal::gen_helpers::SerializeTinyVarInt(5, trace_evdev_events_, msg);
}
protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
}
-GpuCounterConfig_InstrumentedSamplingConfig_ActivityRange::GpuCounterConfig_InstrumentedSamplingConfig_ActivityRange() = default;
-GpuCounterConfig_InstrumentedSamplingConfig_ActivityRange::~GpuCounterConfig_InstrumentedSamplingConfig_ActivityRange() = default;
-GpuCounterConfig_InstrumentedSamplingConfig_ActivityRange::GpuCounterConfig_InstrumentedSamplingConfig_ActivityRange(const GpuCounterConfig_InstrumentedSamplingConfig_ActivityRange&) = default;
-GpuCounterConfig_InstrumentedSamplingConfig_ActivityRange& GpuCounterConfig_InstrumentedSamplingConfig_ActivityRange::operator=(const GpuCounterConfig_InstrumentedSamplingConfig_ActivityRange&) = default;
-GpuCounterConfig_InstrumentedSamplingConfig_ActivityRange::GpuCounterConfig_InstrumentedSamplingConfig_ActivityRange(GpuCounterConfig_InstrumentedSamplingConfig_ActivityRange&&) noexcept = default;
-GpuCounterConfig_InstrumentedSamplingConfig_ActivityRange& GpuCounterConfig_InstrumentedSamplingConfig_ActivityRange::operator=(GpuCounterConfig_InstrumentedSamplingConfig_ActivityRange&&) = default;
+AndroidInputEventConfig_TraceRule::AndroidInputEventConfig_TraceRule() = default;
+AndroidInputEventConfig_TraceRule::~AndroidInputEventConfig_TraceRule() = default;
+AndroidInputEventConfig_TraceRule::AndroidInputEventConfig_TraceRule(const AndroidInputEventConfig_TraceRule&) = default;
+AndroidInputEventConfig_TraceRule& AndroidInputEventConfig_TraceRule::operator=(const AndroidInputEventConfig_TraceRule&) = default;
+AndroidInputEventConfig_TraceRule::AndroidInputEventConfig_TraceRule(AndroidInputEventConfig_TraceRule&&) noexcept = default;
+AndroidInputEventConfig_TraceRule& AndroidInputEventConfig_TraceRule::operator=(AndroidInputEventConfig_TraceRule&&) = default;
-bool GpuCounterConfig_InstrumentedSamplingConfig_ActivityRange::operator==(const GpuCounterConfig_InstrumentedSamplingConfig_ActivityRange& other) const {
+bool AndroidInputEventConfig_TraceRule::operator==(const AndroidInputEventConfig_TraceRule& other) const {
return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
- && ::protozero::internal::gen_helpers::EqualsField(skip_, other.skip_)
- && ::protozero::internal::gen_helpers::EqualsField(count_, other.count_);
+ && ::protozero::internal::gen_helpers::EqualsField(trace_level_, other.trace_level_)
+ && ::protozero::internal::gen_helpers::EqualsField(match_all_packages_, other.match_all_packages_)
+ && ::protozero::internal::gen_helpers::EqualsField(match_any_packages_, other.match_any_packages_)
+ && ::protozero::internal::gen_helpers::EqualsField(match_secure_, other.match_secure_)
+ && ::protozero::internal::gen_helpers::EqualsField(match_ime_connection_active_, other.match_ime_connection_active_);
}
-bool GpuCounterConfig_InstrumentedSamplingConfig_ActivityRange::ParseFromArray(const void* raw, size_t size) {
+bool AndroidInputEventConfig_TraceRule::ParseFromArray(const void* raw, size_t size) {
+ match_all_packages_.clear();
+ match_any_packages_.clear();
unknown_fields_.clear();
bool packed_error = false;
@@ -24310,11 +24218,22 @@ bool GpuCounterConfig_InstrumentedSamplingConfig_ActivityRange::ParseFromArray(c
_has_field_.set(field.id());
}
switch (field.id()) {
- case 1 /* skip */:
- field.get(&skip_);
+ case 1 /* trace_level */:
+ field.get(&trace_level_);
break;
- case 2 /* count */:
- field.get(&count_);
+ case 2 /* match_all_packages */:
+ match_all_packages_.emplace_back();
+ ::protozero::internal::gen_helpers::DeserializeString(field, &match_all_packages_.back());
+ break;
+ case 3 /* match_any_packages */:
+ match_any_packages_.emplace_back();
+ ::protozero::internal::gen_helpers::DeserializeString(field, &match_any_packages_.back());
+ break;
+ case 4 /* match_secure */:
+ field.get(&match_secure_);
+ break;
+ case 5 /* match_ime_connection_active */:
+ field.get(&match_ime_connection_active_);
break;
default:
field.SerializeAndAppendTo(&unknown_fields_);
@@ -24324,47 +24243,89 @@ bool GpuCounterConfig_InstrumentedSamplingConfig_ActivityRange::ParseFromArray(c
return !packed_error && !dec.bytes_left();
}
-std::string GpuCounterConfig_InstrumentedSamplingConfig_ActivityRange::SerializeAsString() const {
+std::string AndroidInputEventConfig_TraceRule::SerializeAsString() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsString();
}
-std::vector<uint8_t> GpuCounterConfig_InstrumentedSamplingConfig_ActivityRange::SerializeAsArray() const {
+std::vector<uint8_t> AndroidInputEventConfig_TraceRule::SerializeAsArray() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsArray();
}
-void GpuCounterConfig_InstrumentedSamplingConfig_ActivityRange::Serialize(::protozero::Message* msg) const {
- // Field 1: skip
+void AndroidInputEventConfig_TraceRule::Serialize(::protozero::Message* msg) const {
+ // Field 1: trace_level
if (_has_field_[1]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(1, skip_, msg);
+ ::protozero::internal::gen_helpers::SerializeVarInt(1, trace_level_, msg);
}
- // Field 2: count
- if (_has_field_[2]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(2, count_, msg);
+ // Field 2: match_all_packages
+ for (auto& it : match_all_packages_) {
+ ::protozero::internal::gen_helpers::SerializeString(2, it, msg);
+ }
+
+ // Field 3: match_any_packages
+ for (auto& it : match_any_packages_) {
+ ::protozero::internal::gen_helpers::SerializeString(3, it, msg);
+ }
+
+ // Field 4: match_secure
+ if (_has_field_[4]) {
+ ::protozero::internal::gen_helpers::SerializeTinyVarInt(4, match_secure_, msg);
+ }
+
+ // Field 5: match_ime_connection_active
+ if (_has_field_[5]) {
+ ::protozero::internal::gen_helpers::SerializeTinyVarInt(5, match_ime_connection_active_, msg);
}
protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
}
+} // namespace perfetto
+} // namespace protos
+} // namespace gen
+#if defined(__GNUC__) || defined(__clang__)
+#pragma GCC diagnostic pop
+#endif
+// gen_amalgamated begin source: gen/protos/perfetto/config/android/android_log_config.gen.cc
+// gen_amalgamated expanded: #include "perfetto/protozero/gen_field_helpers.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/message.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/packed_repeated_fields.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/proto_decoder.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/scattered_heap_buffer.h"
+// DO NOT EDIT. Autogenerated by Perfetto cppgen_plugin
+#if defined(__GNUC__) || defined(__clang__)
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wfloat-equal"
+#endif
+// gen_amalgamated expanded: #include "protos/perfetto/config/android/android_log_config.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/common/android_log_constants.gen.h"
-GpuCounterConfig_InstrumentedSamplingConfig_ActivityNameFilter::GpuCounterConfig_InstrumentedSamplingConfig_ActivityNameFilter() = default;
-GpuCounterConfig_InstrumentedSamplingConfig_ActivityNameFilter::~GpuCounterConfig_InstrumentedSamplingConfig_ActivityNameFilter() = default;
-GpuCounterConfig_InstrumentedSamplingConfig_ActivityNameFilter::GpuCounterConfig_InstrumentedSamplingConfig_ActivityNameFilter(const GpuCounterConfig_InstrumentedSamplingConfig_ActivityNameFilter&) = default;
-GpuCounterConfig_InstrumentedSamplingConfig_ActivityNameFilter& GpuCounterConfig_InstrumentedSamplingConfig_ActivityNameFilter::operator=(const GpuCounterConfig_InstrumentedSamplingConfig_ActivityNameFilter&) = default;
-GpuCounterConfig_InstrumentedSamplingConfig_ActivityNameFilter::GpuCounterConfig_InstrumentedSamplingConfig_ActivityNameFilter(GpuCounterConfig_InstrumentedSamplingConfig_ActivityNameFilter&&) noexcept = default;
-GpuCounterConfig_InstrumentedSamplingConfig_ActivityNameFilter& GpuCounterConfig_InstrumentedSamplingConfig_ActivityNameFilter::operator=(GpuCounterConfig_InstrumentedSamplingConfig_ActivityNameFilter&&) = default;
+namespace perfetto {
+namespace protos {
+namespace gen {
-bool GpuCounterConfig_InstrumentedSamplingConfig_ActivityNameFilter::operator==(const GpuCounterConfig_InstrumentedSamplingConfig_ActivityNameFilter& other) const {
+AndroidLogConfig::AndroidLogConfig() = default;
+AndroidLogConfig::~AndroidLogConfig() = default;
+AndroidLogConfig::AndroidLogConfig(const AndroidLogConfig&) = default;
+AndroidLogConfig& AndroidLogConfig::operator=(const AndroidLogConfig&) = default;
+AndroidLogConfig::AndroidLogConfig(AndroidLogConfig&&) noexcept = default;
+AndroidLogConfig& AndroidLogConfig::operator=(AndroidLogConfig&&) = default;
+
+bool AndroidLogConfig::operator==(const AndroidLogConfig& other) const {
return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
- && ::protozero::internal::gen_helpers::EqualsField(name_glob_, other.name_glob_)
- && ::protozero::internal::gen_helpers::EqualsField(name_base_, other.name_base_);
+ && ::protozero::internal::gen_helpers::EqualsField(log_ids_, other.log_ids_)
+ && ::protozero::internal::gen_helpers::EqualsField(min_prio_, other.min_prio_)
+ && ::protozero::internal::gen_helpers::EqualsField(filter_tags_, other.filter_tags_)
+ && ::protozero::internal::gen_helpers::EqualsField(preserve_log_buffer_, other.preserve_log_buffer_);
}
-bool GpuCounterConfig_InstrumentedSamplingConfig_ActivityNameFilter::ParseFromArray(const void* raw, size_t size) {
+bool AndroidLogConfig::ParseFromArray(const void* raw, size_t size) {
+ log_ids_.clear();
+ filter_tags_.clear();
unknown_fields_.clear();
bool packed_error = false;
@@ -24374,11 +24335,19 @@ bool GpuCounterConfig_InstrumentedSamplingConfig_ActivityNameFilter::ParseFromAr
_has_field_.set(field.id());
}
switch (field.id()) {
- case 1 /* name_glob */:
- ::protozero::internal::gen_helpers::DeserializeString(field, &name_glob_);
+ case 1 /* log_ids */:
+ log_ids_.emplace_back();
+ field.get(&log_ids_.back());
break;
- case 2 /* name_base */:
- field.get(&name_base_);
+ case 3 /* min_prio */:
+ field.get(&min_prio_);
+ break;
+ case 4 /* filter_tags */:
+ filter_tags_.emplace_back();
+ ::protozero::internal::gen_helpers::DeserializeString(field, &filter_tags_.back());
+ break;
+ case 5 /* preserve_log_buffer */:
+ field.get(&preserve_log_buffer_);
break;
default:
field.SerializeAndAppendTo(&unknown_fields_);
@@ -24388,27 +24357,37 @@ bool GpuCounterConfig_InstrumentedSamplingConfig_ActivityNameFilter::ParseFromAr
return !packed_error && !dec.bytes_left();
}
-std::string GpuCounterConfig_InstrumentedSamplingConfig_ActivityNameFilter::SerializeAsString() const {
+std::string AndroidLogConfig::SerializeAsString() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsString();
}
-std::vector<uint8_t> GpuCounterConfig_InstrumentedSamplingConfig_ActivityNameFilter::SerializeAsArray() const {
+std::vector<uint8_t> AndroidLogConfig::SerializeAsArray() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsArray();
}
-void GpuCounterConfig_InstrumentedSamplingConfig_ActivityNameFilter::Serialize(::protozero::Message* msg) const {
- // Field 1: name_glob
- if (_has_field_[1]) {
- ::protozero::internal::gen_helpers::SerializeString(1, name_glob_, msg);
+void AndroidLogConfig::Serialize(::protozero::Message* msg) const {
+ // Field 1: log_ids
+ for (auto& it : log_ids_) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(1, it, msg);
}
- // Field 2: name_base
- if (_has_field_[2]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(2, name_base_, msg);
+ // Field 3: min_prio
+ if (_has_field_[3]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(3, min_prio_, msg);
+ }
+
+ // Field 4: filter_tags
+ for (auto& it : filter_tags_) {
+ ::protozero::internal::gen_helpers::SerializeString(4, it, msg);
+ }
+
+ // Field 5: preserve_log_buffer
+ if (_has_field_[5]) {
+ ::protozero::internal::gen_helpers::SerializeTinyVarInt(5, preserve_log_buffer_, msg);
}
protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
@@ -24420,7 +24399,7 @@ void GpuCounterConfig_InstrumentedSamplingConfig_ActivityNameFilter::Serialize(:
#if defined(__GNUC__) || defined(__clang__)
#pragma GCC diagnostic pop
#endif
-// gen_amalgamated begin source: gen/protos/perfetto/config/gpu/gpu_renderstages_config.gen.cc
+// gen_amalgamated begin source: gen/protos/perfetto/config/android/android_polled_state_config.gen.cc
// gen_amalgamated expanded: #include "perfetto/protozero/gen_field_helpers.h"
// gen_amalgamated expanded: #include "perfetto/protozero/message.h"
// gen_amalgamated expanded: #include "perfetto/protozero/packed_repeated_fields.h"
@@ -24431,28 +24410,25 @@ void GpuCounterConfig_InstrumentedSamplingConfig_ActivityNameFilter::Serialize(:
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wfloat-equal"
#endif
-// gen_amalgamated expanded: #include "protos/perfetto/config/gpu/gpu_renderstages_config.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/config/android/android_polled_state_config.gen.h"
namespace perfetto {
namespace protos {
namespace gen {
-GpuRenderStagesConfig::GpuRenderStagesConfig() = default;
-GpuRenderStagesConfig::~GpuRenderStagesConfig() = default;
-GpuRenderStagesConfig::GpuRenderStagesConfig(const GpuRenderStagesConfig&) = default;
-GpuRenderStagesConfig& GpuRenderStagesConfig::operator=(const GpuRenderStagesConfig&) = default;
-GpuRenderStagesConfig::GpuRenderStagesConfig(GpuRenderStagesConfig&&) noexcept = default;
-GpuRenderStagesConfig& GpuRenderStagesConfig::operator=(GpuRenderStagesConfig&&) = default;
+AndroidPolledStateConfig::AndroidPolledStateConfig() = default;
+AndroidPolledStateConfig::~AndroidPolledStateConfig() = default;
+AndroidPolledStateConfig::AndroidPolledStateConfig(const AndroidPolledStateConfig&) = default;
+AndroidPolledStateConfig& AndroidPolledStateConfig::operator=(const AndroidPolledStateConfig&) = default;
+AndroidPolledStateConfig::AndroidPolledStateConfig(AndroidPolledStateConfig&&) noexcept = default;
+AndroidPolledStateConfig& AndroidPolledStateConfig::operator=(AndroidPolledStateConfig&&) = default;
-bool GpuRenderStagesConfig::operator==(const GpuRenderStagesConfig& other) const {
+bool AndroidPolledStateConfig::operator==(const AndroidPolledStateConfig& other) const {
return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
- && ::protozero::internal::gen_helpers::EqualsField(full_loadstore_, other.full_loadstore_)
- && ::protozero::internal::gen_helpers::EqualsField(low_overhead_, other.low_overhead_)
- && ::protozero::internal::gen_helpers::EqualsField(trace_metrics_, other.trace_metrics_);
+ && ::protozero::internal::gen_helpers::EqualsField(poll_ms_, other.poll_ms_);
}
-bool GpuRenderStagesConfig::ParseFromArray(const void* raw, size_t size) {
- trace_metrics_.clear();
+bool AndroidPolledStateConfig::ParseFromArray(const void* raw, size_t size) {
unknown_fields_.clear();
bool packed_error = false;
@@ -24462,15 +24438,8 @@ bool GpuRenderStagesConfig::ParseFromArray(const void* raw, size_t size) {
_has_field_.set(field.id());
}
switch (field.id()) {
- case 1 /* full_loadstore */:
- field.get(&full_loadstore_);
- break;
- case 2 /* low_overhead */:
- field.get(&low_overhead_);
- break;
- case 3 /* trace_metrics */:
- trace_metrics_.emplace_back();
- ::protozero::internal::gen_helpers::DeserializeString(field, &trace_metrics_.back());
+ case 1 /* poll_ms */:
+ field.get(&poll_ms_);
break;
default:
field.SerializeAndAppendTo(&unknown_fields_);
@@ -24480,32 +24449,22 @@ bool GpuRenderStagesConfig::ParseFromArray(const void* raw, size_t size) {
return !packed_error && !dec.bytes_left();
}
-std::string GpuRenderStagesConfig::SerializeAsString() const {
+std::string AndroidPolledStateConfig::SerializeAsString() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsString();
}
-std::vector<uint8_t> GpuRenderStagesConfig::SerializeAsArray() const {
+std::vector<uint8_t> AndroidPolledStateConfig::SerializeAsArray() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsArray();
}
-void GpuRenderStagesConfig::Serialize(::protozero::Message* msg) const {
- // Field 1: full_loadstore
+void AndroidPolledStateConfig::Serialize(::protozero::Message* msg) const {
+ // Field 1: poll_ms
if (_has_field_[1]) {
- ::protozero::internal::gen_helpers::SerializeTinyVarInt(1, full_loadstore_, msg);
- }
-
- // Field 2: low_overhead
- if (_has_field_[2]) {
- ::protozero::internal::gen_helpers::SerializeTinyVarInt(2, low_overhead_, msg);
- }
-
- // Field 3: trace_metrics
- for (auto& it : trace_metrics_) {
- ::protozero::internal::gen_helpers::SerializeString(3, it, msg);
+ ::protozero::internal::gen_helpers::SerializeVarInt(1, poll_ms_, msg);
}
protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
@@ -24517,7 +24476,7 @@ void GpuRenderStagesConfig::Serialize(::protozero::Message* msg) const {
#if defined(__GNUC__) || defined(__clang__)
#pragma GCC diagnostic pop
#endif
-// gen_amalgamated begin source: gen/protos/perfetto/config/gpu/vulkan_memory_config.gen.cc
+// gen_amalgamated begin source: gen/protos/perfetto/config/android/android_process_state_config.gen.cc
// gen_amalgamated expanded: #include "perfetto/protozero/gen_field_helpers.h"
// gen_amalgamated expanded: #include "perfetto/protozero/message.h"
// gen_amalgamated expanded: #include "perfetto/protozero/packed_repeated_fields.h"
@@ -24528,26 +24487,25 @@ void GpuRenderStagesConfig::Serialize(::protozero::Message* msg) const {
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wfloat-equal"
#endif
-// gen_amalgamated expanded: #include "protos/perfetto/config/gpu/vulkan_memory_config.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/config/android/android_process_state_config.gen.h"
namespace perfetto {
namespace protos {
namespace gen {
-VulkanMemoryConfig::VulkanMemoryConfig() = default;
-VulkanMemoryConfig::~VulkanMemoryConfig() = default;
-VulkanMemoryConfig::VulkanMemoryConfig(const VulkanMemoryConfig&) = default;
-VulkanMemoryConfig& VulkanMemoryConfig::operator=(const VulkanMemoryConfig&) = default;
-VulkanMemoryConfig::VulkanMemoryConfig(VulkanMemoryConfig&&) noexcept = default;
-VulkanMemoryConfig& VulkanMemoryConfig::operator=(VulkanMemoryConfig&&) = default;
+AndroidProcessStateConfig::AndroidProcessStateConfig() = default;
+AndroidProcessStateConfig::~AndroidProcessStateConfig() = default;
+AndroidProcessStateConfig::AndroidProcessStateConfig(const AndroidProcessStateConfig&) = default;
+AndroidProcessStateConfig& AndroidProcessStateConfig::operator=(const AndroidProcessStateConfig&) = default;
+AndroidProcessStateConfig::AndroidProcessStateConfig(AndroidProcessStateConfig&&) noexcept = default;
+AndroidProcessStateConfig& AndroidProcessStateConfig::operator=(AndroidProcessStateConfig&&) = default;
-bool VulkanMemoryConfig::operator==(const VulkanMemoryConfig& other) const {
+bool AndroidProcessStateConfig::operator==(const AndroidProcessStateConfig& other) const {
return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
- && ::protozero::internal::gen_helpers::EqualsField(track_driver_memory_usage_, other.track_driver_memory_usage_)
- && ::protozero::internal::gen_helpers::EqualsField(track_device_memory_usage_, other.track_device_memory_usage_);
+ && ::protozero::internal::gen_helpers::EqualsField(dump_process_metadata_, other.dump_process_metadata_);
}
-bool VulkanMemoryConfig::ParseFromArray(const void* raw, size_t size) {
+bool AndroidProcessStateConfig::ParseFromArray(const void* raw, size_t size) {
unknown_fields_.clear();
bool packed_error = false;
@@ -24557,11 +24515,8 @@ bool VulkanMemoryConfig::ParseFromArray(const void* raw, size_t size) {
_has_field_.set(field.id());
}
switch (field.id()) {
- case 1 /* track_driver_memory_usage */:
- field.get(&track_driver_memory_usage_);
- break;
- case 2 /* track_device_memory_usage */:
- field.get(&track_device_memory_usage_);
+ case 1 /* dump_process_metadata */:
+ field.get(&dump_process_metadata_);
break;
default:
field.SerializeAndAppendTo(&unknown_fields_);
@@ -24571,27 +24526,22 @@ bool VulkanMemoryConfig::ParseFromArray(const void* raw, size_t size) {
return !packed_error && !dec.bytes_left();
}
-std::string VulkanMemoryConfig::SerializeAsString() const {
+std::string AndroidProcessStateConfig::SerializeAsString() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsString();
}
-std::vector<uint8_t> VulkanMemoryConfig::SerializeAsArray() const {
+std::vector<uint8_t> AndroidProcessStateConfig::SerializeAsArray() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsArray();
}
-void VulkanMemoryConfig::Serialize(::protozero::Message* msg) const {
- // Field 1: track_driver_memory_usage
+void AndroidProcessStateConfig::Serialize(::protozero::Message* msg) const {
+ // Field 1: dump_process_metadata
if (_has_field_[1]) {
- ::protozero::internal::gen_helpers::SerializeTinyVarInt(1, track_driver_memory_usage_, msg);
- }
-
- // Field 2: track_device_memory_usage
- if (_has_field_[2]) {
- ::protozero::internal::gen_helpers::SerializeTinyVarInt(2, track_device_memory_usage_, msg);
+ ::protozero::internal::gen_helpers::SerializeTinyVarInt(1, dump_process_metadata_, msg);
}
protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
@@ -24603,7 +24553,7 @@ void VulkanMemoryConfig::Serialize(::protozero::Message* msg) const {
#if defined(__GNUC__) || defined(__clang__)
#pragma GCC diagnostic pop
#endif
-// gen_amalgamated begin source: gen/protos/perfetto/config/inode_file/inode_file_config.gen.cc
+// gen_amalgamated begin source: gen/protos/perfetto/config/android/android_sdk_sysprop_guard_config.gen.cc
// gen_amalgamated expanded: #include "perfetto/protozero/gen_field_helpers.h"
// gen_amalgamated expanded: #include "perfetto/protozero/message.h"
// gen_amalgamated expanded: #include "perfetto/protozero/packed_repeated_fields.h"
@@ -24614,35 +24564,28 @@ void VulkanMemoryConfig::Serialize(::protozero::Message* msg) const {
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wfloat-equal"
#endif
-// gen_amalgamated expanded: #include "protos/perfetto/config/inode_file/inode_file_config.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/config/android/android_sdk_sysprop_guard_config.gen.h"
namespace perfetto {
namespace protos {
namespace gen {
-InodeFileConfig::InodeFileConfig() = default;
-InodeFileConfig::~InodeFileConfig() = default;
-InodeFileConfig::InodeFileConfig(const InodeFileConfig&) = default;
-InodeFileConfig& InodeFileConfig::operator=(const InodeFileConfig&) = default;
-InodeFileConfig::InodeFileConfig(InodeFileConfig&&) noexcept = default;
-InodeFileConfig& InodeFileConfig::operator=(InodeFileConfig&&) = default;
+AndroidSdkSyspropGuardConfig::AndroidSdkSyspropGuardConfig() = default;
+AndroidSdkSyspropGuardConfig::~AndroidSdkSyspropGuardConfig() = default;
+AndroidSdkSyspropGuardConfig::AndroidSdkSyspropGuardConfig(const AndroidSdkSyspropGuardConfig&) = default;
+AndroidSdkSyspropGuardConfig& AndroidSdkSyspropGuardConfig::operator=(const AndroidSdkSyspropGuardConfig&) = default;
+AndroidSdkSyspropGuardConfig::AndroidSdkSyspropGuardConfig(AndroidSdkSyspropGuardConfig&&) noexcept = default;
+AndroidSdkSyspropGuardConfig& AndroidSdkSyspropGuardConfig::operator=(AndroidSdkSyspropGuardConfig&&) = default;
-bool InodeFileConfig::operator==(const InodeFileConfig& other) const {
+bool AndroidSdkSyspropGuardConfig::operator==(const AndroidSdkSyspropGuardConfig& other) const {
return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
- && ::protozero::internal::gen_helpers::EqualsField(scan_interval_ms_, other.scan_interval_ms_)
- && ::protozero::internal::gen_helpers::EqualsField(scan_delay_ms_, other.scan_delay_ms_)
- && ::protozero::internal::gen_helpers::EqualsField(scan_batch_size_, other.scan_batch_size_)
- && ::protozero::internal::gen_helpers::EqualsField(do_not_scan_, other.do_not_scan_)
- && ::protozero::internal::gen_helpers::EqualsField(scan_mount_points_, other.scan_mount_points_)
- && ::protozero::internal::gen_helpers::EqualsField(mount_point_mapping_, other.mount_point_mapping_);
+ && ::protozero::internal::gen_helpers::EqualsField(surfaceflinger_skia_track_events_, other.surfaceflinger_skia_track_events_)
+ && ::protozero::internal::gen_helpers::EqualsField(hwui_skia_track_events_, other.hwui_skia_track_events_)
+ && ::protozero::internal::gen_helpers::EqualsField(hwui_package_name_filter_, other.hwui_package_name_filter_);
}
-int InodeFileConfig::mount_point_mapping_size() const { return static_cast<int>(mount_point_mapping_.size()); }
-void InodeFileConfig::clear_mount_point_mapping() { mount_point_mapping_.clear(); }
-InodeFileConfig_MountPointMappingEntry* InodeFileConfig::add_mount_point_mapping() { mount_point_mapping_.emplace_back(); return &mount_point_mapping_.back(); }
-bool InodeFileConfig::ParseFromArray(const void* raw, size_t size) {
- scan_mount_points_.clear();
- mount_point_mapping_.clear();
+bool AndroidSdkSyspropGuardConfig::ParseFromArray(const void* raw, size_t size) {
+ hwui_package_name_filter_.clear();
unknown_fields_.clear();
bool packed_error = false;
@@ -24652,25 +24595,15 @@ bool InodeFileConfig::ParseFromArray(const void* raw, size_t size) {
_has_field_.set(field.id());
}
switch (field.id()) {
- case 1 /* scan_interval_ms */:
- field.get(&scan_interval_ms_);
- break;
- case 2 /* scan_delay_ms */:
- field.get(&scan_delay_ms_);
- break;
- case 3 /* scan_batch_size */:
- field.get(&scan_batch_size_);
- break;
- case 4 /* do_not_scan */:
- field.get(&do_not_scan_);
+ case 1 /* surfaceflinger_skia_track_events */:
+ field.get(&surfaceflinger_skia_track_events_);
break;
- case 5 /* scan_mount_points */:
- scan_mount_points_.emplace_back();
- ::protozero::internal::gen_helpers::DeserializeString(field, &scan_mount_points_.back());
+ case 2 /* hwui_skia_track_events */:
+ field.get(&hwui_skia_track_events_);
break;
- case 6 /* mount_point_mapping */:
- mount_point_mapping_.emplace_back();
- mount_point_mapping_.back().ParseFromArray(field.data(), field.size());
+ case 3 /* hwui_package_name_filter */:
+ hwui_package_name_filter_.emplace_back();
+ ::protozero::internal::gen_helpers::DeserializeString(field, &hwui_package_name_filter_.back());
break;
default:
field.SerializeAndAppendTo(&unknown_fields_);
@@ -24680,68 +24613,75 @@ bool InodeFileConfig::ParseFromArray(const void* raw, size_t size) {
return !packed_error && !dec.bytes_left();
}
-std::string InodeFileConfig::SerializeAsString() const {
+std::string AndroidSdkSyspropGuardConfig::SerializeAsString() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsString();
}
-std::vector<uint8_t> InodeFileConfig::SerializeAsArray() const {
+std::vector<uint8_t> AndroidSdkSyspropGuardConfig::SerializeAsArray() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsArray();
}
-void InodeFileConfig::Serialize(::protozero::Message* msg) const {
- // Field 1: scan_interval_ms
+void AndroidSdkSyspropGuardConfig::Serialize(::protozero::Message* msg) const {
+ // Field 1: surfaceflinger_skia_track_events
if (_has_field_[1]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(1, scan_interval_ms_, msg);
+ ::protozero::internal::gen_helpers::SerializeTinyVarInt(1, surfaceflinger_skia_track_events_, msg);
}
- // Field 2: scan_delay_ms
+ // Field 2: hwui_skia_track_events
if (_has_field_[2]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(2, scan_delay_ms_, msg);
- }
-
- // Field 3: scan_batch_size
- if (_has_field_[3]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(3, scan_batch_size_, msg);
- }
-
- // Field 4: do_not_scan
- if (_has_field_[4]) {
- ::protozero::internal::gen_helpers::SerializeTinyVarInt(4, do_not_scan_, msg);
- }
-
- // Field 5: scan_mount_points
- for (auto& it : scan_mount_points_) {
- ::protozero::internal::gen_helpers::SerializeString(5, it, msg);
+ ::protozero::internal::gen_helpers::SerializeTinyVarInt(2, hwui_skia_track_events_, msg);
}
- // Field 6: mount_point_mapping
- for (auto& it : mount_point_mapping_) {
- it.Serialize(msg->BeginNestedMessage<::protozero::Message>(6));
+ // Field 3: hwui_package_name_filter
+ for (auto& it : hwui_package_name_filter_) {
+ ::protozero::internal::gen_helpers::SerializeString(3, it, msg);
}
protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
}
+} // namespace perfetto
+} // namespace protos
+} // namespace gen
+#if defined(__GNUC__) || defined(__clang__)
+#pragma GCC diagnostic pop
+#endif
+// gen_amalgamated begin source: gen/protos/perfetto/config/android/android_system_property_config.gen.cc
+// gen_amalgamated expanded: #include "perfetto/protozero/gen_field_helpers.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/message.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/packed_repeated_fields.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/proto_decoder.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/scattered_heap_buffer.h"
+// DO NOT EDIT. Autogenerated by Perfetto cppgen_plugin
+#if defined(__GNUC__) || defined(__clang__)
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wfloat-equal"
+#endif
+// gen_amalgamated expanded: #include "protos/perfetto/config/android/android_system_property_config.gen.h"
+
+namespace perfetto {
+namespace protos {
+namespace gen {
-InodeFileConfig_MountPointMappingEntry::InodeFileConfig_MountPointMappingEntry() = default;
-InodeFileConfig_MountPointMappingEntry::~InodeFileConfig_MountPointMappingEntry() = default;
-InodeFileConfig_MountPointMappingEntry::InodeFileConfig_MountPointMappingEntry(const InodeFileConfig_MountPointMappingEntry&) = default;
-InodeFileConfig_MountPointMappingEntry& InodeFileConfig_MountPointMappingEntry::operator=(const InodeFileConfig_MountPointMappingEntry&) = default;
-InodeFileConfig_MountPointMappingEntry::InodeFileConfig_MountPointMappingEntry(InodeFileConfig_MountPointMappingEntry&&) noexcept = default;
-InodeFileConfig_MountPointMappingEntry& InodeFileConfig_MountPointMappingEntry::operator=(InodeFileConfig_MountPointMappingEntry&&) = default;
+AndroidSystemPropertyConfig::AndroidSystemPropertyConfig() = default;
+AndroidSystemPropertyConfig::~AndroidSystemPropertyConfig() = default;
+AndroidSystemPropertyConfig::AndroidSystemPropertyConfig(const AndroidSystemPropertyConfig&) = default;
+AndroidSystemPropertyConfig& AndroidSystemPropertyConfig::operator=(const AndroidSystemPropertyConfig&) = default;
+AndroidSystemPropertyConfig::AndroidSystemPropertyConfig(AndroidSystemPropertyConfig&&) noexcept = default;
+AndroidSystemPropertyConfig& AndroidSystemPropertyConfig::operator=(AndroidSystemPropertyConfig&&) = default;
-bool InodeFileConfig_MountPointMappingEntry::operator==(const InodeFileConfig_MountPointMappingEntry& other) const {
+bool AndroidSystemPropertyConfig::operator==(const AndroidSystemPropertyConfig& other) const {
return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
- && ::protozero::internal::gen_helpers::EqualsField(mountpoint_, other.mountpoint_)
- && ::protozero::internal::gen_helpers::EqualsField(scan_roots_, other.scan_roots_);
+ && ::protozero::internal::gen_helpers::EqualsField(poll_ms_, other.poll_ms_)
+ && ::protozero::internal::gen_helpers::EqualsField(property_name_, other.property_name_);
}
-bool InodeFileConfig_MountPointMappingEntry::ParseFromArray(const void* raw, size_t size) {
- scan_roots_.clear();
+bool AndroidSystemPropertyConfig::ParseFromArray(const void* raw, size_t size) {
+ property_name_.clear();
unknown_fields_.clear();
bool packed_error = false;
@@ -24751,12 +24691,12 @@ bool InodeFileConfig_MountPointMappingEntry::ParseFromArray(const void* raw, siz
_has_field_.set(field.id());
}
switch (field.id()) {
- case 1 /* mountpoint */:
- ::protozero::internal::gen_helpers::DeserializeString(field, &mountpoint_);
+ case 1 /* poll_ms */:
+ field.get(&poll_ms_);
break;
- case 2 /* scan_roots */:
- scan_roots_.emplace_back();
- ::protozero::internal::gen_helpers::DeserializeString(field, &scan_roots_.back());
+ case 2 /* property_name */:
+ property_name_.emplace_back();
+ ::protozero::internal::gen_helpers::DeserializeString(field, &property_name_.back());
break;
default:
field.SerializeAndAppendTo(&unknown_fields_);
@@ -24766,26 +24706,26 @@ bool InodeFileConfig_MountPointMappingEntry::ParseFromArray(const void* raw, siz
return !packed_error && !dec.bytes_left();
}
-std::string InodeFileConfig_MountPointMappingEntry::SerializeAsString() const {
+std::string AndroidSystemPropertyConfig::SerializeAsString() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsString();
}
-std::vector<uint8_t> InodeFileConfig_MountPointMappingEntry::SerializeAsArray() const {
+std::vector<uint8_t> AndroidSystemPropertyConfig::SerializeAsArray() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsArray();
}
-void InodeFileConfig_MountPointMappingEntry::Serialize(::protozero::Message* msg) const {
- // Field 1: mountpoint
+void AndroidSystemPropertyConfig::Serialize(::protozero::Message* msg) const {
+ // Field 1: poll_ms
if (_has_field_[1]) {
- ::protozero::internal::gen_helpers::SerializeString(1, mountpoint_, msg);
+ ::protozero::internal::gen_helpers::SerializeVarInt(1, poll_ms_, msg);
}
- // Field 2: scan_roots
- for (auto& it : scan_roots_) {
+ // Field 2: property_name
+ for (auto& it : property_name_) {
::protozero::internal::gen_helpers::SerializeString(2, it, msg);
}
@@ -24798,7 +24738,7 @@ void InodeFileConfig_MountPointMappingEntry::Serialize(::protozero::Message* msg
#if defined(__GNUC__) || defined(__clang__)
#pragma GCC diagnostic pop
#endif
-// gen_amalgamated begin source: gen/protos/perfetto/config/interceptors/console_config.gen.cc
+// gen_amalgamated begin source: gen/protos/perfetto/config/android/app_wakelock_config.gen.cc
// gen_amalgamated expanded: #include "perfetto/protozero/gen_field_helpers.h"
// gen_amalgamated expanded: #include "perfetto/protozero/message.h"
// gen_amalgamated expanded: #include "perfetto/protozero/packed_repeated_fields.h"
@@ -24809,26 +24749,27 @@ void InodeFileConfig_MountPointMappingEntry::Serialize(::protozero::Message* msg
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wfloat-equal"
#endif
-// gen_amalgamated expanded: #include "protos/perfetto/config/interceptors/console_config.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/config/android/app_wakelock_config.gen.h"
namespace perfetto {
namespace protos {
namespace gen {
-ConsoleConfig::ConsoleConfig() = default;
-ConsoleConfig::~ConsoleConfig() = default;
-ConsoleConfig::ConsoleConfig(const ConsoleConfig&) = default;
-ConsoleConfig& ConsoleConfig::operator=(const ConsoleConfig&) = default;
-ConsoleConfig::ConsoleConfig(ConsoleConfig&&) noexcept = default;
-ConsoleConfig& ConsoleConfig::operator=(ConsoleConfig&&) = default;
+AppWakelocksConfig::AppWakelocksConfig() = default;
+AppWakelocksConfig::~AppWakelocksConfig() = default;
+AppWakelocksConfig::AppWakelocksConfig(const AppWakelocksConfig&) = default;
+AppWakelocksConfig& AppWakelocksConfig::operator=(const AppWakelocksConfig&) = default;
+AppWakelocksConfig::AppWakelocksConfig(AppWakelocksConfig&&) noexcept = default;
+AppWakelocksConfig& AppWakelocksConfig::operator=(AppWakelocksConfig&&) = default;
-bool ConsoleConfig::operator==(const ConsoleConfig& other) const {
+bool AppWakelocksConfig::operator==(const AppWakelocksConfig& other) const {
return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
- && ::protozero::internal::gen_helpers::EqualsField(output_, other.output_)
- && ::protozero::internal::gen_helpers::EqualsField(enable_colors_, other.enable_colors_);
+ && ::protozero::internal::gen_helpers::EqualsField(write_delay_ms_, other.write_delay_ms_)
+ && ::protozero::internal::gen_helpers::EqualsField(filter_duration_below_ms_, other.filter_duration_below_ms_)
+ && ::protozero::internal::gen_helpers::EqualsField(drop_owner_pid_, other.drop_owner_pid_);
}
-bool ConsoleConfig::ParseFromArray(const void* raw, size_t size) {
+bool AppWakelocksConfig::ParseFromArray(const void* raw, size_t size) {
unknown_fields_.clear();
bool packed_error = false;
@@ -24838,11 +24779,14 @@ bool ConsoleConfig::ParseFromArray(const void* raw, size_t size) {
_has_field_.set(field.id());
}
switch (field.id()) {
- case 1 /* output */:
- field.get(&output_);
+ case 1 /* write_delay_ms */:
+ field.get(&write_delay_ms_);
break;
- case 2 /* enable_colors */:
- field.get(&enable_colors_);
+ case 2 /* filter_duration_below_ms */:
+ field.get(&filter_duration_below_ms_);
+ break;
+ case 3 /* drop_owner_pid */:
+ field.get(&drop_owner_pid_);
break;
default:
field.SerializeAndAppendTo(&unknown_fields_);
@@ -24852,27 +24796,32 @@ bool ConsoleConfig::ParseFromArray(const void* raw, size_t size) {
return !packed_error && !dec.bytes_left();
}
-std::string ConsoleConfig::SerializeAsString() const {
+std::string AppWakelocksConfig::SerializeAsString() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsString();
}
-std::vector<uint8_t> ConsoleConfig::SerializeAsArray() const {
+std::vector<uint8_t> AppWakelocksConfig::SerializeAsArray() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsArray();
}
-void ConsoleConfig::Serialize(::protozero::Message* msg) const {
- // Field 1: output
+void AppWakelocksConfig::Serialize(::protozero::Message* msg) const {
+ // Field 1: write_delay_ms
if (_has_field_[1]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(1, output_, msg);
+ ::protozero::internal::gen_helpers::SerializeVarInt(1, write_delay_ms_, msg);
}
- // Field 2: enable_colors
+ // Field 2: filter_duration_below_ms
if (_has_field_[2]) {
- ::protozero::internal::gen_helpers::SerializeTinyVarInt(2, enable_colors_, msg);
+ ::protozero::internal::gen_helpers::SerializeVarInt(2, filter_duration_below_ms_, msg);
+ }
+
+ // Field 3: drop_owner_pid
+ if (_has_field_[3]) {
+ ::protozero::internal::gen_helpers::SerializeTinyVarInt(3, drop_owner_pid_, msg);
}
protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
@@ -24884,7 +24833,7 @@ void ConsoleConfig::Serialize(::protozero::Message* msg) const {
#if defined(__GNUC__) || defined(__clang__)
#pragma GCC diagnostic pop
#endif
-// gen_amalgamated begin source: gen/protos/perfetto/config/linux/journald_config.gen.cc
+// gen_amalgamated begin source: gen/protos/perfetto/config/android/cpu_per_uid_config.gen.cc
// gen_amalgamated expanded: #include "perfetto/protozero/gen_field_helpers.h"
// gen_amalgamated expanded: #include "perfetto/protozero/message.h"
// gen_amalgamated expanded: #include "perfetto/protozero/packed_repeated_fields.h"
@@ -24895,29 +24844,25 @@ void ConsoleConfig::Serialize(::protozero::Message* msg) const {
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wfloat-equal"
#endif
-// gen_amalgamated expanded: #include "protos/perfetto/config/linux/journald_config.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/config/android/cpu_per_uid_config.gen.h"
namespace perfetto {
namespace protos {
namespace gen {
-SystemdJournaldConfig::SystemdJournaldConfig() = default;
-SystemdJournaldConfig::~SystemdJournaldConfig() = default;
-SystemdJournaldConfig::SystemdJournaldConfig(const SystemdJournaldConfig&) = default;
-SystemdJournaldConfig& SystemdJournaldConfig::operator=(const SystemdJournaldConfig&) = default;
-SystemdJournaldConfig::SystemdJournaldConfig(SystemdJournaldConfig&&) noexcept = default;
-SystemdJournaldConfig& SystemdJournaldConfig::operator=(SystemdJournaldConfig&&) = default;
+CpuPerUidConfig::CpuPerUidConfig() = default;
+CpuPerUidConfig::~CpuPerUidConfig() = default;
+CpuPerUidConfig::CpuPerUidConfig(const CpuPerUidConfig&) = default;
+CpuPerUidConfig& CpuPerUidConfig::operator=(const CpuPerUidConfig&) = default;
+CpuPerUidConfig::CpuPerUidConfig(CpuPerUidConfig&&) noexcept = default;
+CpuPerUidConfig& CpuPerUidConfig::operator=(CpuPerUidConfig&&) = default;
-bool SystemdJournaldConfig::operator==(const SystemdJournaldConfig& other) const {
+bool CpuPerUidConfig::operator==(const CpuPerUidConfig& other) const {
return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
- && ::protozero::internal::gen_helpers::EqualsField(min_prio_, other.min_prio_)
- && ::protozero::internal::gen_helpers::EqualsField(filter_identifiers_, other.filter_identifiers_)
- && ::protozero::internal::gen_helpers::EqualsField(filter_units_, other.filter_units_);
+ && ::protozero::internal::gen_helpers::EqualsField(poll_ms_, other.poll_ms_);
}
-bool SystemdJournaldConfig::ParseFromArray(const void* raw, size_t size) {
- filter_identifiers_.clear();
- filter_units_.clear();
+bool CpuPerUidConfig::ParseFromArray(const void* raw, size_t size) {
unknown_fields_.clear();
bool packed_error = false;
@@ -24927,16 +24872,8 @@ bool SystemdJournaldConfig::ParseFromArray(const void* raw, size_t size) {
_has_field_.set(field.id());
}
switch (field.id()) {
- case 1 /* min_prio */:
- field.get(&min_prio_);
- break;
- case 2 /* filter_identifiers */:
- filter_identifiers_.emplace_back();
- ::protozero::internal::gen_helpers::DeserializeString(field, &filter_identifiers_.back());
- break;
- case 3 /* filter_units */:
- filter_units_.emplace_back();
- ::protozero::internal::gen_helpers::DeserializeString(field, &filter_units_.back());
+ case 1 /* poll_ms */:
+ field.get(&poll_ms_);
break;
default:
field.SerializeAndAppendTo(&unknown_fields_);
@@ -24946,32 +24883,22 @@ bool SystemdJournaldConfig::ParseFromArray(const void* raw, size_t size) {
return !packed_error && !dec.bytes_left();
}
-std::string SystemdJournaldConfig::SerializeAsString() const {
+std::string CpuPerUidConfig::SerializeAsString() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsString();
}
-std::vector<uint8_t> SystemdJournaldConfig::SerializeAsArray() const {
+std::vector<uint8_t> CpuPerUidConfig::SerializeAsArray() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsArray();
}
-void SystemdJournaldConfig::Serialize(::protozero::Message* msg) const {
- // Field 1: min_prio
+void CpuPerUidConfig::Serialize(::protozero::Message* msg) const {
+ // Field 1: poll_ms
if (_has_field_[1]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(1, min_prio_, msg);
- }
-
- // Field 2: filter_identifiers
- for (auto& it : filter_identifiers_) {
- ::protozero::internal::gen_helpers::SerializeString(2, it, msg);
- }
-
- // Field 3: filter_units
- for (auto& it : filter_units_) {
- ::protozero::internal::gen_helpers::SerializeString(3, it, msg);
+ ::protozero::internal::gen_helpers::SerializeVarInt(1, poll_ms_, msg);
}
protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
@@ -24983,7 +24910,7 @@ void SystemdJournaldConfig::Serialize(::protozero::Message* msg) const {
#if defined(__GNUC__) || defined(__clang__)
#pragma GCC diagnostic pop
#endif
-// gen_amalgamated begin source: gen/protos/perfetto/config/power/android_power_config.gen.cc
+// gen_amalgamated begin source: gen/protos/perfetto/config/android/display_video_config.gen.cc
// gen_amalgamated expanded: #include "perfetto/protozero/gen_field_helpers.h"
// gen_amalgamated expanded: #include "perfetto/protozero/message.h"
// gen_amalgamated expanded: #include "perfetto/protozero/packed_repeated_fields.h"
@@ -24994,30 +24921,29 @@ void SystemdJournaldConfig::Serialize(::protozero::Message* msg) const {
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wfloat-equal"
#endif
-// gen_amalgamated expanded: #include "protos/perfetto/config/power/android_power_config.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/config/android/display_video_config.gen.h"
namespace perfetto {
namespace protos {
namespace gen {
-AndroidPowerConfig::AndroidPowerConfig() = default;
-AndroidPowerConfig::~AndroidPowerConfig() = default;
-AndroidPowerConfig::AndroidPowerConfig(const AndroidPowerConfig&) = default;
-AndroidPowerConfig& AndroidPowerConfig::operator=(const AndroidPowerConfig&) = default;
-AndroidPowerConfig::AndroidPowerConfig(AndroidPowerConfig&&) noexcept = default;
-AndroidPowerConfig& AndroidPowerConfig::operator=(AndroidPowerConfig&&) = default;
+DisplayVideoConfig::DisplayVideoConfig() = default;
+DisplayVideoConfig::~DisplayVideoConfig() = default;
+DisplayVideoConfig::DisplayVideoConfig(const DisplayVideoConfig&) = default;
+DisplayVideoConfig& DisplayVideoConfig::operator=(const DisplayVideoConfig&) = default;
+DisplayVideoConfig::DisplayVideoConfig(DisplayVideoConfig&&) noexcept = default;
+DisplayVideoConfig& DisplayVideoConfig::operator=(DisplayVideoConfig&&) = default;
-bool AndroidPowerConfig::operator==(const AndroidPowerConfig& other) const {
+bool DisplayVideoConfig::operator==(const DisplayVideoConfig& other) const {
return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
- && ::protozero::internal::gen_helpers::EqualsField(battery_poll_ms_, other.battery_poll_ms_)
- && ::protozero::internal::gen_helpers::EqualsField(battery_counters_, other.battery_counters_)
- && ::protozero::internal::gen_helpers::EqualsField(collect_power_rails_, other.collect_power_rails_)
- && ::protozero::internal::gen_helpers::EqualsField(collect_energy_estimation_breakdown_, other.collect_energy_estimation_breakdown_)
- && ::protozero::internal::gen_helpers::EqualsField(collect_entity_state_residency_, other.collect_entity_state_residency_);
+ && ::protozero::internal::gen_helpers::EqualsField(scale_, other.scale_)
+ && ::protozero::internal::gen_helpers::EqualsField(format_, other.format_)
+ && ::protozero::internal::gen_helpers::EqualsField(key_frame_interval_secs_, other.key_frame_interval_secs_)
+ && ::protozero::internal::gen_helpers::EqualsField(max_stream_size_bytes_, other.max_stream_size_bytes_)
+ && ::protozero::internal::gen_helpers::EqualsField(bitrate_bps_, other.bitrate_bps_);
}
-bool AndroidPowerConfig::ParseFromArray(const void* raw, size_t size) {
- battery_counters_.clear();
+bool DisplayVideoConfig::ParseFromArray(const void* raw, size_t size) {
unknown_fields_.clear();
bool packed_error = false;
@@ -25027,21 +24953,20 @@ bool AndroidPowerConfig::ParseFromArray(const void* raw, size_t size) {
_has_field_.set(field.id());
}
switch (field.id()) {
- case 1 /* battery_poll_ms */:
- field.get(&battery_poll_ms_);
+ case 1 /* scale */:
+ field.get(&scale_);
break;
- case 2 /* battery_counters */:
- battery_counters_.emplace_back();
- field.get(&battery_counters_.back());
+ case 2 /* format */:
+ field.get(&format_);
break;
- case 3 /* collect_power_rails */:
- field.get(&collect_power_rails_);
+ case 3 /* key_frame_interval_secs */:
+ field.get(&key_frame_interval_secs_);
break;
- case 4 /* collect_energy_estimation_breakdown */:
- field.get(&collect_energy_estimation_breakdown_);
+ case 4 /* max_stream_size_bytes */:
+ field.get(&max_stream_size_bytes_);
break;
- case 5 /* collect_entity_state_residency */:
- field.get(&collect_entity_state_residency_);
+ case 5 /* bitrate_bps */:
+ field.get(&bitrate_bps_);
break;
default:
field.SerializeAndAppendTo(&unknown_fields_);
@@ -25051,42 +24976,42 @@ bool AndroidPowerConfig::ParseFromArray(const void* raw, size_t size) {
return !packed_error && !dec.bytes_left();
}
-std::string AndroidPowerConfig::SerializeAsString() const {
+std::string DisplayVideoConfig::SerializeAsString() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsString();
}
-std::vector<uint8_t> AndroidPowerConfig::SerializeAsArray() const {
+std::vector<uint8_t> DisplayVideoConfig::SerializeAsArray() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsArray();
}
-void AndroidPowerConfig::Serialize(::protozero::Message* msg) const {
- // Field 1: battery_poll_ms
+void DisplayVideoConfig::Serialize(::protozero::Message* msg) const {
+ // Field 1: scale
if (_has_field_[1]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(1, battery_poll_ms_, msg);
+ ::protozero::internal::gen_helpers::SerializeFixed(1, scale_, msg);
}
- // Field 2: battery_counters
- for (auto& it : battery_counters_) {
- ::protozero::internal::gen_helpers::SerializeVarInt(2, it, msg);
+ // Field 2: format
+ if (_has_field_[2]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(2, format_, msg);
}
- // Field 3: collect_power_rails
+ // Field 3: key_frame_interval_secs
if (_has_field_[3]) {
- ::protozero::internal::gen_helpers::SerializeTinyVarInt(3, collect_power_rails_, msg);
+ ::protozero::internal::gen_helpers::SerializeVarInt(3, key_frame_interval_secs_, msg);
}
- // Field 4: collect_energy_estimation_breakdown
+ // Field 4: max_stream_size_bytes
if (_has_field_[4]) {
- ::protozero::internal::gen_helpers::SerializeTinyVarInt(4, collect_energy_estimation_breakdown_, msg);
+ ::protozero::internal::gen_helpers::SerializeVarInt(4, max_stream_size_bytes_, msg);
}
- // Field 5: collect_entity_state_residency
+ // Field 5: bitrate_bps
if (_has_field_[5]) {
- ::protozero::internal::gen_helpers::SerializeTinyVarInt(5, collect_entity_state_residency_, msg);
+ ::protozero::internal::gen_helpers::SerializeVarInt(5, bitrate_bps_, msg);
}
protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
@@ -25098,7 +25023,7 @@ void AndroidPowerConfig::Serialize(::protozero::Message* msg) const {
#if defined(__GNUC__) || defined(__clang__)
#pragma GCC diagnostic pop
#endif
-// gen_amalgamated begin source: gen/protos/perfetto/config/priority_boost/priority_boost_config.gen.cc
+// gen_amalgamated begin source: gen/protos/perfetto/config/android/inputmethod_config.gen.cc
// gen_amalgamated expanded: #include "perfetto/protozero/gen_field_helpers.h"
// gen_amalgamated expanded: #include "perfetto/protozero/message.h"
// gen_amalgamated expanded: #include "perfetto/protozero/packed_repeated_fields.h"
@@ -25109,26 +25034,27 @@ void AndroidPowerConfig::Serialize(::protozero::Message* msg) const {
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wfloat-equal"
#endif
-// gen_amalgamated expanded: #include "protos/perfetto/config/priority_boost/priority_boost_config.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/config/android/inputmethod_config.gen.h"
namespace perfetto {
namespace protos {
namespace gen {
-PriorityBoostConfig::PriorityBoostConfig() = default;
-PriorityBoostConfig::~PriorityBoostConfig() = default;
-PriorityBoostConfig::PriorityBoostConfig(const PriorityBoostConfig&) = default;
-PriorityBoostConfig& PriorityBoostConfig::operator=(const PriorityBoostConfig&) = default;
-PriorityBoostConfig::PriorityBoostConfig(PriorityBoostConfig&&) noexcept = default;
-PriorityBoostConfig& PriorityBoostConfig::operator=(PriorityBoostConfig&&) = default;
+InputMethodConfig::InputMethodConfig() = default;
+InputMethodConfig::~InputMethodConfig() = default;
+InputMethodConfig::InputMethodConfig(const InputMethodConfig&) = default;
+InputMethodConfig& InputMethodConfig::operator=(const InputMethodConfig&) = default;
+InputMethodConfig::InputMethodConfig(InputMethodConfig&&) noexcept = default;
+InputMethodConfig& InputMethodConfig::operator=(InputMethodConfig&&) = default;
-bool PriorityBoostConfig::operator==(const PriorityBoostConfig& other) const {
+bool InputMethodConfig::operator==(const InputMethodConfig& other) const {
return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
- && ::protozero::internal::gen_helpers::EqualsField(policy_, other.policy_)
- && ::protozero::internal::gen_helpers::EqualsField(priority_, other.priority_);
+ && ::protozero::internal::gen_helpers::EqualsField(client_, other.client_)
+ && ::protozero::internal::gen_helpers::EqualsField(service_, other.service_)
+ && ::protozero::internal::gen_helpers::EqualsField(manager_service_, other.manager_service_);
}
-bool PriorityBoostConfig::ParseFromArray(const void* raw, size_t size) {
+bool InputMethodConfig::ParseFromArray(const void* raw, size_t size) {
unknown_fields_.clear();
bool packed_error = false;
@@ -25138,11 +25064,14 @@ bool PriorityBoostConfig::ParseFromArray(const void* raw, size_t size) {
_has_field_.set(field.id());
}
switch (field.id()) {
- case 1 /* policy */:
- field.get(&policy_);
+ case 1 /* client */:
+ field.get(&client_);
break;
- case 2 /* priority */:
- field.get(&priority_);
+ case 2 /* service */:
+ field.get(&service_);
+ break;
+ case 3 /* manager_service */:
+ field.get(&manager_service_);
break;
default:
field.SerializeAndAppendTo(&unknown_fields_);
@@ -25152,27 +25081,32 @@ bool PriorityBoostConfig::ParseFromArray(const void* raw, size_t size) {
return !packed_error && !dec.bytes_left();
}
-std::string PriorityBoostConfig::SerializeAsString() const {
+std::string InputMethodConfig::SerializeAsString() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsString();
}
-std::vector<uint8_t> PriorityBoostConfig::SerializeAsArray() const {
+std::vector<uint8_t> InputMethodConfig::SerializeAsArray() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsArray();
}
-void PriorityBoostConfig::Serialize(::protozero::Message* msg) const {
- // Field 1: policy
+void InputMethodConfig::Serialize(::protozero::Message* msg) const {
+ // Field 1: client
if (_has_field_[1]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(1, policy_, msg);
+ ::protozero::internal::gen_helpers::SerializeTinyVarInt(1, client_, msg);
}
- // Field 2: priority
+ // Field 2: service
if (_has_field_[2]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(2, priority_, msg);
+ ::protozero::internal::gen_helpers::SerializeTinyVarInt(2, service_, msg);
+ }
+
+ // Field 3: manager_service
+ if (_has_field_[3]) {
+ ::protozero::internal::gen_helpers::SerializeTinyVarInt(3, manager_service_, msg);
}
protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
@@ -25184,7 +25118,7 @@ void PriorityBoostConfig::Serialize(::protozero::Message* msg) const {
#if defined(__GNUC__) || defined(__clang__)
#pragma GCC diagnostic pop
#endif
-// gen_amalgamated begin source: gen/protos/perfetto/config/process_stats/process_stats_config.gen.cc
+// gen_amalgamated begin source: gen/protos/perfetto/config/android/kernel_wakelocks_config.gen.cc
// gen_amalgamated expanded: #include "perfetto/protozero/gen_field_helpers.h"
// gen_amalgamated expanded: #include "perfetto/protozero/message.h"
// gen_amalgamated expanded: #include "perfetto/protozero/packed_repeated_fields.h"
@@ -25195,36 +25129,25 @@ void PriorityBoostConfig::Serialize(::protozero::Message* msg) const {
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wfloat-equal"
#endif
-// gen_amalgamated expanded: #include "protos/perfetto/config/process_stats/process_stats_config.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/config/android/kernel_wakelocks_config.gen.h"
namespace perfetto {
namespace protos {
namespace gen {
-ProcessStatsConfig::ProcessStatsConfig() = default;
-ProcessStatsConfig::~ProcessStatsConfig() = default;
-ProcessStatsConfig::ProcessStatsConfig(const ProcessStatsConfig&) = default;
-ProcessStatsConfig& ProcessStatsConfig::operator=(const ProcessStatsConfig&) = default;
-ProcessStatsConfig::ProcessStatsConfig(ProcessStatsConfig&&) noexcept = default;
-ProcessStatsConfig& ProcessStatsConfig::operator=(ProcessStatsConfig&&) = default;
+KernelWakelocksConfig::KernelWakelocksConfig() = default;
+KernelWakelocksConfig::~KernelWakelocksConfig() = default;
+KernelWakelocksConfig::KernelWakelocksConfig(const KernelWakelocksConfig&) = default;
+KernelWakelocksConfig& KernelWakelocksConfig::operator=(const KernelWakelocksConfig&) = default;
+KernelWakelocksConfig::KernelWakelocksConfig(KernelWakelocksConfig&&) noexcept = default;
+KernelWakelocksConfig& KernelWakelocksConfig::operator=(KernelWakelocksConfig&&) = default;
-bool ProcessStatsConfig::operator==(const ProcessStatsConfig& other) const {
+bool KernelWakelocksConfig::operator==(const KernelWakelocksConfig& other) const {
return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
- && ::protozero::internal::gen_helpers::EqualsField(quirks_, other.quirks_)
- && ::protozero::internal::gen_helpers::EqualsField(scan_all_processes_on_start_, other.scan_all_processes_on_start_)
- && ::protozero::internal::gen_helpers::EqualsField(record_thread_names_, other.record_thread_names_)
- && ::protozero::internal::gen_helpers::EqualsField(proc_stats_poll_ms_, other.proc_stats_poll_ms_)
- && ::protozero::internal::gen_helpers::EqualsField(proc_stats_cache_ttl_ms_, other.proc_stats_cache_ttl_ms_)
- && ::protozero::internal::gen_helpers::EqualsField(scan_smaps_rollup_, other.scan_smaps_rollup_)
- && ::protozero::internal::gen_helpers::EqualsField(record_process_age_, other.record_process_age_)
- && ::protozero::internal::gen_helpers::EqualsField(record_process_runtime_, other.record_process_runtime_)
- && ::protozero::internal::gen_helpers::EqualsField(record_process_dmabuf_rss_, other.record_process_dmabuf_rss_)
- && ::protozero::internal::gen_helpers::EqualsField(resolve_process_fds_, other.resolve_process_fds_)
- && ::protozero::internal::gen_helpers::EqualsField(skip_main_thread_message_, other.skip_main_thread_message_);
+ && ::protozero::internal::gen_helpers::EqualsField(poll_ms_, other.poll_ms_);
}
-bool ProcessStatsConfig::ParseFromArray(const void* raw, size_t size) {
- quirks_.clear();
+bool KernelWakelocksConfig::ParseFromArray(const void* raw, size_t size) {
unknown_fields_.clear();
bool packed_error = false;
@@ -25234,39 +25157,8 @@ bool ProcessStatsConfig::ParseFromArray(const void* raw, size_t size) {
_has_field_.set(field.id());
}
switch (field.id()) {
- case 1 /* quirks */:
- quirks_.emplace_back();
- field.get(&quirks_.back());
- break;
- case 2 /* scan_all_processes_on_start */:
- field.get(&scan_all_processes_on_start_);
- break;
- case 3 /* record_thread_names */:
- field.get(&record_thread_names_);
- break;
- case 4 /* proc_stats_poll_ms */:
- field.get(&proc_stats_poll_ms_);
- break;
- case 6 /* proc_stats_cache_ttl_ms */:
- field.get(&proc_stats_cache_ttl_ms_);
- break;
- case 10 /* scan_smaps_rollup */:
- field.get(&scan_smaps_rollup_);
- break;
- case 11 /* record_process_age */:
- field.get(&record_process_age_);
- break;
- case 12 /* record_process_runtime */:
- field.get(&record_process_runtime_);
- break;
- case 13 /* record_process_dmabuf_rss */:
- field.get(&record_process_dmabuf_rss_);
- break;
- case 9 /* resolve_process_fds */:
- field.get(&resolve_process_fds_);
- break;
- case 14 /* skip_main_thread_message */:
- field.get(&skip_main_thread_message_);
+ case 1 /* poll_ms */:
+ field.get(&poll_ms_);
break;
default:
field.SerializeAndAppendTo(&unknown_fields_);
@@ -25276,72 +25168,22 @@ bool ProcessStatsConfig::ParseFromArray(const void* raw, size_t size) {
return !packed_error && !dec.bytes_left();
}
-std::string ProcessStatsConfig::SerializeAsString() const {
+std::string KernelWakelocksConfig::SerializeAsString() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsString();
}
-std::vector<uint8_t> ProcessStatsConfig::SerializeAsArray() const {
+std::vector<uint8_t> KernelWakelocksConfig::SerializeAsArray() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsArray();
}
-void ProcessStatsConfig::Serialize(::protozero::Message* msg) const {
- // Field 1: quirks
- for (auto& it : quirks_) {
- ::protozero::internal::gen_helpers::SerializeVarInt(1, it, msg);
- }
-
- // Field 2: scan_all_processes_on_start
- if (_has_field_[2]) {
- ::protozero::internal::gen_helpers::SerializeTinyVarInt(2, scan_all_processes_on_start_, msg);
- }
-
- // Field 3: record_thread_names
- if (_has_field_[3]) {
- ::protozero::internal::gen_helpers::SerializeTinyVarInt(3, record_thread_names_, msg);
- }
-
- // Field 4: proc_stats_poll_ms
- if (_has_field_[4]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(4, proc_stats_poll_ms_, msg);
- }
-
- // Field 6: proc_stats_cache_ttl_ms
- if (_has_field_[6]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(6, proc_stats_cache_ttl_ms_, msg);
- }
-
- // Field 10: scan_smaps_rollup
- if (_has_field_[10]) {
- ::protozero::internal::gen_helpers::SerializeTinyVarInt(10, scan_smaps_rollup_, msg);
- }
-
- // Field 11: record_process_age
- if (_has_field_[11]) {
- ::protozero::internal::gen_helpers::SerializeTinyVarInt(11, record_process_age_, msg);
- }
-
- // Field 12: record_process_runtime
- if (_has_field_[12]) {
- ::protozero::internal::gen_helpers::SerializeTinyVarInt(12, record_process_runtime_, msg);
- }
-
- // Field 13: record_process_dmabuf_rss
- if (_has_field_[13]) {
- ::protozero::internal::gen_helpers::SerializeTinyVarInt(13, record_process_dmabuf_rss_, msg);
- }
-
- // Field 9: resolve_process_fds
- if (_has_field_[9]) {
- ::protozero::internal::gen_helpers::SerializeTinyVarInt(9, resolve_process_fds_, msg);
- }
-
- // Field 14: skip_main_thread_message
- if (_has_field_[14]) {
- ::protozero::internal::gen_helpers::SerializeTinyVarInt(14, skip_main_thread_message_, msg);
+void KernelWakelocksConfig::Serialize(::protozero::Message* msg) const {
+ // Field 1: poll_ms
+ if (_has_field_[1]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(1, poll_ms_, msg);
}
protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
@@ -25353,7 +25195,7 @@ void ProcessStatsConfig::Serialize(::protozero::Message* msg) const {
#if defined(__GNUC__) || defined(__clang__)
#pragma GCC diagnostic pop
#endif
-// gen_amalgamated begin source: gen/protos/perfetto/config/profiling/heapprofd_config.gen.cc
+// gen_amalgamated begin source: gen/protos/perfetto/config/android/network_trace_config.gen.cc
// gen_amalgamated expanded: #include "perfetto/protozero/gen_field_helpers.h"
// gen_amalgamated expanded: #include "perfetto/protozero/message.h"
// gen_amalgamated expanded: #include "perfetto/protozero/packed_repeated_fields.h"
@@ -25364,56 +25206,30 @@ void ProcessStatsConfig::Serialize(::protozero::Message* msg) const {
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wfloat-equal"
#endif
-// gen_amalgamated expanded: #include "protos/perfetto/config/profiling/heapprofd_config.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/config/android/network_trace_config.gen.h"
namespace perfetto {
namespace protos {
namespace gen {
-HeapprofdConfig::HeapprofdConfig() = default;
-HeapprofdConfig::~HeapprofdConfig() = default;
-HeapprofdConfig::HeapprofdConfig(const HeapprofdConfig&) = default;
-HeapprofdConfig& HeapprofdConfig::operator=(const HeapprofdConfig&) = default;
-HeapprofdConfig::HeapprofdConfig(HeapprofdConfig&&) noexcept = default;
-HeapprofdConfig& HeapprofdConfig::operator=(HeapprofdConfig&&) = default;
+NetworkPacketTraceConfig::NetworkPacketTraceConfig() = default;
+NetworkPacketTraceConfig::~NetworkPacketTraceConfig() = default;
+NetworkPacketTraceConfig::NetworkPacketTraceConfig(const NetworkPacketTraceConfig&) = default;
+NetworkPacketTraceConfig& NetworkPacketTraceConfig::operator=(const NetworkPacketTraceConfig&) = default;
+NetworkPacketTraceConfig::NetworkPacketTraceConfig(NetworkPacketTraceConfig&&) noexcept = default;
+NetworkPacketTraceConfig& NetworkPacketTraceConfig::operator=(NetworkPacketTraceConfig&&) = default;
-bool HeapprofdConfig::operator==(const HeapprofdConfig& other) const {
+bool NetworkPacketTraceConfig::operator==(const NetworkPacketTraceConfig& other) const {
return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
- && ::protozero::internal::gen_helpers::EqualsField(sampling_interval_bytes_, other.sampling_interval_bytes_)
- && ::protozero::internal::gen_helpers::EqualsField(adaptive_sampling_shmem_threshold_, other.adaptive_sampling_shmem_threshold_)
- && ::protozero::internal::gen_helpers::EqualsField(adaptive_sampling_max_sampling_interval_bytes_, other.adaptive_sampling_max_sampling_interval_bytes_)
- && ::protozero::internal::gen_helpers::EqualsField(process_cmdline_, other.process_cmdline_)
- && ::protozero::internal::gen_helpers::EqualsField(pid_, other.pid_)
- && ::protozero::internal::gen_helpers::EqualsField(target_installed_by_, other.target_installed_by_)
- && ::protozero::internal::gen_helpers::EqualsField(heaps_, other.heaps_)
- && ::protozero::internal::gen_helpers::EqualsField(exclude_heaps_, other.exclude_heaps_)
- && ::protozero::internal::gen_helpers::EqualsField(stream_allocations_, other.stream_allocations_)
- && ::protozero::internal::gen_helpers::EqualsField(heap_sampling_intervals_, other.heap_sampling_intervals_)
- && ::protozero::internal::gen_helpers::EqualsField(all_heaps_, other.all_heaps_)
- && ::protozero::internal::gen_helpers::EqualsField(all_, other.all_)
- && ::protozero::internal::gen_helpers::EqualsField(min_anonymous_memory_kb_, other.min_anonymous_memory_kb_)
- && ::protozero::internal::gen_helpers::EqualsField(max_heapprofd_memory_kb_, other.max_heapprofd_memory_kb_)
- && ::protozero::internal::gen_helpers::EqualsField(max_heapprofd_cpu_secs_, other.max_heapprofd_cpu_secs_)
- && ::protozero::internal::gen_helpers::EqualsField(skip_symbol_prefix_, other.skip_symbol_prefix_)
- && ::protozero::internal::gen_helpers::EqualsField(continuous_dump_config_, other.continuous_dump_config_)
- && ::protozero::internal::gen_helpers::EqualsField(shmem_size_bytes_, other.shmem_size_bytes_)
- && ::protozero::internal::gen_helpers::EqualsField(block_client_, other.block_client_)
- && ::protozero::internal::gen_helpers::EqualsField(block_client_timeout_us_, other.block_client_timeout_us_)
- && ::protozero::internal::gen_helpers::EqualsField(no_startup_, other.no_startup_)
- && ::protozero::internal::gen_helpers::EqualsField(no_running_, other.no_running_)
- && ::protozero::internal::gen_helpers::EqualsField(dump_at_max_, other.dump_at_max_)
- && ::protozero::internal::gen_helpers::EqualsField(disable_fork_teardown_, other.disable_fork_teardown_)
- && ::protozero::internal::gen_helpers::EqualsField(disable_vfork_detection_, other.disable_vfork_detection_);
+ && ::protozero::internal::gen_helpers::EqualsField(poll_ms_, other.poll_ms_)
+ && ::protozero::internal::gen_helpers::EqualsField(aggregation_threshold_, other.aggregation_threshold_)
+ && ::protozero::internal::gen_helpers::EqualsField(intern_limit_, other.intern_limit_)
+ && ::protozero::internal::gen_helpers::EqualsField(drop_local_port_, other.drop_local_port_)
+ && ::protozero::internal::gen_helpers::EqualsField(drop_remote_port_, other.drop_remote_port_)
+ && ::protozero::internal::gen_helpers::EqualsField(drop_tcp_flags_, other.drop_tcp_flags_);
}
-bool HeapprofdConfig::ParseFromArray(const void* raw, size_t size) {
- process_cmdline_.clear();
- pid_.clear();
- target_installed_by_.clear();
- heaps_.clear();
- exclude_heaps_.clear();
- heap_sampling_intervals_.clear();
- skip_symbol_prefix_.clear();
+bool NetworkPacketTraceConfig::ParseFromArray(const void* raw, size_t size) {
unknown_fields_.clear();
bool packed_error = false;
@@ -25423,87 +25239,23 @@ bool HeapprofdConfig::ParseFromArray(const void* raw, size_t size) {
_has_field_.set(field.id());
}
switch (field.id()) {
- case 1 /* sampling_interval_bytes */:
- field.get(&sampling_interval_bytes_);
- break;
- case 24 /* adaptive_sampling_shmem_threshold */:
- field.get(&adaptive_sampling_shmem_threshold_);
- break;
- case 25 /* adaptive_sampling_max_sampling_interval_bytes */:
- field.get(&adaptive_sampling_max_sampling_interval_bytes_);
- break;
- case 2 /* process_cmdline */:
- process_cmdline_.emplace_back();
- ::protozero::internal::gen_helpers::DeserializeString(field, &process_cmdline_.back());
- break;
- case 4 /* pid */:
- pid_.emplace_back();
- field.get(&pid_.back());
- break;
- case 26 /* target_installed_by */:
- target_installed_by_.emplace_back();
- ::protozero::internal::gen_helpers::DeserializeString(field, &target_installed_by_.back());
- break;
- case 20 /* heaps */:
- heaps_.emplace_back();
- ::protozero::internal::gen_helpers::DeserializeString(field, &heaps_.back());
- break;
- case 27 /* exclude_heaps */:
- exclude_heaps_.emplace_back();
- ::protozero::internal::gen_helpers::DeserializeString(field, &exclude_heaps_.back());
- break;
- case 23 /* stream_allocations */:
- field.get(&stream_allocations_);
- break;
- case 22 /* heap_sampling_intervals */:
- heap_sampling_intervals_.emplace_back();
- field.get(&heap_sampling_intervals_.back());
- break;
- case 21 /* all_heaps */:
- field.get(&all_heaps_);
- break;
- case 5 /* all */:
- field.get(&all_);
- break;
- case 15 /* min_anonymous_memory_kb */:
- field.get(&min_anonymous_memory_kb_);
- break;
- case 16 /* max_heapprofd_memory_kb */:
- field.get(&max_heapprofd_memory_kb_);
- break;
- case 17 /* max_heapprofd_cpu_secs */:
- field.get(&max_heapprofd_cpu_secs_);
- break;
- case 7 /* skip_symbol_prefix */:
- skip_symbol_prefix_.emplace_back();
- ::protozero::internal::gen_helpers::DeserializeString(field, &skip_symbol_prefix_.back());
- break;
- case 6 /* continuous_dump_config */:
- (*continuous_dump_config_).ParseFromArray(field.data(), field.size());
- break;
- case 8 /* shmem_size_bytes */:
- field.get(&shmem_size_bytes_);
- break;
- case 9 /* block_client */:
- field.get(&block_client_);
- break;
- case 14 /* block_client_timeout_us */:
- field.get(&block_client_timeout_us_);
+ case 1 /* poll_ms */:
+ field.get(&poll_ms_);
break;
- case 10 /* no_startup */:
- field.get(&no_startup_);
+ case 2 /* aggregation_threshold */:
+ field.get(&aggregation_threshold_);
break;
- case 11 /* no_running */:
- field.get(&no_running_);
+ case 3 /* intern_limit */:
+ field.get(&intern_limit_);
break;
- case 13 /* dump_at_max */:
- field.get(&dump_at_max_);
+ case 4 /* drop_local_port */:
+ field.get(&drop_local_port_);
break;
- case 18 /* disable_fork_teardown */:
- field.get(&disable_fork_teardown_);
+ case 5 /* drop_remote_port */:
+ field.get(&drop_remote_port_);
break;
- case 19 /* disable_vfork_detection */:
- field.get(&disable_vfork_detection_);
+ case 6 /* drop_tcp_flags */:
+ field.get(&drop_tcp_flags_);
break;
default:
field.SerializeAndAppendTo(&unknown_fields_);
@@ -25513,162 +25265,92 @@ bool HeapprofdConfig::ParseFromArray(const void* raw, size_t size) {
return !packed_error && !dec.bytes_left();
}
-std::string HeapprofdConfig::SerializeAsString() const {
+std::string NetworkPacketTraceConfig::SerializeAsString() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsString();
}
-std::vector<uint8_t> HeapprofdConfig::SerializeAsArray() const {
+std::vector<uint8_t> NetworkPacketTraceConfig::SerializeAsArray() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsArray();
}
-void HeapprofdConfig::Serialize(::protozero::Message* msg) const {
- // Field 1: sampling_interval_bytes
+void NetworkPacketTraceConfig::Serialize(::protozero::Message* msg) const {
+ // Field 1: poll_ms
if (_has_field_[1]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(1, sampling_interval_bytes_, msg);
- }
-
- // Field 24: adaptive_sampling_shmem_threshold
- if (_has_field_[24]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(24, adaptive_sampling_shmem_threshold_, msg);
- }
-
- // Field 25: adaptive_sampling_max_sampling_interval_bytes
- if (_has_field_[25]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(25, adaptive_sampling_max_sampling_interval_bytes_, msg);
- }
-
- // Field 2: process_cmdline
- for (auto& it : process_cmdline_) {
- ::protozero::internal::gen_helpers::SerializeString(2, it, msg);
- }
-
- // Field 4: pid
- for (auto& it : pid_) {
- ::protozero::internal::gen_helpers::SerializeVarInt(4, it, msg);
- }
-
- // Field 26: target_installed_by
- for (auto& it : target_installed_by_) {
- ::protozero::internal::gen_helpers::SerializeString(26, it, msg);
- }
-
- // Field 20: heaps
- for (auto& it : heaps_) {
- ::protozero::internal::gen_helpers::SerializeString(20, it, msg);
- }
-
- // Field 27: exclude_heaps
- for (auto& it : exclude_heaps_) {
- ::protozero::internal::gen_helpers::SerializeString(27, it, msg);
+ ::protozero::internal::gen_helpers::SerializeVarInt(1, poll_ms_, msg);
}
- // Field 23: stream_allocations
- if (_has_field_[23]) {
- ::protozero::internal::gen_helpers::SerializeTinyVarInt(23, stream_allocations_, msg);
+ // Field 2: aggregation_threshold
+ if (_has_field_[2]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(2, aggregation_threshold_, msg);
}
- // Field 22: heap_sampling_intervals
- for (auto& it : heap_sampling_intervals_) {
- ::protozero::internal::gen_helpers::SerializeVarInt(22, it, msg);
+ // Field 3: intern_limit
+ if (_has_field_[3]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(3, intern_limit_, msg);
}
- // Field 21: all_heaps
- if (_has_field_[21]) {
- ::protozero::internal::gen_helpers::SerializeTinyVarInt(21, all_heaps_, msg);
+ // Field 4: drop_local_port
+ if (_has_field_[4]) {
+ ::protozero::internal::gen_helpers::SerializeTinyVarInt(4, drop_local_port_, msg);
}
- // Field 5: all
+ // Field 5: drop_remote_port
if (_has_field_[5]) {
- ::protozero::internal::gen_helpers::SerializeTinyVarInt(5, all_, msg);
- }
-
- // Field 15: min_anonymous_memory_kb
- if (_has_field_[15]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(15, min_anonymous_memory_kb_, msg);
- }
-
- // Field 16: max_heapprofd_memory_kb
- if (_has_field_[16]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(16, max_heapprofd_memory_kb_, msg);
- }
-
- // Field 17: max_heapprofd_cpu_secs
- if (_has_field_[17]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(17, max_heapprofd_cpu_secs_, msg);
- }
-
- // Field 7: skip_symbol_prefix
- for (auto& it : skip_symbol_prefix_) {
- ::protozero::internal::gen_helpers::SerializeString(7, it, msg);
+ ::protozero::internal::gen_helpers::SerializeTinyVarInt(5, drop_remote_port_, msg);
}
- // Field 6: continuous_dump_config
+ // Field 6: drop_tcp_flags
if (_has_field_[6]) {
- (*continuous_dump_config_).Serialize(msg->BeginNestedMessage<::protozero::Message>(6));
- }
-
- // Field 8: shmem_size_bytes
- if (_has_field_[8]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(8, shmem_size_bytes_, msg);
- }
-
- // Field 9: block_client
- if (_has_field_[9]) {
- ::protozero::internal::gen_helpers::SerializeTinyVarInt(9, block_client_, msg);
- }
-
- // Field 14: block_client_timeout_us
- if (_has_field_[14]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(14, block_client_timeout_us_, msg);
- }
-
- // Field 10: no_startup
- if (_has_field_[10]) {
- ::protozero::internal::gen_helpers::SerializeTinyVarInt(10, no_startup_, msg);
- }
-
- // Field 11: no_running
- if (_has_field_[11]) {
- ::protozero::internal::gen_helpers::SerializeTinyVarInt(11, no_running_, msg);
- }
-
- // Field 13: dump_at_max
- if (_has_field_[13]) {
- ::protozero::internal::gen_helpers::SerializeTinyVarInt(13, dump_at_max_, msg);
- }
-
- // Field 18: disable_fork_teardown
- if (_has_field_[18]) {
- ::protozero::internal::gen_helpers::SerializeTinyVarInt(18, disable_fork_teardown_, msg);
- }
-
- // Field 19: disable_vfork_detection
- if (_has_field_[19]) {
- ::protozero::internal::gen_helpers::SerializeTinyVarInt(19, disable_vfork_detection_, msg);
+ ::protozero::internal::gen_helpers::SerializeTinyVarInt(6, drop_tcp_flags_, msg);
}
protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
}
+} // namespace perfetto
+} // namespace protos
+} // namespace gen
+#if defined(__GNUC__) || defined(__clang__)
+#pragma GCC diagnostic pop
+#endif
+// gen_amalgamated begin source: gen/protos/perfetto/config/android/packages_list_config.gen.cc
+// gen_amalgamated expanded: #include "perfetto/protozero/gen_field_helpers.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/message.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/packed_repeated_fields.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/proto_decoder.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/scattered_heap_buffer.h"
+// DO NOT EDIT. Autogenerated by Perfetto cppgen_plugin
+#if defined(__GNUC__) || defined(__clang__)
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wfloat-equal"
+#endif
+// gen_amalgamated expanded: #include "protos/perfetto/config/android/packages_list_config.gen.h"
-HeapprofdConfig_ContinuousDumpConfig::HeapprofdConfig_ContinuousDumpConfig() = default;
-HeapprofdConfig_ContinuousDumpConfig::~HeapprofdConfig_ContinuousDumpConfig() = default;
-HeapprofdConfig_ContinuousDumpConfig::HeapprofdConfig_ContinuousDumpConfig(const HeapprofdConfig_ContinuousDumpConfig&) = default;
-HeapprofdConfig_ContinuousDumpConfig& HeapprofdConfig_ContinuousDumpConfig::operator=(const HeapprofdConfig_ContinuousDumpConfig&) = default;
-HeapprofdConfig_ContinuousDumpConfig::HeapprofdConfig_ContinuousDumpConfig(HeapprofdConfig_ContinuousDumpConfig&&) noexcept = default;
-HeapprofdConfig_ContinuousDumpConfig& HeapprofdConfig_ContinuousDumpConfig::operator=(HeapprofdConfig_ContinuousDumpConfig&&) = default;
+namespace perfetto {
+namespace protos {
+namespace gen {
-bool HeapprofdConfig_ContinuousDumpConfig::operator==(const HeapprofdConfig_ContinuousDumpConfig& other) const {
+PackagesListConfig::PackagesListConfig() = default;
+PackagesListConfig::~PackagesListConfig() = default;
+PackagesListConfig::PackagesListConfig(const PackagesListConfig&) = default;
+PackagesListConfig& PackagesListConfig::operator=(const PackagesListConfig&) = default;
+PackagesListConfig::PackagesListConfig(PackagesListConfig&&) noexcept = default;
+PackagesListConfig& PackagesListConfig::operator=(PackagesListConfig&&) = default;
+
+bool PackagesListConfig::operator==(const PackagesListConfig& other) const {
return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
- && ::protozero::internal::gen_helpers::EqualsField(dump_phase_ms_, other.dump_phase_ms_)
- && ::protozero::internal::gen_helpers::EqualsField(dump_interval_ms_, other.dump_interval_ms_);
+ && ::protozero::internal::gen_helpers::EqualsField(package_name_filter_, other.package_name_filter_)
+ && ::protozero::internal::gen_helpers::EqualsField(package_name_regex_filter_, other.package_name_regex_filter_)
+ && ::protozero::internal::gen_helpers::EqualsField(only_write_on_cpu_use_every_ms_, other.only_write_on_cpu_use_every_ms_);
}
-bool HeapprofdConfig_ContinuousDumpConfig::ParseFromArray(const void* raw, size_t size) {
+bool PackagesListConfig::ParseFromArray(const void* raw, size_t size) {
+ package_name_filter_.clear();
+ package_name_regex_filter_.clear();
unknown_fields_.clear();
bool packed_error = false;
@@ -25678,11 +25360,16 @@ bool HeapprofdConfig_ContinuousDumpConfig::ParseFromArray(const void* raw, size_
_has_field_.set(field.id());
}
switch (field.id()) {
- case 5 /* dump_phase_ms */:
- field.get(&dump_phase_ms_);
+ case 1 /* package_name_filter */:
+ package_name_filter_.emplace_back();
+ ::protozero::internal::gen_helpers::DeserializeString(field, &package_name_filter_.back());
break;
- case 6 /* dump_interval_ms */:
- field.get(&dump_interval_ms_);
+ case 3 /* package_name_regex_filter */:
+ package_name_regex_filter_.emplace_back();
+ ::protozero::internal::gen_helpers::DeserializeString(field, &package_name_regex_filter_.back());
+ break;
+ case 2 /* only_write_on_cpu_use_every_ms */:
+ field.get(&only_write_on_cpu_use_every_ms_);
break;
default:
field.SerializeAndAppendTo(&unknown_fields_);
@@ -25692,27 +25379,32 @@ bool HeapprofdConfig_ContinuousDumpConfig::ParseFromArray(const void* raw, size_
return !packed_error && !dec.bytes_left();
}
-std::string HeapprofdConfig_ContinuousDumpConfig::SerializeAsString() const {
+std::string PackagesListConfig::SerializeAsString() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsString();
}
-std::vector<uint8_t> HeapprofdConfig_ContinuousDumpConfig::SerializeAsArray() const {
+std::vector<uint8_t> PackagesListConfig::SerializeAsArray() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsArray();
}
-void HeapprofdConfig_ContinuousDumpConfig::Serialize(::protozero::Message* msg) const {
- // Field 5: dump_phase_ms
- if (_has_field_[5]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(5, dump_phase_ms_, msg);
+void PackagesListConfig::Serialize(::protozero::Message* msg) const {
+ // Field 1: package_name_filter
+ for (auto& it : package_name_filter_) {
+ ::protozero::internal::gen_helpers::SerializeString(1, it, msg);
}
- // Field 6: dump_interval_ms
- if (_has_field_[6]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(6, dump_interval_ms_, msg);
+ // Field 3: package_name_regex_filter
+ for (auto& it : package_name_regex_filter_) {
+ ::protozero::internal::gen_helpers::SerializeString(3, it, msg);
+ }
+
+ // Field 2: only_write_on_cpu_use_every_ms
+ if (_has_field_[2]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(2, only_write_on_cpu_use_every_ms_, msg);
}
protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
@@ -25724,7 +25416,7 @@ void HeapprofdConfig_ContinuousDumpConfig::Serialize(::protozero::Message* msg)
#if defined(__GNUC__) || defined(__clang__)
#pragma GCC diagnostic pop
#endif
-// gen_amalgamated begin source: gen/protos/perfetto/config/profiling/java_hprof_config.gen.cc
+// gen_amalgamated begin source: gen/protos/perfetto/config/android/pixel_modem_config.gen.cc
// gen_amalgamated expanded: #include "perfetto/protozero/gen_field_helpers.h"
// gen_amalgamated expanded: #include "perfetto/protozero/message.h"
// gen_amalgamated expanded: #include "perfetto/protozero/packed_repeated_fields.h"
@@ -25735,39 +25427,29 @@ void HeapprofdConfig_ContinuousDumpConfig::Serialize(::protozero::Message* msg)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wfloat-equal"
#endif
-// gen_amalgamated expanded: #include "protos/perfetto/config/profiling/java_hprof_config.gen.h"
-// gen_amalgamated expanded: #include "protos/perfetto/config/profiling/smaps_config.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/config/android/pixel_modem_config.gen.h"
namespace perfetto {
namespace protos {
namespace gen {
-JavaHprofConfig::JavaHprofConfig() = default;
-JavaHprofConfig::~JavaHprofConfig() = default;
-JavaHprofConfig::JavaHprofConfig(const JavaHprofConfig&) = default;
-JavaHprofConfig& JavaHprofConfig::operator=(const JavaHprofConfig&) = default;
-JavaHprofConfig::JavaHprofConfig(JavaHprofConfig&&) noexcept = default;
-JavaHprofConfig& JavaHprofConfig::operator=(JavaHprofConfig&&) = default;
+PixelModemConfig::PixelModemConfig() = default;
+PixelModemConfig::~PixelModemConfig() = default;
+PixelModemConfig::PixelModemConfig(const PixelModemConfig&) = default;
+PixelModemConfig& PixelModemConfig::operator=(const PixelModemConfig&) = default;
+PixelModemConfig::PixelModemConfig(PixelModemConfig&&) noexcept = default;
+PixelModemConfig& PixelModemConfig::operator=(PixelModemConfig&&) = default;
-bool JavaHprofConfig::operator==(const JavaHprofConfig& other) const {
+bool PixelModemConfig::operator==(const PixelModemConfig& other) const {
return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
- && ::protozero::internal::gen_helpers::EqualsField(process_cmdline_, other.process_cmdline_)
- && ::protozero::internal::gen_helpers::EqualsField(pid_, other.pid_)
- && ::protozero::internal::gen_helpers::EqualsField(target_installed_by_, other.target_installed_by_)
- && ::protozero::internal::gen_helpers::EqualsField(continuous_dump_config_, other.continuous_dump_config_)
- && ::protozero::internal::gen_helpers::EqualsField(min_anonymous_memory_kb_, other.min_anonymous_memory_kb_)
- && ::protozero::internal::gen_helpers::EqualsField(min_java_heap_size_kb_, other.min_java_heap_size_kb_)
- && ::protozero::internal::gen_helpers::EqualsField(dump_smaps_, other.dump_smaps_)
- && ::protozero::internal::gen_helpers::EqualsField(smaps_config_, other.smaps_config_)
- && ::protozero::internal::gen_helpers::EqualsField(ignored_types_, other.ignored_types_)
- && ::protozero::internal::gen_helpers::EqualsField(dump_oome_callstack_, other.dump_oome_callstack_);
+ && ::protozero::internal::gen_helpers::EqualsField(event_group_, other.event_group_)
+ && ::protozero::internal::gen_helpers::EqualsField(pigweed_hash_allow_list_, other.pigweed_hash_allow_list_)
+ && ::protozero::internal::gen_helpers::EqualsField(pigweed_hash_deny_list_, other.pigweed_hash_deny_list_);
}
-bool JavaHprofConfig::ParseFromArray(const void* raw, size_t size) {
- process_cmdline_.clear();
- pid_.clear();
- target_installed_by_.clear();
- ignored_types_.clear();
+bool PixelModemConfig::ParseFromArray(const void* raw, size_t size) {
+ pigweed_hash_allow_list_.clear();
+ pigweed_hash_deny_list_.clear();
unknown_fields_.clear();
bool packed_error = false;
@@ -25777,39 +25459,16 @@ bool JavaHprofConfig::ParseFromArray(const void* raw, size_t size) {
_has_field_.set(field.id());
}
switch (field.id()) {
- case 1 /* process_cmdline */:
- process_cmdline_.emplace_back();
- ::protozero::internal::gen_helpers::DeserializeString(field, &process_cmdline_.back());
- break;
- case 2 /* pid */:
- pid_.emplace_back();
- field.get(&pid_.back());
- break;
- case 7 /* target_installed_by */:
- target_installed_by_.emplace_back();
- ::protozero::internal::gen_helpers::DeserializeString(field, &target_installed_by_.back());
- break;
- case 3 /* continuous_dump_config */:
- (*continuous_dump_config_).ParseFromArray(field.data(), field.size());
- break;
- case 4 /* min_anonymous_memory_kb */:
- field.get(&min_anonymous_memory_kb_);
- break;
- case 9 /* min_java_heap_size_kb */:
- field.get(&min_java_heap_size_kb_);
- break;
- case 5 /* dump_smaps */:
- field.get(&dump_smaps_);
- break;
- case 8 /* smaps_config */:
- (*smaps_config_).ParseFromArray(field.data(), field.size());
+ case 1 /* event_group */:
+ field.get(&event_group_);
break;
- case 6 /* ignored_types */:
- ignored_types_.emplace_back();
- ::protozero::internal::gen_helpers::DeserializeString(field, &ignored_types_.back());
+ case 2 /* pigweed_hash_allow_list */:
+ pigweed_hash_allow_list_.emplace_back();
+ field.get(&pigweed_hash_allow_list_.back());
break;
- case 10 /* dump_oome_callstack */:
- field.get(&dump_oome_callstack_);
+ case 3 /* pigweed_hash_deny_list */:
+ pigweed_hash_deny_list_.emplace_back();
+ field.get(&pigweed_hash_deny_list_.back());
break;
default:
field.SerializeAndAppendTo(&unknown_fields_);
@@ -25819,88 +25478,152 @@ bool JavaHprofConfig::ParseFromArray(const void* raw, size_t size) {
return !packed_error && !dec.bytes_left();
}
-std::string JavaHprofConfig::SerializeAsString() const {
+std::string PixelModemConfig::SerializeAsString() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsString();
}
-std::vector<uint8_t> JavaHprofConfig::SerializeAsArray() const {
+std::vector<uint8_t> PixelModemConfig::SerializeAsArray() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsArray();
}
-void JavaHprofConfig::Serialize(::protozero::Message* msg) const {
- // Field 1: process_cmdline
- for (auto& it : process_cmdline_) {
- ::protozero::internal::gen_helpers::SerializeString(1, it, msg);
+void PixelModemConfig::Serialize(::protozero::Message* msg) const {
+ // Field 1: event_group
+ if (_has_field_[1]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(1, event_group_, msg);
}
- // Field 2: pid
- for (auto& it : pid_) {
+ // Field 2: pigweed_hash_allow_list
+ for (auto& it : pigweed_hash_allow_list_) {
::protozero::internal::gen_helpers::SerializeVarInt(2, it, msg);
}
- // Field 7: target_installed_by
- for (auto& it : target_installed_by_) {
- ::protozero::internal::gen_helpers::SerializeString(7, it, msg);
+ // Field 3: pigweed_hash_deny_list
+ for (auto& it : pigweed_hash_deny_list_) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(3, it, msg);
}
- // Field 3: continuous_dump_config
- if (_has_field_[3]) {
- (*continuous_dump_config_).Serialize(msg->BeginNestedMessage<::protozero::Message>(3));
- }
+ protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
+}
- // Field 4: min_anonymous_memory_kb
- if (_has_field_[4]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(4, min_anonymous_memory_kb_, msg);
- }
+} // namespace perfetto
+} // namespace protos
+} // namespace gen
+#if defined(__GNUC__) || defined(__clang__)
+#pragma GCC diagnostic pop
+#endif
+// gen_amalgamated begin source: gen/protos/perfetto/config/android/protolog_config.gen.cc
+// gen_amalgamated expanded: #include "perfetto/protozero/gen_field_helpers.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/message.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/packed_repeated_fields.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/proto_decoder.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/scattered_heap_buffer.h"
+// DO NOT EDIT. Autogenerated by Perfetto cppgen_plugin
+#if defined(__GNUC__) || defined(__clang__)
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wfloat-equal"
+#endif
+// gen_amalgamated expanded: #include "protos/perfetto/config/android/protolog_config.gen.h"
- // Field 9: min_java_heap_size_kb
- if (_has_field_[9]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(9, min_java_heap_size_kb_, msg);
- }
+namespace perfetto {
+namespace protos {
+namespace gen {
- // Field 5: dump_smaps
- if (_has_field_[5]) {
- ::protozero::internal::gen_helpers::SerializeTinyVarInt(5, dump_smaps_, msg);
+ProtoLogGroup::ProtoLogGroup() = default;
+ProtoLogGroup::~ProtoLogGroup() = default;
+ProtoLogGroup::ProtoLogGroup(const ProtoLogGroup&) = default;
+ProtoLogGroup& ProtoLogGroup::operator=(const ProtoLogGroup&) = default;
+ProtoLogGroup::ProtoLogGroup(ProtoLogGroup&&) noexcept = default;
+ProtoLogGroup& ProtoLogGroup::operator=(ProtoLogGroup&&) = default;
+
+bool ProtoLogGroup::operator==(const ProtoLogGroup& other) const {
+ return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
+ && ::protozero::internal::gen_helpers::EqualsField(group_name_, other.group_name_)
+ && ::protozero::internal::gen_helpers::EqualsField(log_from_, other.log_from_)
+ && ::protozero::internal::gen_helpers::EqualsField(collect_stacktrace_, other.collect_stacktrace_);
+}
+
+bool ProtoLogGroup::ParseFromArray(const void* raw, size_t size) {
+ unknown_fields_.clear();
+ bool packed_error = false;
+
+ ::protozero::ProtoDecoder dec(raw, size);
+ for (auto field = dec.ReadField(); field.valid(); field = dec.ReadField()) {
+ if (field.id() < _has_field_.size()) {
+ _has_field_.set(field.id());
+ }
+ switch (field.id()) {
+ case 1 /* group_name */:
+ ::protozero::internal::gen_helpers::DeserializeString(field, &group_name_);
+ break;
+ case 2 /* log_from */:
+ field.get(&log_from_);
+ break;
+ case 3 /* collect_stacktrace */:
+ field.get(&collect_stacktrace_);
+ break;
+ default:
+ field.SerializeAndAppendTo(&unknown_fields_);
+ break;
+ }
}
+ return !packed_error && !dec.bytes_left();
+}
- // Field 8: smaps_config
- if (_has_field_[8]) {
- (*smaps_config_).Serialize(msg->BeginNestedMessage<::protozero::Message>(8));
+std::string ProtoLogGroup::SerializeAsString() const {
+ ::protozero::internal::gen_helpers::MessageSerializer msg;
+ Serialize(msg.get());
+ return msg.SerializeAsString();
+}
+
+std::vector<uint8_t> ProtoLogGroup::SerializeAsArray() const {
+ ::protozero::internal::gen_helpers::MessageSerializer msg;
+ Serialize(msg.get());
+ return msg.SerializeAsArray();
+}
+
+void ProtoLogGroup::Serialize(::protozero::Message* msg) const {
+ // Field 1: group_name
+ if (_has_field_[1]) {
+ ::protozero::internal::gen_helpers::SerializeString(1, group_name_, msg);
}
- // Field 6: ignored_types
- for (auto& it : ignored_types_) {
- ::protozero::internal::gen_helpers::SerializeString(6, it, msg);
+ // Field 2: log_from
+ if (_has_field_[2]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(2, log_from_, msg);
}
- // Field 10: dump_oome_callstack
- if (_has_field_[10]) {
- ::protozero::internal::gen_helpers::SerializeTinyVarInt(10, dump_oome_callstack_, msg);
+ // Field 3: collect_stacktrace
+ if (_has_field_[3]) {
+ ::protozero::internal::gen_helpers::SerializeTinyVarInt(3, collect_stacktrace_, msg);
}
protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
}
-JavaHprofConfig_ContinuousDumpConfig::JavaHprofConfig_ContinuousDumpConfig() = default;
-JavaHprofConfig_ContinuousDumpConfig::~JavaHprofConfig_ContinuousDumpConfig() = default;
-JavaHprofConfig_ContinuousDumpConfig::JavaHprofConfig_ContinuousDumpConfig(const JavaHprofConfig_ContinuousDumpConfig&) = default;
-JavaHprofConfig_ContinuousDumpConfig& JavaHprofConfig_ContinuousDumpConfig::operator=(const JavaHprofConfig_ContinuousDumpConfig&) = default;
-JavaHprofConfig_ContinuousDumpConfig::JavaHprofConfig_ContinuousDumpConfig(JavaHprofConfig_ContinuousDumpConfig&&) noexcept = default;
-JavaHprofConfig_ContinuousDumpConfig& JavaHprofConfig_ContinuousDumpConfig::operator=(JavaHprofConfig_ContinuousDumpConfig&&) = default;
+ProtoLogConfig::ProtoLogConfig() = default;
+ProtoLogConfig::~ProtoLogConfig() = default;
+ProtoLogConfig::ProtoLogConfig(const ProtoLogConfig&) = default;
+ProtoLogConfig& ProtoLogConfig::operator=(const ProtoLogConfig&) = default;
+ProtoLogConfig::ProtoLogConfig(ProtoLogConfig&&) noexcept = default;
+ProtoLogConfig& ProtoLogConfig::operator=(ProtoLogConfig&&) = default;
-bool JavaHprofConfig_ContinuousDumpConfig::operator==(const JavaHprofConfig_ContinuousDumpConfig& other) const {
+bool ProtoLogConfig::operator==(const ProtoLogConfig& other) const {
return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
- && ::protozero::internal::gen_helpers::EqualsField(dump_phase_ms_, other.dump_phase_ms_)
- && ::protozero::internal::gen_helpers::EqualsField(dump_interval_ms_, other.dump_interval_ms_)
- && ::protozero::internal::gen_helpers::EqualsField(scan_pids_only_on_start_, other.scan_pids_only_on_start_);
+ && ::protozero::internal::gen_helpers::EqualsField(group_overrides_, other.group_overrides_)
+ && ::protozero::internal::gen_helpers::EqualsField(tracing_mode_, other.tracing_mode_)
+ && ::protozero::internal::gen_helpers::EqualsField(default_log_from_level_, other.default_log_from_level_);
}
-bool JavaHprofConfig_ContinuousDumpConfig::ParseFromArray(const void* raw, size_t size) {
+int ProtoLogConfig::group_overrides_size() const { return static_cast<int>(group_overrides_.size()); }
+void ProtoLogConfig::clear_group_overrides() { group_overrides_.clear(); }
+ProtoLogGroup* ProtoLogConfig::add_group_overrides() { group_overrides_.emplace_back(); return &group_overrides_.back(); }
+bool ProtoLogConfig::ParseFromArray(const void* raw, size_t size) {
+ group_overrides_.clear();
unknown_fields_.clear();
bool packed_error = false;
@@ -25910,14 +25633,15 @@ bool JavaHprofConfig_ContinuousDumpConfig::ParseFromArray(const void* raw, size_
_has_field_.set(field.id());
}
switch (field.id()) {
- case 1 /* dump_phase_ms */:
- field.get(&dump_phase_ms_);
+ case 1 /* group_overrides */:
+ group_overrides_.emplace_back();
+ group_overrides_.back().ParseFromArray(field.data(), field.size());
break;
- case 2 /* dump_interval_ms */:
- field.get(&dump_interval_ms_);
+ case 2 /* tracing_mode */:
+ field.get(&tracing_mode_);
break;
- case 3 /* scan_pids_only_on_start */:
- field.get(&scan_pids_only_on_start_);
+ case 3 /* default_log_from_level */:
+ field.get(&default_log_from_level_);
break;
default:
field.SerializeAndAppendTo(&unknown_fields_);
@@ -25927,32 +25651,32 @@ bool JavaHprofConfig_ContinuousDumpConfig::ParseFromArray(const void* raw, size_
return !packed_error && !dec.bytes_left();
}
-std::string JavaHprofConfig_ContinuousDumpConfig::SerializeAsString() const {
+std::string ProtoLogConfig::SerializeAsString() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsString();
}
-std::vector<uint8_t> JavaHprofConfig_ContinuousDumpConfig::SerializeAsArray() const {
+std::vector<uint8_t> ProtoLogConfig::SerializeAsArray() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsArray();
}
-void JavaHprofConfig_ContinuousDumpConfig::Serialize(::protozero::Message* msg) const {
- // Field 1: dump_phase_ms
- if (_has_field_[1]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(1, dump_phase_ms_, msg);
+void ProtoLogConfig::Serialize(::protozero::Message* msg) const {
+ // Field 1: group_overrides
+ for (auto& it : group_overrides_) {
+ it.Serialize(msg->BeginNestedMessage<::protozero::Message>(1));
}
- // Field 2: dump_interval_ms
+ // Field 2: tracing_mode
if (_has_field_[2]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(2, dump_interval_ms_, msg);
+ ::protozero::internal::gen_helpers::SerializeVarInt(2, tracing_mode_, msg);
}
- // Field 3: scan_pids_only_on_start
+ // Field 3: default_log_from_level
if (_has_field_[3]) {
- ::protozero::internal::gen_helpers::SerializeTinyVarInt(3, scan_pids_only_on_start_, msg);
+ ::protozero::internal::gen_helpers::SerializeVarInt(3, default_log_from_level_, msg);
}
protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
@@ -25964,7 +25688,7 @@ void JavaHprofConfig_ContinuousDumpConfig::Serialize(::protozero::Message* msg)
#if defined(__GNUC__) || defined(__clang__)
#pragma GCC diagnostic pop
#endif
-// gen_amalgamated begin source: gen/protos/perfetto/config/profiling/perf_event_config.gen.cc
+// gen_amalgamated begin source: gen/protos/perfetto/config/android/surfaceflinger_layers_config.gen.cc
// gen_amalgamated expanded: #include "perfetto/protozero/gen_field_helpers.h"
// gen_amalgamated expanded: #include "perfetto/protozero/message.h"
// gen_amalgamated expanded: #include "perfetto/protozero/packed_repeated_fields.h"
@@ -25975,57 +25699,27 @@ void JavaHprofConfig_ContinuousDumpConfig::Serialize(::protozero::Message* msg)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wfloat-equal"
#endif
-// gen_amalgamated expanded: #include "protos/perfetto/config/profiling/perf_event_config.gen.h"
-// gen_amalgamated expanded: #include "protos/perfetto/common/perf_events.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/config/android/surfaceflinger_layers_config.gen.h"
namespace perfetto {
namespace protos {
namespace gen {
-PerfEventConfig::PerfEventConfig() = default;
-PerfEventConfig::~PerfEventConfig() = default;
-PerfEventConfig::PerfEventConfig(const PerfEventConfig&) = default;
-PerfEventConfig& PerfEventConfig::operator=(const PerfEventConfig&) = default;
-PerfEventConfig::PerfEventConfig(PerfEventConfig&&) noexcept = default;
-PerfEventConfig& PerfEventConfig::operator=(PerfEventConfig&&) = default;
+SurfaceFlingerLayersConfig::SurfaceFlingerLayersConfig() = default;
+SurfaceFlingerLayersConfig::~SurfaceFlingerLayersConfig() = default;
+SurfaceFlingerLayersConfig::SurfaceFlingerLayersConfig(const SurfaceFlingerLayersConfig&) = default;
+SurfaceFlingerLayersConfig& SurfaceFlingerLayersConfig::operator=(const SurfaceFlingerLayersConfig&) = default;
+SurfaceFlingerLayersConfig::SurfaceFlingerLayersConfig(SurfaceFlingerLayersConfig&&) noexcept = default;
+SurfaceFlingerLayersConfig& SurfaceFlingerLayersConfig::operator=(SurfaceFlingerLayersConfig&&) = default;
-bool PerfEventConfig::operator==(const PerfEventConfig& other) const {
+bool SurfaceFlingerLayersConfig::operator==(const SurfaceFlingerLayersConfig& other) const {
return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
- && ::protozero::internal::gen_helpers::EqualsField(timebase_, other.timebase_)
- && ::protozero::internal::gen_helpers::EqualsField(followers_, other.followers_)
- && ::protozero::internal::gen_helpers::EqualsField(callstack_sampling_, other.callstack_sampling_)
- && ::protozero::internal::gen_helpers::EqualsField(target_cpu_, other.target_cpu_)
- && ::protozero::internal::gen_helpers::EqualsField(ignore_open_failure_, other.ignore_open_failure_)
- && ::protozero::internal::gen_helpers::EqualsField(cpuid_, other.cpuid_)
- && ::protozero::internal::gen_helpers::EqualsField(ring_buffer_read_period_ms_, other.ring_buffer_read_period_ms_)
- && ::protozero::internal::gen_helpers::EqualsField(ring_buffer_pages_, other.ring_buffer_pages_)
- && ::protozero::internal::gen_helpers::EqualsField(max_enqueued_footprint_kb_, other.max_enqueued_footprint_kb_)
- && ::protozero::internal::gen_helpers::EqualsField(max_daemon_memory_kb_, other.max_daemon_memory_kb_)
- && ::protozero::internal::gen_helpers::EqualsField(remote_descriptor_timeout_ms_, other.remote_descriptor_timeout_ms_)
- && ::protozero::internal::gen_helpers::EqualsField(unwind_state_clear_period_ms_, other.unwind_state_clear_period_ms_)
- && ::protozero::internal::gen_helpers::EqualsField(target_installed_by_, other.target_installed_by_)
- && ::protozero::internal::gen_helpers::EqualsField(all_cpus_, other.all_cpus_)
- && ::protozero::internal::gen_helpers::EqualsField(sampling_frequency_, other.sampling_frequency_)
- && ::protozero::internal::gen_helpers::EqualsField(kernel_frames_, other.kernel_frames_)
- && ::protozero::internal::gen_helpers::EqualsField(target_pid_, other.target_pid_)
- && ::protozero::internal::gen_helpers::EqualsField(target_cmdline_, other.target_cmdline_)
- && ::protozero::internal::gen_helpers::EqualsField(exclude_pid_, other.exclude_pid_)
- && ::protozero::internal::gen_helpers::EqualsField(exclude_cmdline_, other.exclude_cmdline_)
- && ::protozero::internal::gen_helpers::EqualsField(additional_cmdline_count_, other.additional_cmdline_count_);
+ && ::protozero::internal::gen_helpers::EqualsField(mode_, other.mode_)
+ && ::protozero::internal::gen_helpers::EqualsField(trace_flags_, other.trace_flags_);
}
-int PerfEventConfig::followers_size() const { return static_cast<int>(followers_.size()); }
-void PerfEventConfig::clear_followers() { followers_.clear(); }
-FollowerEvent* PerfEventConfig::add_followers() { followers_.emplace_back(); return &followers_.back(); }
-bool PerfEventConfig::ParseFromArray(const void* raw, size_t size) {
- followers_.clear();
- target_cpu_.clear();
- cpuid_.clear();
- target_installed_by_.clear();
- target_pid_.clear();
- target_cmdline_.clear();
- exclude_pid_.clear();
- exclude_cmdline_.clear();
+bool SurfaceFlingerLayersConfig::ParseFromArray(const void* raw, size_t size) {
+ trace_flags_.clear();
unknown_fields_.clear();
bool packed_error = false;
@@ -26035,76 +25729,12 @@ bool PerfEventConfig::ParseFromArray(const void* raw, size_t size) {
_has_field_.set(field.id());
}
switch (field.id()) {
- case 15 /* timebase */:
- (*timebase_).ParseFromArray(field.data(), field.size());
- break;
- case 19 /* followers */:
- followers_.emplace_back();
- followers_.back().ParseFromArray(field.data(), field.size());
- break;
- case 16 /* callstack_sampling */:
- (*callstack_sampling_).ParseFromArray(field.data(), field.size());
- break;
- case 20 /* target_cpu */:
- target_cpu_.emplace_back();
- field.get(&target_cpu_.back());
- break;
- case 21 /* ignore_open_failure */:
- field.get(&ignore_open_failure_);
- break;
- case 22 /* cpuid */:
- cpuid_.emplace_back();
- ::protozero::internal::gen_helpers::DeserializeString(field, &cpuid_.back());
- break;
- case 8 /* ring_buffer_read_period_ms */:
- field.get(&ring_buffer_read_period_ms_);
- break;
- case 3 /* ring_buffer_pages */:
- field.get(&ring_buffer_pages_);
- break;
- case 17 /* max_enqueued_footprint_kb */:
- field.get(&max_enqueued_footprint_kb_);
- break;
- case 13 /* max_daemon_memory_kb */:
- field.get(&max_daemon_memory_kb_);
- break;
- case 9 /* remote_descriptor_timeout_ms */:
- field.get(&remote_descriptor_timeout_ms_);
- break;
- case 10 /* unwind_state_clear_period_ms */:
- field.get(&unwind_state_clear_period_ms_);
- break;
- case 18 /* target_installed_by */:
- target_installed_by_.emplace_back();
- ::protozero::internal::gen_helpers::DeserializeString(field, &target_installed_by_.back());
- break;
- case 1 /* all_cpus */:
- field.get(&all_cpus_);
- break;
- case 2 /* sampling_frequency */:
- field.get(&sampling_frequency_);
- break;
- case 12 /* kernel_frames */:
- field.get(&kernel_frames_);
- break;
- case 4 /* target_pid */:
- target_pid_.emplace_back();
- field.get(&target_pid_.back());
- break;
- case 5 /* target_cmdline */:
- target_cmdline_.emplace_back();
- ::protozero::internal::gen_helpers::DeserializeString(field, &target_cmdline_.back());
- break;
- case 6 /* exclude_pid */:
- exclude_pid_.emplace_back();
- field.get(&exclude_pid_.back());
- break;
- case 7 /* exclude_cmdline */:
- exclude_cmdline_.emplace_back();
- ::protozero::internal::gen_helpers::DeserializeString(field, &exclude_cmdline_.back());
+ case 1 /* mode */:
+ field.get(&mode_);
break;
- case 11 /* additional_cmdline_count */:
- field.get(&additional_cmdline_count_);
+ case 2 /* trace_flags */:
+ trace_flags_.emplace_back();
+ field.get(&trace_flags_.back());
break;
default:
field.SerializeAndAppendTo(&unknown_fields_);
@@ -26114,143 +25744,146 @@ bool PerfEventConfig::ParseFromArray(const void* raw, size_t size) {
return !packed_error && !dec.bytes_left();
}
-std::string PerfEventConfig::SerializeAsString() const {
+std::string SurfaceFlingerLayersConfig::SerializeAsString() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsString();
}
-std::vector<uint8_t> PerfEventConfig::SerializeAsArray() const {
+std::vector<uint8_t> SurfaceFlingerLayersConfig::SerializeAsArray() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsArray();
}
-void PerfEventConfig::Serialize(::protozero::Message* msg) const {
- // Field 15: timebase
- if (_has_field_[15]) {
- (*timebase_).Serialize(msg->BeginNestedMessage<::protozero::Message>(15));
- }
-
- // Field 19: followers
- for (auto& it : followers_) {
- it.Serialize(msg->BeginNestedMessage<::protozero::Message>(19));
- }
-
- // Field 16: callstack_sampling
- if (_has_field_[16]) {
- (*callstack_sampling_).Serialize(msg->BeginNestedMessage<::protozero::Message>(16));
+void SurfaceFlingerLayersConfig::Serialize(::protozero::Message* msg) const {
+ // Field 1: mode
+ if (_has_field_[1]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(1, mode_, msg);
}
- // Field 20: target_cpu
- for (auto& it : target_cpu_) {
- ::protozero::internal::gen_helpers::SerializeVarInt(20, it, msg);
+ // Field 2: trace_flags
+ for (auto& it : trace_flags_) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(2, it, msg);
}
- // Field 21: ignore_open_failure
- if (_has_field_[21]) {
- ::protozero::internal::gen_helpers::SerializeTinyVarInt(21, ignore_open_failure_, msg);
- }
+ protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
+}
- // Field 22: cpuid
- for (auto& it : cpuid_) {
- ::protozero::internal::gen_helpers::SerializeString(22, it, msg);
- }
+} // namespace perfetto
+} // namespace protos
+} // namespace gen
+#if defined(__GNUC__) || defined(__clang__)
+#pragma GCC diagnostic pop
+#endif
+// gen_amalgamated begin source: gen/protos/perfetto/config/android/surfaceflinger_transactions_config.gen.cc
+// gen_amalgamated expanded: #include "perfetto/protozero/gen_field_helpers.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/message.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/packed_repeated_fields.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/proto_decoder.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/scattered_heap_buffer.h"
+// DO NOT EDIT. Autogenerated by Perfetto cppgen_plugin
+#if defined(__GNUC__) || defined(__clang__)
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wfloat-equal"
+#endif
+// gen_amalgamated expanded: #include "protos/perfetto/config/android/surfaceflinger_transactions_config.gen.h"
- // Field 8: ring_buffer_read_period_ms
- if (_has_field_[8]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(8, ring_buffer_read_period_ms_, msg);
- }
+namespace perfetto {
+namespace protos {
+namespace gen {
- // Field 3: ring_buffer_pages
- if (_has_field_[3]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(3, ring_buffer_pages_, msg);
- }
+SurfaceFlingerTransactionsConfig::SurfaceFlingerTransactionsConfig() = default;
+SurfaceFlingerTransactionsConfig::~SurfaceFlingerTransactionsConfig() = default;
+SurfaceFlingerTransactionsConfig::SurfaceFlingerTransactionsConfig(const SurfaceFlingerTransactionsConfig&) = default;
+SurfaceFlingerTransactionsConfig& SurfaceFlingerTransactionsConfig::operator=(const SurfaceFlingerTransactionsConfig&) = default;
+SurfaceFlingerTransactionsConfig::SurfaceFlingerTransactionsConfig(SurfaceFlingerTransactionsConfig&&) noexcept = default;
+SurfaceFlingerTransactionsConfig& SurfaceFlingerTransactionsConfig::operator=(SurfaceFlingerTransactionsConfig&&) = default;
- // Field 17: max_enqueued_footprint_kb
- if (_has_field_[17]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(17, max_enqueued_footprint_kb_, msg);
- }
+bool SurfaceFlingerTransactionsConfig::operator==(const SurfaceFlingerTransactionsConfig& other) const {
+ return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
+ && ::protozero::internal::gen_helpers::EqualsField(mode_, other.mode_);
+}
- // Field 13: max_daemon_memory_kb
- if (_has_field_[13]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(13, max_daemon_memory_kb_, msg);
- }
+bool SurfaceFlingerTransactionsConfig::ParseFromArray(const void* raw, size_t size) {
+ unknown_fields_.clear();
+ bool packed_error = false;
- // Field 9: remote_descriptor_timeout_ms
- if (_has_field_[9]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(9, remote_descriptor_timeout_ms_, msg);
+ ::protozero::ProtoDecoder dec(raw, size);
+ for (auto field = dec.ReadField(); field.valid(); field = dec.ReadField()) {
+ if (field.id() < _has_field_.size()) {
+ _has_field_.set(field.id());
+ }
+ switch (field.id()) {
+ case 1 /* mode */:
+ field.get(&mode_);
+ break;
+ default:
+ field.SerializeAndAppendTo(&unknown_fields_);
+ break;
+ }
}
+ return !packed_error && !dec.bytes_left();
+}
- // Field 10: unwind_state_clear_period_ms
- if (_has_field_[10]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(10, unwind_state_clear_period_ms_, msg);
- }
+std::string SurfaceFlingerTransactionsConfig::SerializeAsString() const {
+ ::protozero::internal::gen_helpers::MessageSerializer msg;
+ Serialize(msg.get());
+ return msg.SerializeAsString();
+}
- // Field 18: target_installed_by
- for (auto& it : target_installed_by_) {
- ::protozero::internal::gen_helpers::SerializeString(18, it, msg);
- }
+std::vector<uint8_t> SurfaceFlingerTransactionsConfig::SerializeAsArray() const {
+ ::protozero::internal::gen_helpers::MessageSerializer msg;
+ Serialize(msg.get());
+ return msg.SerializeAsArray();
+}
- // Field 1: all_cpus
+void SurfaceFlingerTransactionsConfig::Serialize(::protozero::Message* msg) const {
+ // Field 1: mode
if (_has_field_[1]) {
- ::protozero::internal::gen_helpers::SerializeTinyVarInt(1, all_cpus_, msg);
- }
-
- // Field 2: sampling_frequency
- if (_has_field_[2]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(2, sampling_frequency_, msg);
- }
-
- // Field 12: kernel_frames
- if (_has_field_[12]) {
- ::protozero::internal::gen_helpers::SerializeTinyVarInt(12, kernel_frames_, msg);
- }
-
- // Field 4: target_pid
- for (auto& it : target_pid_) {
- ::protozero::internal::gen_helpers::SerializeVarInt(4, it, msg);
- }
-
- // Field 5: target_cmdline
- for (auto& it : target_cmdline_) {
- ::protozero::internal::gen_helpers::SerializeString(5, it, msg);
- }
-
- // Field 6: exclude_pid
- for (auto& it : exclude_pid_) {
- ::protozero::internal::gen_helpers::SerializeVarInt(6, it, msg);
- }
-
- // Field 7: exclude_cmdline
- for (auto& it : exclude_cmdline_) {
- ::protozero::internal::gen_helpers::SerializeString(7, it, msg);
- }
-
- // Field 11: additional_cmdline_count
- if (_has_field_[11]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(11, additional_cmdline_count_, msg);
+ ::protozero::internal::gen_helpers::SerializeVarInt(1, mode_, msg);
}
protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
}
+} // namespace perfetto
+} // namespace protos
+} // namespace gen
+#if defined(__GNUC__) || defined(__clang__)
+#pragma GCC diagnostic pop
+#endif
+// gen_amalgamated begin source: gen/protos/perfetto/config/android/user_list_config.gen.cc
+// gen_amalgamated expanded: #include "perfetto/protozero/gen_field_helpers.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/message.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/packed_repeated_fields.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/proto_decoder.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/scattered_heap_buffer.h"
+// DO NOT EDIT. Autogenerated by Perfetto cppgen_plugin
+#if defined(__GNUC__) || defined(__clang__)
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wfloat-equal"
+#endif
+// gen_amalgamated expanded: #include "protos/perfetto/config/android/user_list_config.gen.h"
-PerfEventConfig_CallstackSampling::PerfEventConfig_CallstackSampling() = default;
-PerfEventConfig_CallstackSampling::~PerfEventConfig_CallstackSampling() = default;
-PerfEventConfig_CallstackSampling::PerfEventConfig_CallstackSampling(const PerfEventConfig_CallstackSampling&) = default;
-PerfEventConfig_CallstackSampling& PerfEventConfig_CallstackSampling::operator=(const PerfEventConfig_CallstackSampling&) = default;
-PerfEventConfig_CallstackSampling::PerfEventConfig_CallstackSampling(PerfEventConfig_CallstackSampling&&) noexcept = default;
-PerfEventConfig_CallstackSampling& PerfEventConfig_CallstackSampling::operator=(PerfEventConfig_CallstackSampling&&) = default;
+namespace perfetto {
+namespace protos {
+namespace gen {
-bool PerfEventConfig_CallstackSampling::operator==(const PerfEventConfig_CallstackSampling& other) const {
+AndroidUserListConfig::AndroidUserListConfig() = default;
+AndroidUserListConfig::~AndroidUserListConfig() = default;
+AndroidUserListConfig::AndroidUserListConfig(const AndroidUserListConfig&) = default;
+AndroidUserListConfig& AndroidUserListConfig::operator=(const AndroidUserListConfig&) = default;
+AndroidUserListConfig::AndroidUserListConfig(AndroidUserListConfig&&) noexcept = default;
+AndroidUserListConfig& AndroidUserListConfig::operator=(AndroidUserListConfig&&) = default;
+
+bool AndroidUserListConfig::operator==(const AndroidUserListConfig& other) const {
return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
- && ::protozero::internal::gen_helpers::EqualsField(scope_, other.scope_)
- && ::protozero::internal::gen_helpers::EqualsField(kernel_frames_, other.kernel_frames_)
- && ::protozero::internal::gen_helpers::EqualsField(user_frames_, other.user_frames_);
+ && ::protozero::internal::gen_helpers::EqualsField(user_type_filter_, other.user_type_filter_);
}
-bool PerfEventConfig_CallstackSampling::ParseFromArray(const void* raw, size_t size) {
+bool AndroidUserListConfig::ParseFromArray(const void* raw, size_t size) {
+ user_type_filter_.clear();
unknown_fields_.clear();
bool packed_error = false;
@@ -26260,14 +25893,9 @@ bool PerfEventConfig_CallstackSampling::ParseFromArray(const void* raw, size_t s
_has_field_.set(field.id());
}
switch (field.id()) {
- case 1 /* scope */:
- (*scope_).ParseFromArray(field.data(), field.size());
- break;
- case 2 /* kernel_frames */:
- field.get(&kernel_frames_);
- break;
- case 3 /* user_frames */:
- field.get(&user_frames_);
+ case 1 /* user_type_filter */:
+ user_type_filter_.emplace_back();
+ ::protozero::internal::gen_helpers::DeserializeString(field, &user_type_filter_.back());
break;
default:
field.SerializeAndAppendTo(&unknown_fields_);
@@ -26277,140 +25905,22 @@ bool PerfEventConfig_CallstackSampling::ParseFromArray(const void* raw, size_t s
return !packed_error && !dec.bytes_left();
}
-std::string PerfEventConfig_CallstackSampling::SerializeAsString() const {
+std::string AndroidUserListConfig::SerializeAsString() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsString();
}
-std::vector<uint8_t> PerfEventConfig_CallstackSampling::SerializeAsArray() const {
+std::vector<uint8_t> AndroidUserListConfig::SerializeAsArray() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsArray();
}
-void PerfEventConfig_CallstackSampling::Serialize(::protozero::Message* msg) const {
- // Field 1: scope
- if (_has_field_[1]) {
- (*scope_).Serialize(msg->BeginNestedMessage<::protozero::Message>(1));
- }
-
- // Field 2: kernel_frames
- if (_has_field_[2]) {
- ::protozero::internal::gen_helpers::SerializeTinyVarInt(2, kernel_frames_, msg);
- }
-
- // Field 3: user_frames
- if (_has_field_[3]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(3, user_frames_, msg);
- }
-
- protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
-}
-
-
-PerfEventConfig_Scope::PerfEventConfig_Scope() = default;
-PerfEventConfig_Scope::~PerfEventConfig_Scope() = default;
-PerfEventConfig_Scope::PerfEventConfig_Scope(const PerfEventConfig_Scope&) = default;
-PerfEventConfig_Scope& PerfEventConfig_Scope::operator=(const PerfEventConfig_Scope&) = default;
-PerfEventConfig_Scope::PerfEventConfig_Scope(PerfEventConfig_Scope&&) noexcept = default;
-PerfEventConfig_Scope& PerfEventConfig_Scope::operator=(PerfEventConfig_Scope&&) = default;
-
-bool PerfEventConfig_Scope::operator==(const PerfEventConfig_Scope& other) const {
- return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
- && ::protozero::internal::gen_helpers::EqualsField(target_pid_, other.target_pid_)
- && ::protozero::internal::gen_helpers::EqualsField(target_cmdline_, other.target_cmdline_)
- && ::protozero::internal::gen_helpers::EqualsField(exclude_pid_, other.exclude_pid_)
- && ::protozero::internal::gen_helpers::EqualsField(exclude_cmdline_, other.exclude_cmdline_)
- && ::protozero::internal::gen_helpers::EqualsField(additional_cmdline_count_, other.additional_cmdline_count_)
- && ::protozero::internal::gen_helpers::EqualsField(process_shard_count_, other.process_shard_count_);
-}
-
-bool PerfEventConfig_Scope::ParseFromArray(const void* raw, size_t size) {
- target_pid_.clear();
- target_cmdline_.clear();
- exclude_pid_.clear();
- exclude_cmdline_.clear();
- unknown_fields_.clear();
- bool packed_error = false;
-
- ::protozero::ProtoDecoder dec(raw, size);
- for (auto field = dec.ReadField(); field.valid(); field = dec.ReadField()) {
- if (field.id() < _has_field_.size()) {
- _has_field_.set(field.id());
- }
- switch (field.id()) {
- case 1 /* target_pid */:
- target_pid_.emplace_back();
- field.get(&target_pid_.back());
- break;
- case 2 /* target_cmdline */:
- target_cmdline_.emplace_back();
- ::protozero::internal::gen_helpers::DeserializeString(field, &target_cmdline_.back());
- break;
- case 3 /* exclude_pid */:
- exclude_pid_.emplace_back();
- field.get(&exclude_pid_.back());
- break;
- case 4 /* exclude_cmdline */:
- exclude_cmdline_.emplace_back();
- ::protozero::internal::gen_helpers::DeserializeString(field, &exclude_cmdline_.back());
- break;
- case 5 /* additional_cmdline_count */:
- field.get(&additional_cmdline_count_);
- break;
- case 6 /* process_shard_count */:
- field.get(&process_shard_count_);
- break;
- default:
- field.SerializeAndAppendTo(&unknown_fields_);
- break;
- }
- }
- return !packed_error && !dec.bytes_left();
-}
-
-std::string PerfEventConfig_Scope::SerializeAsString() const {
- ::protozero::internal::gen_helpers::MessageSerializer msg;
- Serialize(msg.get());
- return msg.SerializeAsString();
-}
-
-std::vector<uint8_t> PerfEventConfig_Scope::SerializeAsArray() const {
- ::protozero::internal::gen_helpers::MessageSerializer msg;
- Serialize(msg.get());
- return msg.SerializeAsArray();
-}
-
-void PerfEventConfig_Scope::Serialize(::protozero::Message* msg) const {
- // Field 1: target_pid
- for (auto& it : target_pid_) {
- ::protozero::internal::gen_helpers::SerializeVarInt(1, it, msg);
- }
-
- // Field 2: target_cmdline
- for (auto& it : target_cmdline_) {
- ::protozero::internal::gen_helpers::SerializeString(2, it, msg);
- }
-
- // Field 3: exclude_pid
- for (auto& it : exclude_pid_) {
- ::protozero::internal::gen_helpers::SerializeVarInt(3, it, msg);
- }
-
- // Field 4: exclude_cmdline
- for (auto& it : exclude_cmdline_) {
- ::protozero::internal::gen_helpers::SerializeString(4, it, msg);
- }
-
- // Field 5: additional_cmdline_count
- if (_has_field_[5]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(5, additional_cmdline_count_, msg);
- }
-
- // Field 6: process_shard_count
- if (_has_field_[6]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(6, process_shard_count_, msg);
+void AndroidUserListConfig::Serialize(::protozero::Message* msg) const {
+ // Field 1: user_type_filter
+ for (auto& it : user_type_filter_) {
+ ::protozero::internal::gen_helpers::SerializeString(1, it, msg);
}
protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
@@ -26422,7 +25932,7 @@ void PerfEventConfig_Scope::Serialize(::protozero::Message* msg) const {
#if defined(__GNUC__) || defined(__clang__)
#pragma GCC diagnostic pop
#endif
-// gen_amalgamated begin source: gen/protos/perfetto/config/profiling/smaps_config.gen.cc
+// gen_amalgamated begin source: gen/protos/perfetto/config/android/windowmanager_config.gen.cc
// gen_amalgamated expanded: #include "perfetto/protozero/gen_field_helpers.h"
// gen_amalgamated expanded: #include "perfetto/protozero/message.h"
// gen_amalgamated expanded: #include "perfetto/protozero/packed_repeated_fields.h"
@@ -26433,30 +25943,27 @@ void PerfEventConfig_Scope::Serialize(::protozero::Message* msg) const {
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wfloat-equal"
#endif
-// gen_amalgamated expanded: #include "protos/perfetto/config/profiling/smaps_config.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/config/android/windowmanager_config.gen.h"
namespace perfetto {
namespace protos {
namespace gen {
-RedactionRule::RedactionRule() = default;
-RedactionRule::~RedactionRule() = default;
-RedactionRule::RedactionRule(const RedactionRule&) = default;
-RedactionRule& RedactionRule::operator=(const RedactionRule&) = default;
-RedactionRule::RedactionRule(RedactionRule&&) noexcept = default;
-RedactionRule& RedactionRule::operator=(RedactionRule&&) = default;
+WindowManagerConfig::WindowManagerConfig() = default;
+WindowManagerConfig::~WindowManagerConfig() = default;
+WindowManagerConfig::WindowManagerConfig(const WindowManagerConfig&) = default;
+WindowManagerConfig& WindowManagerConfig::operator=(const WindowManagerConfig&) = default;
+WindowManagerConfig::WindowManagerConfig(WindowManagerConfig&&) noexcept = default;
+WindowManagerConfig& WindowManagerConfig::operator=(WindowManagerConfig&&) = default;
-bool RedactionRule::operator==(const RedactionRule& other) const {
+bool WindowManagerConfig::operator==(const WindowManagerConfig& other) const {
return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
- && ::protozero::internal::gen_helpers::EqualsField(pattern_, other.pattern_)
- && ::protozero::internal::gen_helpers::EqualsField(match_mode_, other.match_mode_)
- && ::protozero::internal::gen_helpers::EqualsField(keep_full_, other.keep_full_)
- && ::protozero::internal::gen_helpers::EqualsField(replacement_name_, other.replacement_name_)
- && ::protozero::internal::gen_helpers::EqualsField(keep_file_extension_, other.keep_file_extension_)
- && ::protozero::internal::gen_helpers::EqualsField(keep_path_elements_, other.keep_path_elements_);
+ && ::protozero::internal::gen_helpers::EqualsField(log_frequency_, other.log_frequency_)
+ && ::protozero::internal::gen_helpers::EqualsField(log_level_, other.log_level_)
+ && ::protozero::internal::gen_helpers::EqualsField(log_mode_, other.log_mode_);
}
-bool RedactionRule::ParseFromArray(const void* raw, size_t size) {
+bool WindowManagerConfig::ParseFromArray(const void* raw, size_t size) {
unknown_fields_.clear();
bool packed_error = false;
@@ -26466,23 +25973,14 @@ bool RedactionRule::ParseFromArray(const void* raw, size_t size) {
_has_field_.set(field.id());
}
switch (field.id()) {
- case 1 /* pattern */:
- ::protozero::internal::gen_helpers::DeserializeString(field, &pattern_);
- break;
- case 2 /* match_mode */:
- field.get(&match_mode_);
- break;
- case 3 /* keep_full */:
- field.get(&keep_full_);
- break;
- case 4 /* replacement_name */:
- ::protozero::internal::gen_helpers::DeserializeString(field, &replacement_name_);
+ case 1 /* log_frequency */:
+ field.get(&log_frequency_);
break;
- case 5 /* keep_file_extension */:
- field.get(&keep_file_extension_);
+ case 2 /* log_level */:
+ field.get(&log_level_);
break;
- case 6 /* keep_path_elements */:
- field.get(&keep_path_elements_);
+ case 3 /* log_mode */:
+ field.get(&log_mode_);
break;
default:
field.SerializeAndAppendTo(&unknown_fields_);
@@ -26492,127 +25990,32 @@ bool RedactionRule::ParseFromArray(const void* raw, size_t size) {
return !packed_error && !dec.bytes_left();
}
-std::string RedactionRule::SerializeAsString() const {
+std::string WindowManagerConfig::SerializeAsString() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsString();
}
-std::vector<uint8_t> RedactionRule::SerializeAsArray() const {
+std::vector<uint8_t> WindowManagerConfig::SerializeAsArray() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsArray();
}
-void RedactionRule::Serialize(::protozero::Message* msg) const {
- // Field 1: pattern
+void WindowManagerConfig::Serialize(::protozero::Message* msg) const {
+ // Field 1: log_frequency
if (_has_field_[1]) {
- ::protozero::internal::gen_helpers::SerializeString(1, pattern_, msg);
+ ::protozero::internal::gen_helpers::SerializeVarInt(1, log_frequency_, msg);
}
- // Field 2: match_mode
+ // Field 2: log_level
if (_has_field_[2]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(2, match_mode_, msg);
+ ::protozero::internal::gen_helpers::SerializeVarInt(2, log_level_, msg);
}
- // Field 3: keep_full
+ // Field 3: log_mode
if (_has_field_[3]) {
- ::protozero::internal::gen_helpers::SerializeTinyVarInt(3, keep_full_, msg);
- }
-
- // Field 4: replacement_name
- if (_has_field_[4]) {
- ::protozero::internal::gen_helpers::SerializeString(4, replacement_name_, msg);
- }
-
- // Field 5: keep_file_extension
- if (_has_field_[5]) {
- ::protozero::internal::gen_helpers::SerializeTinyVarInt(5, keep_file_extension_, msg);
- }
-
- // Field 6: keep_path_elements
- if (_has_field_[6]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(6, keep_path_elements_, msg);
- }
-
- protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
-}
-
-
-SmapsConfig::SmapsConfig() = default;
-SmapsConfig::~SmapsConfig() = default;
-SmapsConfig::SmapsConfig(const SmapsConfig&) = default;
-SmapsConfig& SmapsConfig::operator=(const SmapsConfig&) = default;
-SmapsConfig::SmapsConfig(SmapsConfig&&) noexcept = default;
-SmapsConfig& SmapsConfig::operator=(SmapsConfig&&) = default;
-
-bool SmapsConfig::operator==(const SmapsConfig& other) const {
- return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
- && ::protozero::internal::gen_helpers::EqualsField(vma_fields_, other.vma_fields_)
- && ::protozero::internal::gen_helpers::EqualsField(unaggregated_, other.unaggregated_)
- && ::protozero::internal::gen_helpers::EqualsField(name_redaction_rules_, other.name_redaction_rules_);
-}
-
-int SmapsConfig::name_redaction_rules_size() const { return static_cast<int>(name_redaction_rules_.size()); }
-void SmapsConfig::clear_name_redaction_rules() { name_redaction_rules_.clear(); }
-RedactionRule* SmapsConfig::add_name_redaction_rules() { name_redaction_rules_.emplace_back(); return &name_redaction_rules_.back(); }
-bool SmapsConfig::ParseFromArray(const void* raw, size_t size) {
- vma_fields_.clear();
- name_redaction_rules_.clear();
- unknown_fields_.clear();
- bool packed_error = false;
-
- ::protozero::ProtoDecoder dec(raw, size);
- for (auto field = dec.ReadField(); field.valid(); field = dec.ReadField()) {
- if (field.id() < _has_field_.size()) {
- _has_field_.set(field.id());
- }
- switch (field.id()) {
- case 1 /* vma_fields */:
- vma_fields_.emplace_back();
- field.get(&vma_fields_.back());
- break;
- case 2 /* unaggregated */:
- field.get(&unaggregated_);
- break;
- case 3 /* name_redaction_rules */:
- name_redaction_rules_.emplace_back();
- name_redaction_rules_.back().ParseFromArray(field.data(), field.size());
- break;
- default:
- field.SerializeAndAppendTo(&unknown_fields_);
- break;
- }
- }
- return !packed_error && !dec.bytes_left();
-}
-
-std::string SmapsConfig::SerializeAsString() const {
- ::protozero::internal::gen_helpers::MessageSerializer msg;
- Serialize(msg.get());
- return msg.SerializeAsString();
-}
-
-std::vector<uint8_t> SmapsConfig::SerializeAsArray() const {
- ::protozero::internal::gen_helpers::MessageSerializer msg;
- Serialize(msg.get());
- return msg.SerializeAsArray();
-}
-
-void SmapsConfig::Serialize(::protozero::Message* msg) const {
- // Field 1: vma_fields
- for (auto& it : vma_fields_) {
- ::protozero::internal::gen_helpers::SerializeVarInt(1, it, msg);
- }
-
- // Field 2: unaggregated
- if (_has_field_[2]) {
- ::protozero::internal::gen_helpers::SerializeTinyVarInt(2, unaggregated_, msg);
- }
-
- // Field 3: name_redaction_rules
- for (auto& it : name_redaction_rules_) {
- it.Serialize(msg->BeginNestedMessage<::protozero::Message>(3));
+ ::protozero::internal::gen_helpers::SerializeVarInt(3, log_mode_, msg);
}
protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
@@ -26624,7 +26027,7 @@ void SmapsConfig::Serialize(::protozero::Message* msg) const {
#if defined(__GNUC__) || defined(__clang__)
#pragma GCC diagnostic pop
#endif
-// gen_amalgamated begin source: gen/protos/perfetto/config/protovm/protovm_config.gen.cc
+// gen_amalgamated begin source: gen/protos/perfetto/config/ftrace/frozen_ftrace_config.gen.cc
// gen_amalgamated expanded: #include "perfetto/protozero/gen_field_helpers.h"
// gen_amalgamated expanded: #include "perfetto/protozero/message.h"
// gen_amalgamated expanded: #include "perfetto/protozero/packed_repeated_fields.h"
@@ -26635,25 +26038,25 @@ void SmapsConfig::Serialize(::protozero::Message* msg) const {
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wfloat-equal"
#endif
-// gen_amalgamated expanded: #include "protos/perfetto/config/protovm/protovm_config.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/config/ftrace/frozen_ftrace_config.gen.h"
namespace perfetto {
namespace protos {
namespace gen {
-ProtoVmConfig::ProtoVmConfig() = default;
-ProtoVmConfig::~ProtoVmConfig() = default;
-ProtoVmConfig::ProtoVmConfig(const ProtoVmConfig&) = default;
-ProtoVmConfig& ProtoVmConfig::operator=(const ProtoVmConfig&) = default;
-ProtoVmConfig::ProtoVmConfig(ProtoVmConfig&&) noexcept = default;
-ProtoVmConfig& ProtoVmConfig::operator=(ProtoVmConfig&&) = default;
+FrozenFtraceConfig::FrozenFtraceConfig() = default;
+FrozenFtraceConfig::~FrozenFtraceConfig() = default;
+FrozenFtraceConfig::FrozenFtraceConfig(const FrozenFtraceConfig&) = default;
+FrozenFtraceConfig& FrozenFtraceConfig::operator=(const FrozenFtraceConfig&) = default;
+FrozenFtraceConfig::FrozenFtraceConfig(FrozenFtraceConfig&&) noexcept = default;
+FrozenFtraceConfig& FrozenFtraceConfig::operator=(FrozenFtraceConfig&&) = default;
-bool ProtoVmConfig::operator==(const ProtoVmConfig& other) const {
+bool FrozenFtraceConfig::operator==(const FrozenFtraceConfig& other) const {
return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
- && ::protozero::internal::gen_helpers::EqualsField(memory_limit_kb_, other.memory_limit_kb_);
+ && ::protozero::internal::gen_helpers::EqualsField(instance_name_, other.instance_name_);
}
-bool ProtoVmConfig::ParseFromArray(const void* raw, size_t size) {
+bool FrozenFtraceConfig::ParseFromArray(const void* raw, size_t size) {
unknown_fields_.clear();
bool packed_error = false;
@@ -26663,8 +26066,8 @@ bool ProtoVmConfig::ParseFromArray(const void* raw, size_t size) {
_has_field_.set(field.id());
}
switch (field.id()) {
- case 1 /* memory_limit_kb */:
- field.get(&memory_limit_kb_);
+ case 1 /* instance_name */:
+ ::protozero::internal::gen_helpers::DeserializeString(field, &instance_name_);
break;
default:
field.SerializeAndAppendTo(&unknown_fields_);
@@ -26674,22 +26077,22 @@ bool ProtoVmConfig::ParseFromArray(const void* raw, size_t size) {
return !packed_error && !dec.bytes_left();
}
-std::string ProtoVmConfig::SerializeAsString() const {
+std::string FrozenFtraceConfig::SerializeAsString() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsString();
}
-std::vector<uint8_t> ProtoVmConfig::SerializeAsArray() const {
+std::vector<uint8_t> FrozenFtraceConfig::SerializeAsArray() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsArray();
}
-void ProtoVmConfig::Serialize(::protozero::Message* msg) const {
- // Field 1: memory_limit_kb
+void FrozenFtraceConfig::Serialize(::protozero::Message* msg) const {
+ // Field 1: instance_name
if (_has_field_[1]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(1, memory_limit_kb_, msg);
+ ::protozero::internal::gen_helpers::SerializeString(1, instance_name_, msg);
}
protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
@@ -26701,7 +26104,7 @@ void ProtoVmConfig::Serialize(::protozero::Message* msg) const {
#if defined(__GNUC__) || defined(__clang__)
#pragma GCC diagnostic pop
#endif
-// gen_amalgamated begin source: gen/protos/perfetto/config/qnx/qnx_config.gen.cc
+// gen_amalgamated begin source: gen/protos/perfetto/config/ftrace/ftrace_config.gen.cc
// gen_amalgamated expanded: #include "perfetto/protozero/gen_field_helpers.h"
// gen_amalgamated expanded: #include "perfetto/protozero/message.h"
// gen_amalgamated expanded: #include "perfetto/protozero/packed_repeated_fields.h"
@@ -26712,30 +26115,70 @@ void ProtoVmConfig::Serialize(::protozero::Message* msg) const {
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wfloat-equal"
#endif
-// gen_amalgamated expanded: #include "protos/perfetto/config/qnx/qnx_config.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/config/ftrace/ftrace_config.gen.h"
namespace perfetto {
namespace protos {
namespace gen {
-QnxConfig::QnxConfig() = default;
-QnxConfig::~QnxConfig() = default;
-QnxConfig::QnxConfig(const QnxConfig&) = default;
-QnxConfig& QnxConfig::operator=(const QnxConfig&) = default;
-QnxConfig::QnxConfig(QnxConfig&&) noexcept = default;
-QnxConfig& QnxConfig::operator=(QnxConfig&&) = default;
+FtraceConfig::FtraceConfig() = default;
+FtraceConfig::~FtraceConfig() = default;
+FtraceConfig::FtraceConfig(const FtraceConfig&) = default;
+FtraceConfig& FtraceConfig::operator=(const FtraceConfig&) = default;
+FtraceConfig::FtraceConfig(FtraceConfig&&) noexcept = default;
+FtraceConfig& FtraceConfig::operator=(FtraceConfig&&) = default;
-bool QnxConfig::operator==(const QnxConfig& other) const {
+bool FtraceConfig::operator==(const FtraceConfig& other) const {
return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
- && ::protozero::internal::gen_helpers::EqualsField(qnx_kernel_buffers_, other.qnx_kernel_buffers_)
- && ::protozero::internal::gen_helpers::EqualsField(qnx_kernel_kbuffers_, other.qnx_kernel_kbuffers_)
- && ::protozero::internal::gen_helpers::EqualsField(qnx_kernel_wide_events_, other.qnx_kernel_wide_events_)
- && ::protozero::internal::gen_helpers::EqualsField(qnx_cache_pages_, other.qnx_cache_pages_)
- && ::protozero::internal::gen_helpers::EqualsField(qnx_cache_max_pages_, other.qnx_cache_max_pages_)
- && ::protozero::internal::gen_helpers::EqualsField(qnx_trace_buffer_init_bytes_, other.qnx_trace_buffer_init_bytes_);
+ && ::protozero::internal::gen_helpers::EqualsField(ftrace_events_, other.ftrace_events_)
+ && ::protozero::internal::gen_helpers::EqualsField(atrace_categories_, other.atrace_categories_)
+ && ::protozero::internal::gen_helpers::EqualsField(atrace_apps_, other.atrace_apps_)
+ && ::protozero::internal::gen_helpers::EqualsField(atrace_categories_prefer_sdk_, other.atrace_categories_prefer_sdk_)
+ && ::protozero::internal::gen_helpers::EqualsField(atrace_userspace_only_, other.atrace_userspace_only_)
+ && ::protozero::internal::gen_helpers::EqualsField(buffer_size_kb_, other.buffer_size_kb_)
+ && ::protozero::internal::gen_helpers::EqualsField(buffer_size_lower_bound_, other.buffer_size_lower_bound_)
+ && ::protozero::internal::gen_helpers::EqualsField(drain_period_ms_, other.drain_period_ms_)
+ && ::protozero::internal::gen_helpers::EqualsField(drain_buffer_percent_, other.drain_buffer_percent_)
+ && ::protozero::internal::gen_helpers::EqualsField(compact_sched_, other.compact_sched_)
+ && ::protozero::internal::gen_helpers::EqualsField(print_filter_, other.print_filter_)
+ && ::protozero::internal::gen_helpers::EqualsField(symbolize_ksyms_, other.symbolize_ksyms_)
+ && ::protozero::internal::gen_helpers::EqualsField(ksyms_mem_policy_, other.ksyms_mem_policy_)
+ && ::protozero::internal::gen_helpers::EqualsField(throttle_rss_stat_, other.throttle_rss_stat_)
+ && ::protozero::internal::gen_helpers::EqualsField(denser_generic_event_encoding_, other.denser_generic_event_encoding_)
+ && ::protozero::internal::gen_helpers::EqualsField(disable_generic_events_, other.disable_generic_events_)
+ && ::protozero::internal::gen_helpers::EqualsField(syscall_events_, other.syscall_events_)
+ && ::protozero::internal::gen_helpers::EqualsField(enable_function_graph_, other.enable_function_graph_)
+ && ::protozero::internal::gen_helpers::EqualsField(function_filters_, other.function_filters_)
+ && ::protozero::internal::gen_helpers::EqualsField(function_graph_roots_, other.function_graph_roots_)
+ && ::protozero::internal::gen_helpers::EqualsField(function_graph_max_depth_, other.function_graph_max_depth_)
+ && ::protozero::internal::gen_helpers::EqualsField(kprobe_events_, other.kprobe_events_)
+ && ::protozero::internal::gen_helpers::EqualsField(preserve_ftrace_buffer_, other.preserve_ftrace_buffer_)
+ && ::protozero::internal::gen_helpers::EqualsField(use_monotonic_raw_clock_, other.use_monotonic_raw_clock_)
+ && ::protozero::internal::gen_helpers::EqualsField(instance_name_, other.instance_name_)
+ && ::protozero::internal::gen_helpers::EqualsField(debug_ftrace_abi_, other.debug_ftrace_abi_)
+ && ::protozero::internal::gen_helpers::EqualsField(tids_to_trace_, other.tids_to_trace_)
+ && ::protozero::internal::gen_helpers::EqualsField(tracefs_options_, other.tracefs_options_)
+ && ::protozero::internal::gen_helpers::EqualsField(tracing_cpumask_, other.tracing_cpumask_)
+ && ::protozero::internal::gen_helpers::EqualsField(initialize_ksyms_synchronously_for_testing_, other.initialize_ksyms_synchronously_for_testing_);
}
-bool QnxConfig::ParseFromArray(const void* raw, size_t size) {
+int FtraceConfig::kprobe_events_size() const { return static_cast<int>(kprobe_events_.size()); }
+void FtraceConfig::clear_kprobe_events() { kprobe_events_.clear(); }
+FtraceConfig_KprobeEvent* FtraceConfig::add_kprobe_events() { kprobe_events_.emplace_back(); return &kprobe_events_.back(); }
+int FtraceConfig::tracefs_options_size() const { return static_cast<int>(tracefs_options_.size()); }
+void FtraceConfig::clear_tracefs_options() { tracefs_options_.clear(); }
+FtraceConfig_TracefsOption* FtraceConfig::add_tracefs_options() { tracefs_options_.emplace_back(); return &tracefs_options_.back(); }
+bool FtraceConfig::ParseFromArray(const void* raw, size_t size) {
+ ftrace_events_.clear();
+ atrace_categories_.clear();
+ atrace_apps_.clear();
+ atrace_categories_prefer_sdk_.clear();
+ syscall_events_.clear();
+ function_filters_.clear();
+ function_graph_roots_.clear();
+ kprobe_events_.clear();
+ tids_to_trace_.clear();
+ tracefs_options_.clear();
unknown_fields_.clear();
bool packed_error = false;
@@ -26745,23 +26188,105 @@ bool QnxConfig::ParseFromArray(const void* raw, size_t size) {
_has_field_.set(field.id());
}
switch (field.id()) {
- case 1 /* qnx_kernel_buffers */:
- field.get(&qnx_kernel_buffers_);
+ case 1 /* ftrace_events */:
+ ftrace_events_.emplace_back();
+ ::protozero::internal::gen_helpers::DeserializeString(field, &ftrace_events_.back());
break;
- case 2 /* qnx_kernel_kbuffers */:
- field.get(&qnx_kernel_kbuffers_);
+ case 2 /* atrace_categories */:
+ atrace_categories_.emplace_back();
+ ::protozero::internal::gen_helpers::DeserializeString(field, &atrace_categories_.back());
break;
- case 3 /* qnx_kernel_wide_events */:
- field.get(&qnx_kernel_wide_events_);
+ case 3 /* atrace_apps */:
+ atrace_apps_.emplace_back();
+ ::protozero::internal::gen_helpers::DeserializeString(field, &atrace_apps_.back());
break;
- case 4 /* qnx_cache_pages */:
- field.get(&qnx_cache_pages_);
+ case 28 /* atrace_categories_prefer_sdk */:
+ atrace_categories_prefer_sdk_.emplace_back();
+ ::protozero::internal::gen_helpers::DeserializeString(field, &atrace_categories_prefer_sdk_.back());
break;
- case 5 /* qnx_cache_max_pages */:
- field.get(&qnx_cache_max_pages_);
+ case 34 /* atrace_userspace_only */:
+ field.get(&atrace_userspace_only_);
break;
- case 6 /* qnx_trace_buffer_init_bytes */:
- field.get(&qnx_trace_buffer_init_bytes_);
+ case 10 /* buffer_size_kb */:
+ field.get(&buffer_size_kb_);
+ break;
+ case 27 /* buffer_size_lower_bound */:
+ field.get(&buffer_size_lower_bound_);
+ break;
+ case 11 /* drain_period_ms */:
+ field.get(&drain_period_ms_);
+ break;
+ case 29 /* drain_buffer_percent */:
+ field.get(&drain_buffer_percent_);
+ break;
+ case 12 /* compact_sched */:
+ (*compact_sched_).ParseFromArray(field.data(), field.size());
+ break;
+ case 22 /* print_filter */:
+ (*print_filter_).ParseFromArray(field.data(), field.size());
+ break;
+ case 13 /* symbolize_ksyms */:
+ field.get(&symbolize_ksyms_);
+ break;
+ case 17 /* ksyms_mem_policy */:
+ field.get(&ksyms_mem_policy_);
+ break;
+ case 15 /* throttle_rss_stat */:
+ field.get(&throttle_rss_stat_);
+ break;
+ case 32 /* denser_generic_event_encoding */:
+ field.get(&denser_generic_event_encoding_);
+ break;
+ case 16 /* disable_generic_events */:
+ field.get(&disable_generic_events_);
+ break;
+ case 18 /* syscall_events */:
+ syscall_events_.emplace_back();
+ ::protozero::internal::gen_helpers::DeserializeString(field, &syscall_events_.back());
+ break;
+ case 19 /* enable_function_graph */:
+ field.get(&enable_function_graph_);
+ break;
+ case 20 /* function_filters */:
+ function_filters_.emplace_back();
+ ::protozero::internal::gen_helpers::DeserializeString(field, &function_filters_.back());
+ break;
+ case 21 /* function_graph_roots */:
+ function_graph_roots_.emplace_back();
+ ::protozero::internal::gen_helpers::DeserializeString(field, &function_graph_roots_.back());
+ break;
+ case 33 /* function_graph_max_depth */:
+ field.get(&function_graph_max_depth_);
+ break;
+ case 30 /* kprobe_events */:
+ kprobe_events_.emplace_back();
+ kprobe_events_.back().ParseFromArray(field.data(), field.size());
+ break;
+ case 23 /* preserve_ftrace_buffer */:
+ field.get(&preserve_ftrace_buffer_);
+ break;
+ case 24 /* use_monotonic_raw_clock */:
+ field.get(&use_monotonic_raw_clock_);
+ break;
+ case 25 /* instance_name */:
+ ::protozero::internal::gen_helpers::DeserializeString(field, &instance_name_);
+ break;
+ case 31 /* debug_ftrace_abi */:
+ field.get(&debug_ftrace_abi_);
+ break;
+ case 35 /* tids_to_trace */:
+ tids_to_trace_.emplace_back();
+ field.get(&tids_to_trace_.back());
+ break;
+ case 36 /* tracefs_options */:
+ tracefs_options_.emplace_back();
+ tracefs_options_.back().ParseFromArray(field.data(), field.size());
+ break;
+ case 37 /* tracing_cpumask */:
+ ::protozero::internal::gen_helpers::DeserializeString(field, &tracing_cpumask_);
+ break;
+ case 14 /* initialize_ksyms_synchronously_for_testing */:
+ field.get(&initialize_ksyms_synchronously_for_testing_);
break;
default:
field.SerializeAndAppendTo(&unknown_fields_);
@@ -26771,117 +26296,187 @@ bool QnxConfig::ParseFromArray(const void* raw, size_t size) {
return !packed_error && !dec.bytes_left();
}
-std::string QnxConfig::SerializeAsString() const {
+std::string FtraceConfig::SerializeAsString() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsString();
}
-std::vector<uint8_t> QnxConfig::SerializeAsArray() const {
+std::vector<uint8_t> FtraceConfig::SerializeAsArray() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsArray();
}
-void QnxConfig::Serialize(::protozero::Message* msg) const {
- // Field 1: qnx_kernel_buffers
- if (_has_field_[1]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(1, qnx_kernel_buffers_, msg);
- }
+void FtraceConfig::Serialize(::protozero::Message* msg) const {
+ // Field 1: ftrace_events
+ for (auto& it : ftrace_events_) {
+ ::protozero::internal::gen_helpers::SerializeString(1, it, msg);
+ }
- // Field 2: qnx_kernel_kbuffers
- if (_has_field_[2]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(2, qnx_kernel_kbuffers_, msg);
+ // Field 2: atrace_categories
+ for (auto& it : atrace_categories_) {
+ ::protozero::internal::gen_helpers::SerializeString(2, it, msg);
}
- // Field 3: qnx_kernel_wide_events
- if (_has_field_[3]) {
- ::protozero::internal::gen_helpers::SerializeTinyVarInt(3, qnx_kernel_wide_events_, msg);
+ // Field 3: atrace_apps
+ for (auto& it : atrace_apps_) {
+ ::protozero::internal::gen_helpers::SerializeString(3, it, msg);
}
- // Field 4: qnx_cache_pages
- if (_has_field_[4]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(4, qnx_cache_pages_, msg);
+ // Field 28: atrace_categories_prefer_sdk
+ for (auto& it : atrace_categories_prefer_sdk_) {
+ ::protozero::internal::gen_helpers::SerializeString(28, it, msg);
}
- // Field 5: qnx_cache_max_pages
- if (_has_field_[5]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(5, qnx_cache_max_pages_, msg);
+ // Field 34: atrace_userspace_only
+ if (_has_field_[34]) {
+ ::protozero::internal::gen_helpers::SerializeTinyVarInt(34, atrace_userspace_only_, msg);
}
- // Field 6: qnx_trace_buffer_init_bytes
- if (_has_field_[6]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(6, qnx_trace_buffer_init_bytes_, msg);
+ // Field 10: buffer_size_kb
+ if (_has_field_[10]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(10, buffer_size_kb_, msg);
}
- protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
-}
+ // Field 27: buffer_size_lower_bound
+ if (_has_field_[27]) {
+ ::protozero::internal::gen_helpers::SerializeTinyVarInt(27, buffer_size_lower_bound_, msg);
+ }
-} // namespace perfetto
-} // namespace protos
-} // namespace gen
-#if defined(__GNUC__) || defined(__clang__)
-#pragma GCC diagnostic pop
-#endif
-// gen_amalgamated begin source: gen/protos/perfetto/config/statsd/atom_ids.gen.cc
-// gen_amalgamated expanded: #include "perfetto/protozero/gen_field_helpers.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/message.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/packed_repeated_fields.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/proto_decoder.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/scattered_heap_buffer.h"
-// DO NOT EDIT. Autogenerated by Perfetto cppgen_plugin
-#if defined(__GNUC__) || defined(__clang__)
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wfloat-equal"
-#endif
-// gen_amalgamated expanded: #include "protos/perfetto/config/statsd/atom_ids.gen.h"
+ // Field 11: drain_period_ms
+ if (_has_field_[11]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(11, drain_period_ms_, msg);
+ }
-namespace perfetto {
-namespace protos {
-namespace gen {
-} // namespace perfetto
-} // namespace protos
-} // namespace gen
-#if defined(__GNUC__) || defined(__clang__)
-#pragma GCC diagnostic pop
-#endif
-// gen_amalgamated begin source: gen/protos/perfetto/config/statsd/statsd_tracing_config.gen.cc
-// gen_amalgamated expanded: #include "perfetto/protozero/gen_field_helpers.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/message.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/packed_repeated_fields.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/proto_decoder.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/scattered_heap_buffer.h"
-// DO NOT EDIT. Autogenerated by Perfetto cppgen_plugin
-#if defined(__GNUC__) || defined(__clang__)
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wfloat-equal"
-#endif
-// gen_amalgamated expanded: #include "protos/perfetto/config/statsd/statsd_tracing_config.gen.h"
-// gen_amalgamated expanded: #include "protos/perfetto/config/statsd/atom_ids.gen.h"
+ // Field 29: drain_buffer_percent
+ if (_has_field_[29]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(29, drain_buffer_percent_, msg);
+ }
-namespace perfetto {
-namespace protos {
-namespace gen {
+ // Field 12: compact_sched
+ if (_has_field_[12]) {
+ (*compact_sched_).Serialize(msg->BeginNestedMessage<::protozero::Message>(12));
+ }
-StatsdPullAtomConfig::StatsdPullAtomConfig() = default;
-StatsdPullAtomConfig::~StatsdPullAtomConfig() = default;
-StatsdPullAtomConfig::StatsdPullAtomConfig(const StatsdPullAtomConfig&) = default;
-StatsdPullAtomConfig& StatsdPullAtomConfig::operator=(const StatsdPullAtomConfig&) = default;
-StatsdPullAtomConfig::StatsdPullAtomConfig(StatsdPullAtomConfig&&) noexcept = default;
-StatsdPullAtomConfig& StatsdPullAtomConfig::operator=(StatsdPullAtomConfig&&) = default;
+ // Field 22: print_filter
+ if (_has_field_[22]) {
+ (*print_filter_).Serialize(msg->BeginNestedMessage<::protozero::Message>(22));
+ }
-bool StatsdPullAtomConfig::operator==(const StatsdPullAtomConfig& other) const {
+ // Field 13: symbolize_ksyms
+ if (_has_field_[13]) {
+ ::protozero::internal::gen_helpers::SerializeTinyVarInt(13, symbolize_ksyms_, msg);
+ }
+
+ // Field 17: ksyms_mem_policy
+ if (_has_field_[17]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(17, ksyms_mem_policy_, msg);
+ }
+
+ // Field 15: throttle_rss_stat
+ if (_has_field_[15]) {
+ ::protozero::internal::gen_helpers::SerializeTinyVarInt(15, throttle_rss_stat_, msg);
+ }
+
+ // Field 32: denser_generic_event_encoding
+ if (_has_field_[32]) {
+ ::protozero::internal::gen_helpers::SerializeTinyVarInt(32, denser_generic_event_encoding_, msg);
+ }
+
+ // Field 16: disable_generic_events
+ if (_has_field_[16]) {
+ ::protozero::internal::gen_helpers::SerializeTinyVarInt(16, disable_generic_events_, msg);
+ }
+
+ // Field 18: syscall_events
+ for (auto& it : syscall_events_) {
+ ::protozero::internal::gen_helpers::SerializeString(18, it, msg);
+ }
+
+ // Field 19: enable_function_graph
+ if (_has_field_[19]) {
+ ::protozero::internal::gen_helpers::SerializeTinyVarInt(19, enable_function_graph_, msg);
+ }
+
+ // Field 20: function_filters
+ for (auto& it : function_filters_) {
+ ::protozero::internal::gen_helpers::SerializeString(20, it, msg);
+ }
+
+ // Field 21: function_graph_roots
+ for (auto& it : function_graph_roots_) {
+ ::protozero::internal::gen_helpers::SerializeString(21, it, msg);
+ }
+
+ // Field 33: function_graph_max_depth
+ if (_has_field_[33]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(33, function_graph_max_depth_, msg);
+ }
+
+ // Field 30: kprobe_events
+ for (auto& it : kprobe_events_) {
+ it.Serialize(msg->BeginNestedMessage<::protozero::Message>(30));
+ }
+
+ // Field 23: preserve_ftrace_buffer
+ if (_has_field_[23]) {
+ ::protozero::internal::gen_helpers::SerializeTinyVarInt(23, preserve_ftrace_buffer_, msg);
+ }
+
+ // Field 24: use_monotonic_raw_clock
+ if (_has_field_[24]) {
+ ::protozero::internal::gen_helpers::SerializeTinyVarInt(24, use_monotonic_raw_clock_, msg);
+ }
+
+ // Field 25: instance_name
+ if (_has_field_[25]) {
+ ::protozero::internal::gen_helpers::SerializeString(25, instance_name_, msg);
+ }
+
+ // Field 31: debug_ftrace_abi
+ if (_has_field_[31]) {
+ ::protozero::internal::gen_helpers::SerializeTinyVarInt(31, debug_ftrace_abi_, msg);
+ }
+
+ // Field 35: tids_to_trace
+ for (auto& it : tids_to_trace_) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(35, it, msg);
+ }
+
+ // Field 36: tracefs_options
+ for (auto& it : tracefs_options_) {
+ it.Serialize(msg->BeginNestedMessage<::protozero::Message>(36));
+ }
+
+ // Field 37: tracing_cpumask
+ if (_has_field_[37]) {
+ ::protozero::internal::gen_helpers::SerializeString(37, tracing_cpumask_, msg);
+ }
+
+ // Field 14: initialize_ksyms_synchronously_for_testing
+ if (_has_field_[14]) {
+ ::protozero::internal::gen_helpers::SerializeTinyVarInt(14, initialize_ksyms_synchronously_for_testing_, msg);
+ }
+
+ protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
+}
+
+
+FtraceConfig_TracefsOption::FtraceConfig_TracefsOption() = default;
+FtraceConfig_TracefsOption::~FtraceConfig_TracefsOption() = default;
+FtraceConfig_TracefsOption::FtraceConfig_TracefsOption(const FtraceConfig_TracefsOption&) = default;
+FtraceConfig_TracefsOption& FtraceConfig_TracefsOption::operator=(const FtraceConfig_TracefsOption&) = default;
+FtraceConfig_TracefsOption::FtraceConfig_TracefsOption(FtraceConfig_TracefsOption&&) noexcept = default;
+FtraceConfig_TracefsOption& FtraceConfig_TracefsOption::operator=(FtraceConfig_TracefsOption&&) = default;
+
+bool FtraceConfig_TracefsOption::operator==(const FtraceConfig_TracefsOption& other) const {
return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
- && ::protozero::internal::gen_helpers::EqualsField(pull_atom_id_, other.pull_atom_id_)
- && ::protozero::internal::gen_helpers::EqualsField(raw_pull_atom_id_, other.raw_pull_atom_id_)
- && ::protozero::internal::gen_helpers::EqualsField(pull_frequency_ms_, other.pull_frequency_ms_)
- && ::protozero::internal::gen_helpers::EqualsField(packages_, other.packages_);
+ && ::protozero::internal::gen_helpers::EqualsField(name_, other.name_)
+ && ::protozero::internal::gen_helpers::EqualsField(state_, other.state_);
}
-bool StatsdPullAtomConfig::ParseFromArray(const void* raw, size_t size) {
- pull_atom_id_.clear();
- raw_pull_atom_id_.clear();
- packages_.clear();
+bool FtraceConfig_TracefsOption::ParseFromArray(const void* raw, size_t size) {
unknown_fields_.clear();
bool packed_error = false;
@@ -26891,20 +26486,11 @@ bool StatsdPullAtomConfig::ParseFromArray(const void* raw, size_t size) {
_has_field_.set(field.id());
}
switch (field.id()) {
- case 1 /* pull_atom_id */:
- pull_atom_id_.emplace_back();
- field.get(&pull_atom_id_.back());
- break;
- case 2 /* raw_pull_atom_id */:
- raw_pull_atom_id_.emplace_back();
- field.get(&raw_pull_atom_id_.back());
- break;
- case 3 /* pull_frequency_ms */:
- field.get(&pull_frequency_ms_);
+ case 1 /* name */:
+ ::protozero::internal::gen_helpers::DeserializeString(field, &name_);
break;
- case 4 /* packages */:
- packages_.emplace_back();
- ::protozero::internal::gen_helpers::DeserializeString(field, &packages_.back());
+ case 2 /* state */:
+ field.get(&state_);
break;
default:
field.SerializeAndAppendTo(&unknown_fields_);
@@ -26914,64 +26500,47 @@ bool StatsdPullAtomConfig::ParseFromArray(const void* raw, size_t size) {
return !packed_error && !dec.bytes_left();
}
-std::string StatsdPullAtomConfig::SerializeAsString() const {
+std::string FtraceConfig_TracefsOption::SerializeAsString() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsString();
}
-std::vector<uint8_t> StatsdPullAtomConfig::SerializeAsArray() const {
+std::vector<uint8_t> FtraceConfig_TracefsOption::SerializeAsArray() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsArray();
}
-void StatsdPullAtomConfig::Serialize(::protozero::Message* msg) const {
- // Field 1: pull_atom_id
- for (auto& it : pull_atom_id_) {
- ::protozero::internal::gen_helpers::SerializeVarInt(1, it, msg);
- }
-
- // Field 2: raw_pull_atom_id
- for (auto& it : raw_pull_atom_id_) {
- ::protozero::internal::gen_helpers::SerializeVarInt(2, it, msg);
- }
-
- // Field 3: pull_frequency_ms
- if (_has_field_[3]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(3, pull_frequency_ms_, msg);
+void FtraceConfig_TracefsOption::Serialize(::protozero::Message* msg) const {
+ // Field 1: name
+ if (_has_field_[1]) {
+ ::protozero::internal::gen_helpers::SerializeString(1, name_, msg);
}
- // Field 4: packages
- for (auto& it : packages_) {
- ::protozero::internal::gen_helpers::SerializeString(4, it, msg);
+ // Field 2: state
+ if (_has_field_[2]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(2, state_, msg);
}
protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
}
-StatsdTracingConfig::StatsdTracingConfig() = default;
-StatsdTracingConfig::~StatsdTracingConfig() = default;
-StatsdTracingConfig::StatsdTracingConfig(const StatsdTracingConfig&) = default;
-StatsdTracingConfig& StatsdTracingConfig::operator=(const StatsdTracingConfig&) = default;
-StatsdTracingConfig::StatsdTracingConfig(StatsdTracingConfig&&) noexcept = default;
-StatsdTracingConfig& StatsdTracingConfig::operator=(StatsdTracingConfig&&) = default;
+FtraceConfig_KprobeEvent::FtraceConfig_KprobeEvent() = default;
+FtraceConfig_KprobeEvent::~FtraceConfig_KprobeEvent() = default;
+FtraceConfig_KprobeEvent::FtraceConfig_KprobeEvent(const FtraceConfig_KprobeEvent&) = default;
+FtraceConfig_KprobeEvent& FtraceConfig_KprobeEvent::operator=(const FtraceConfig_KprobeEvent&) = default;
+FtraceConfig_KprobeEvent::FtraceConfig_KprobeEvent(FtraceConfig_KprobeEvent&&) noexcept = default;
+FtraceConfig_KprobeEvent& FtraceConfig_KprobeEvent::operator=(FtraceConfig_KprobeEvent&&) = default;
-bool StatsdTracingConfig::operator==(const StatsdTracingConfig& other) const {
+bool FtraceConfig_KprobeEvent::operator==(const FtraceConfig_KprobeEvent& other) const {
return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
- && ::protozero::internal::gen_helpers::EqualsField(push_atom_id_, other.push_atom_id_)
- && ::protozero::internal::gen_helpers::EqualsField(raw_push_atom_id_, other.raw_push_atom_id_)
- && ::protozero::internal::gen_helpers::EqualsField(pull_config_, other.pull_config_);
+ && ::protozero::internal::gen_helpers::EqualsField(probe_, other.probe_)
+ && ::protozero::internal::gen_helpers::EqualsField(type_, other.type_);
}
-int StatsdTracingConfig::pull_config_size() const { return static_cast<int>(pull_config_.size()); }
-void StatsdTracingConfig::clear_pull_config() { pull_config_.clear(); }
-StatsdPullAtomConfig* StatsdTracingConfig::add_pull_config() { pull_config_.emplace_back(); return &pull_config_.back(); }
-bool StatsdTracingConfig::ParseFromArray(const void* raw, size_t size) {
- push_atom_id_.clear();
- raw_push_atom_id_.clear();
- pull_config_.clear();
+bool FtraceConfig_KprobeEvent::ParseFromArray(const void* raw, size_t size) {
unknown_fields_.clear();
bool packed_error = false;
@@ -26981,17 +26550,11 @@ bool StatsdTracingConfig::ParseFromArray(const void* raw, size_t size) {
_has_field_.set(field.id());
}
switch (field.id()) {
- case 1 /* push_atom_id */:
- push_atom_id_.emplace_back();
- field.get(&push_atom_id_.back());
- break;
- case 2 /* raw_push_atom_id */:
- raw_push_atom_id_.emplace_back();
- field.get(&raw_push_atom_id_.back());
+ case 1 /* probe */:
+ ::protozero::internal::gen_helpers::DeserializeString(field, &probe_);
break;
- case 3 /* pull_config */:
- pull_config_.emplace_back();
- pull_config_.back().ParseFromArray(field.data(), field.size());
+ case 2 /* type */:
+ field.get(&type_);
break;
default:
field.SerializeAndAppendTo(&unknown_fields_);
@@ -27001,91 +26564,50 @@ bool StatsdTracingConfig::ParseFromArray(const void* raw, size_t size) {
return !packed_error && !dec.bytes_left();
}
-std::string StatsdTracingConfig::SerializeAsString() const {
+std::string FtraceConfig_KprobeEvent::SerializeAsString() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsString();
}
-std::vector<uint8_t> StatsdTracingConfig::SerializeAsArray() const {
+std::vector<uint8_t> FtraceConfig_KprobeEvent::SerializeAsArray() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsArray();
}
-void StatsdTracingConfig::Serialize(::protozero::Message* msg) const {
- // Field 1: push_atom_id
- for (auto& it : push_atom_id_) {
- ::protozero::internal::gen_helpers::SerializeVarInt(1, it, msg);
- }
-
- // Field 2: raw_push_atom_id
- for (auto& it : raw_push_atom_id_) {
- ::protozero::internal::gen_helpers::SerializeVarInt(2, it, msg);
+void FtraceConfig_KprobeEvent::Serialize(::protozero::Message* msg) const {
+ // Field 1: probe
+ if (_has_field_[1]) {
+ ::protozero::internal::gen_helpers::SerializeString(1, probe_, msg);
}
- // Field 3: pull_config
- for (auto& it : pull_config_) {
- it.Serialize(msg->BeginNestedMessage<::protozero::Message>(3));
+ // Field 2: type
+ if (_has_field_[2]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(2, type_, msg);
}
protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
}
-} // namespace perfetto
-} // namespace protos
-} // namespace gen
-#if defined(__GNUC__) || defined(__clang__)
-#pragma GCC diagnostic pop
-#endif
-// gen_amalgamated begin source: gen/protos/perfetto/config/sys_stats/sys_stats_config.gen.cc
-// gen_amalgamated expanded: #include "perfetto/protozero/gen_field_helpers.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/message.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/packed_repeated_fields.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/proto_decoder.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/scattered_heap_buffer.h"
-// DO NOT EDIT. Autogenerated by Perfetto cppgen_plugin
-#if defined(__GNUC__) || defined(__clang__)
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wfloat-equal"
-#endif
-// gen_amalgamated expanded: #include "protos/perfetto/config/sys_stats/sys_stats_config.gen.h"
-// gen_amalgamated expanded: #include "protos/perfetto/common/sys_stats_counters.gen.h"
-
-namespace perfetto {
-namespace protos {
-namespace gen {
-SysStatsConfig::SysStatsConfig() = default;
-SysStatsConfig::~SysStatsConfig() = default;
-SysStatsConfig::SysStatsConfig(const SysStatsConfig&) = default;
-SysStatsConfig& SysStatsConfig::operator=(const SysStatsConfig&) = default;
-SysStatsConfig::SysStatsConfig(SysStatsConfig&&) noexcept = default;
-SysStatsConfig& SysStatsConfig::operator=(SysStatsConfig&&) = default;
+FtraceConfig_PrintFilter::FtraceConfig_PrintFilter() = default;
+FtraceConfig_PrintFilter::~FtraceConfig_PrintFilter() = default;
+FtraceConfig_PrintFilter::FtraceConfig_PrintFilter(const FtraceConfig_PrintFilter&) = default;
+FtraceConfig_PrintFilter& FtraceConfig_PrintFilter::operator=(const FtraceConfig_PrintFilter&) = default;
+FtraceConfig_PrintFilter::FtraceConfig_PrintFilter(FtraceConfig_PrintFilter&&) noexcept = default;
+FtraceConfig_PrintFilter& FtraceConfig_PrintFilter::operator=(FtraceConfig_PrintFilter&&) = default;
-bool SysStatsConfig::operator==(const SysStatsConfig& other) const {
+bool FtraceConfig_PrintFilter::operator==(const FtraceConfig_PrintFilter& other) const {
return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
- && ::protozero::internal::gen_helpers::EqualsField(meminfo_period_ms_, other.meminfo_period_ms_)
- && ::protozero::internal::gen_helpers::EqualsField(meminfo_counters_, other.meminfo_counters_)
- && ::protozero::internal::gen_helpers::EqualsField(vmstat_period_ms_, other.vmstat_period_ms_)
- && ::protozero::internal::gen_helpers::EqualsField(vmstat_counters_, other.vmstat_counters_)
- && ::protozero::internal::gen_helpers::EqualsField(stat_period_ms_, other.stat_period_ms_)
- && ::protozero::internal::gen_helpers::EqualsField(stat_counters_, other.stat_counters_)
- && ::protozero::internal::gen_helpers::EqualsField(devfreq_period_ms_, other.devfreq_period_ms_)
- && ::protozero::internal::gen_helpers::EqualsField(cpufreq_period_ms_, other.cpufreq_period_ms_)
- && ::protozero::internal::gen_helpers::EqualsField(buddyinfo_period_ms_, other.buddyinfo_period_ms_)
- && ::protozero::internal::gen_helpers::EqualsField(diskstat_period_ms_, other.diskstat_period_ms_)
- && ::protozero::internal::gen_helpers::EqualsField(psi_period_ms_, other.psi_period_ms_)
- && ::protozero::internal::gen_helpers::EqualsField(thermal_period_ms_, other.thermal_period_ms_)
- && ::protozero::internal::gen_helpers::EqualsField(cpuidle_period_ms_, other.cpuidle_period_ms_)
- && ::protozero::internal::gen_helpers::EqualsField(gpufreq_period_ms_, other.gpufreq_period_ms_)
- && ::protozero::internal::gen_helpers::EqualsField(slab_period_ms_, other.slab_period_ms_);
+ && ::protozero::internal::gen_helpers::EqualsField(rules_, other.rules_);
}
-bool SysStatsConfig::ParseFromArray(const void* raw, size_t size) {
- meminfo_counters_.clear();
- vmstat_counters_.clear();
- stat_counters_.clear();
+int FtraceConfig_PrintFilter::rules_size() const { return static_cast<int>(rules_.size()); }
+void FtraceConfig_PrintFilter::clear_rules() { rules_.clear(); }
+FtraceConfig_PrintFilter_Rule* FtraceConfig_PrintFilter::add_rules() { rules_.emplace_back(); return &rules_.back(); }
+bool FtraceConfig_PrintFilter::ParseFromArray(const void* raw, size_t size) {
+ rules_.clear();
unknown_fields_.clear();
bool packed_error = false;
@@ -27095,53 +26617,9 @@ bool SysStatsConfig::ParseFromArray(const void* raw, size_t size) {
_has_field_.set(field.id());
}
switch (field.id()) {
- case 1 /* meminfo_period_ms */:
- field.get(&meminfo_period_ms_);
- break;
- case 2 /* meminfo_counters */:
- meminfo_counters_.emplace_back();
- field.get(&meminfo_counters_.back());
- break;
- case 3 /* vmstat_period_ms */:
- field.get(&vmstat_period_ms_);
- break;
- case 4 /* vmstat_counters */:
- vmstat_counters_.emplace_back();
- field.get(&vmstat_counters_.back());
- break;
- case 5 /* stat_period_ms */:
- field.get(&stat_period_ms_);
- break;
- case 6 /* stat_counters */:
- stat_counters_.emplace_back();
- field.get(&stat_counters_.back());
- break;
- case 7 /* devfreq_period_ms */:
- field.get(&devfreq_period_ms_);
- break;
- case 8 /* cpufreq_period_ms */:
- field.get(&cpufreq_period_ms_);
- break;
- case 9 /* buddyinfo_period_ms */:
- field.get(&buddyinfo_period_ms_);
- break;
- case 10 /* diskstat_period_ms */:
- field.get(&diskstat_period_ms_);
- break;
- case 11 /* psi_period_ms */:
- field.get(&psi_period_ms_);
- break;
- case 12 /* thermal_period_ms */:
- field.get(&thermal_period_ms_);
- break;
- case 13 /* cpuidle_period_ms */:
- field.get(&cpuidle_period_ms_);
- break;
- case 14 /* gpufreq_period_ms */:
- field.get(&gpufreq_period_ms_);
- break;
- case 15 /* slab_period_ms */:
- field.get(&slab_period_ms_);
+ case 1 /* rules */:
+ rules_.emplace_back();
+ rules_.back().ParseFromArray(field.data(), field.size());
break;
default:
field.SerializeAndAppendTo(&unknown_fields_);
@@ -27151,133 +26629,115 @@ bool SysStatsConfig::ParseFromArray(const void* raw, size_t size) {
return !packed_error && !dec.bytes_left();
}
-std::string SysStatsConfig::SerializeAsString() const {
+std::string FtraceConfig_PrintFilter::SerializeAsString() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsString();
}
-std::vector<uint8_t> SysStatsConfig::SerializeAsArray() const {
+std::vector<uint8_t> FtraceConfig_PrintFilter::SerializeAsArray() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsArray();
}
-void SysStatsConfig::Serialize(::protozero::Message* msg) const {
- // Field 1: meminfo_period_ms
- if (_has_field_[1]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(1, meminfo_period_ms_, msg);
- }
-
- // Field 2: meminfo_counters
- for (auto& it : meminfo_counters_) {
- ::protozero::internal::gen_helpers::SerializeVarInt(2, it, msg);
- }
-
- // Field 3: vmstat_period_ms
- if (_has_field_[3]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(3, vmstat_period_ms_, msg);
- }
-
- // Field 4: vmstat_counters
- for (auto& it : vmstat_counters_) {
- ::protozero::internal::gen_helpers::SerializeVarInt(4, it, msg);
+void FtraceConfig_PrintFilter::Serialize(::protozero::Message* msg) const {
+ // Field 1: rules
+ for (auto& it : rules_) {
+ it.Serialize(msg->BeginNestedMessage<::protozero::Message>(1));
}
- // Field 5: stat_period_ms
- if (_has_field_[5]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(5, stat_period_ms_, msg);
- }
+ protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
+}
- // Field 6: stat_counters
- for (auto& it : stat_counters_) {
- ::protozero::internal::gen_helpers::SerializeVarInt(6, it, msg);
- }
- // Field 7: devfreq_period_ms
- if (_has_field_[7]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(7, devfreq_period_ms_, msg);
- }
+FtraceConfig_PrintFilter_Rule::FtraceConfig_PrintFilter_Rule() = default;
+FtraceConfig_PrintFilter_Rule::~FtraceConfig_PrintFilter_Rule() = default;
+FtraceConfig_PrintFilter_Rule::FtraceConfig_PrintFilter_Rule(const FtraceConfig_PrintFilter_Rule&) = default;
+FtraceConfig_PrintFilter_Rule& FtraceConfig_PrintFilter_Rule::operator=(const FtraceConfig_PrintFilter_Rule&) = default;
+FtraceConfig_PrintFilter_Rule::FtraceConfig_PrintFilter_Rule(FtraceConfig_PrintFilter_Rule&&) noexcept = default;
+FtraceConfig_PrintFilter_Rule& FtraceConfig_PrintFilter_Rule::operator=(FtraceConfig_PrintFilter_Rule&&) = default;
- // Field 8: cpufreq_period_ms
- if (_has_field_[8]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(8, cpufreq_period_ms_, msg);
- }
+bool FtraceConfig_PrintFilter_Rule::operator==(const FtraceConfig_PrintFilter_Rule& other) const {
+ return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
+ && ::protozero::internal::gen_helpers::EqualsField(prefix_, other.prefix_)
+ && ::protozero::internal::gen_helpers::EqualsField(atrace_msg_, other.atrace_msg_)
+ && ::protozero::internal::gen_helpers::EqualsField(allow_, other.allow_);
+}
- // Field 9: buddyinfo_period_ms
- if (_has_field_[9]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(9, buddyinfo_period_ms_, msg);
- }
+bool FtraceConfig_PrintFilter_Rule::ParseFromArray(const void* raw, size_t size) {
+ unknown_fields_.clear();
+ bool packed_error = false;
- // Field 10: diskstat_period_ms
- if (_has_field_[10]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(10, diskstat_period_ms_, msg);
+ ::protozero::ProtoDecoder dec(raw, size);
+ for (auto field = dec.ReadField(); field.valid(); field = dec.ReadField()) {
+ if (field.id() < _has_field_.size()) {
+ _has_field_.set(field.id());
+ }
+ switch (field.id()) {
+ case 1 /* prefix */:
+ ::protozero::internal::gen_helpers::DeserializeString(field, &prefix_);
+ break;
+ case 3 /* atrace_msg */:
+ (*atrace_msg_).ParseFromArray(field.data(), field.size());
+ break;
+ case 2 /* allow */:
+ field.get(&allow_);
+ break;
+ default:
+ field.SerializeAndAppendTo(&unknown_fields_);
+ break;
+ }
}
+ return !packed_error && !dec.bytes_left();
+}
- // Field 11: psi_period_ms
- if (_has_field_[11]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(11, psi_period_ms_, msg);
- }
+std::string FtraceConfig_PrintFilter_Rule::SerializeAsString() const {
+ ::protozero::internal::gen_helpers::MessageSerializer msg;
+ Serialize(msg.get());
+ return msg.SerializeAsString();
+}
- // Field 12: thermal_period_ms
- if (_has_field_[12]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(12, thermal_period_ms_, msg);
- }
+std::vector<uint8_t> FtraceConfig_PrintFilter_Rule::SerializeAsArray() const {
+ ::protozero::internal::gen_helpers::MessageSerializer msg;
+ Serialize(msg.get());
+ return msg.SerializeAsArray();
+}
- // Field 13: cpuidle_period_ms
- if (_has_field_[13]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(13, cpuidle_period_ms_, msg);
+void FtraceConfig_PrintFilter_Rule::Serialize(::protozero::Message* msg) const {
+ // Field 1: prefix
+ if (_has_field_[1]) {
+ ::protozero::internal::gen_helpers::SerializeString(1, prefix_, msg);
}
- // Field 14: gpufreq_period_ms
- if (_has_field_[14]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(14, gpufreq_period_ms_, msg);
+ // Field 3: atrace_msg
+ if (_has_field_[3]) {
+ (*atrace_msg_).Serialize(msg->BeginNestedMessage<::protozero::Message>(3));
}
- // Field 15: slab_period_ms
- if (_has_field_[15]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(15, slab_period_ms_, msg);
+ // Field 2: allow
+ if (_has_field_[2]) {
+ ::protozero::internal::gen_helpers::SerializeTinyVarInt(2, allow_, msg);
}
protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
}
-} // namespace perfetto
-} // namespace protos
-} // namespace gen
-#if defined(__GNUC__) || defined(__clang__)
-#pragma GCC diagnostic pop
-#endif
-// gen_amalgamated begin source: gen/protos/perfetto/config/system_info/system_info_config.gen.cc
-// gen_amalgamated expanded: #include "perfetto/protozero/gen_field_helpers.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/message.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/packed_repeated_fields.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/proto_decoder.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/scattered_heap_buffer.h"
-// DO NOT EDIT. Autogenerated by Perfetto cppgen_plugin
-#if defined(__GNUC__) || defined(__clang__)
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wfloat-equal"
-#endif
-// gen_amalgamated expanded: #include "protos/perfetto/config/system_info/system_info_config.gen.h"
-
-namespace perfetto {
-namespace protos {
-namespace gen {
-SystemInfoConfig::SystemInfoConfig() = default;
-SystemInfoConfig::~SystemInfoConfig() = default;
-SystemInfoConfig::SystemInfoConfig(const SystemInfoConfig&) = default;
-SystemInfoConfig& SystemInfoConfig::operator=(const SystemInfoConfig&) = default;
-SystemInfoConfig::SystemInfoConfig(SystemInfoConfig&&) noexcept = default;
-SystemInfoConfig& SystemInfoConfig::operator=(SystemInfoConfig&&) = default;
+FtraceConfig_PrintFilter_Rule_AtraceMessage::FtraceConfig_PrintFilter_Rule_AtraceMessage() = default;
+FtraceConfig_PrintFilter_Rule_AtraceMessage::~FtraceConfig_PrintFilter_Rule_AtraceMessage() = default;
+FtraceConfig_PrintFilter_Rule_AtraceMessage::FtraceConfig_PrintFilter_Rule_AtraceMessage(const FtraceConfig_PrintFilter_Rule_AtraceMessage&) = default;
+FtraceConfig_PrintFilter_Rule_AtraceMessage& FtraceConfig_PrintFilter_Rule_AtraceMessage::operator=(const FtraceConfig_PrintFilter_Rule_AtraceMessage&) = default;
+FtraceConfig_PrintFilter_Rule_AtraceMessage::FtraceConfig_PrintFilter_Rule_AtraceMessage(FtraceConfig_PrintFilter_Rule_AtraceMessage&&) noexcept = default;
+FtraceConfig_PrintFilter_Rule_AtraceMessage& FtraceConfig_PrintFilter_Rule_AtraceMessage::operator=(FtraceConfig_PrintFilter_Rule_AtraceMessage&&) = default;
-bool SystemInfoConfig::operator==(const SystemInfoConfig& other) const {
+bool FtraceConfig_PrintFilter_Rule_AtraceMessage::operator==(const FtraceConfig_PrintFilter_Rule_AtraceMessage& other) const {
return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
- && ::protozero::internal::gen_helpers::EqualsField(irq_names_, other.irq_names_);
+ && ::protozero::internal::gen_helpers::EqualsField(type_, other.type_)
+ && ::protozero::internal::gen_helpers::EqualsField(prefix_, other.prefix_);
}
-bool SystemInfoConfig::ParseFromArray(const void* raw, size_t size) {
+bool FtraceConfig_PrintFilter_Rule_AtraceMessage::ParseFromArray(const void* raw, size_t size) {
unknown_fields_.clear();
bool packed_error = false;
@@ -27287,8 +26747,11 @@ bool SystemInfoConfig::ParseFromArray(const void* raw, size_t size) {
_has_field_.set(field.id());
}
switch (field.id()) {
- case 1 /* irq_names */:
- field.get(&irq_names_);
+ case 1 /* type */:
+ ::protozero::internal::gen_helpers::DeserializeString(field, &type_);
+ break;
+ case 2 /* prefix */:
+ ::protozero::internal::gen_helpers::DeserializeString(field, &prefix_);
break;
default:
field.SerializeAndAppendTo(&unknown_fields_);
@@ -27298,76 +26761,46 @@ bool SystemInfoConfig::ParseFromArray(const void* raw, size_t size) {
return !packed_error && !dec.bytes_left();
}
-std::string SystemInfoConfig::SerializeAsString() const {
+std::string FtraceConfig_PrintFilter_Rule_AtraceMessage::SerializeAsString() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsString();
}
-std::vector<uint8_t> SystemInfoConfig::SerializeAsArray() const {
+std::vector<uint8_t> FtraceConfig_PrintFilter_Rule_AtraceMessage::SerializeAsArray() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsArray();
}
-void SystemInfoConfig::Serialize(::protozero::Message* msg) const {
- // Field 1: irq_names
+void FtraceConfig_PrintFilter_Rule_AtraceMessage::Serialize(::protozero::Message* msg) const {
+ // Field 1: type
if (_has_field_[1]) {
- ::protozero::internal::gen_helpers::SerializeTinyVarInt(1, irq_names_, msg);
+ ::protozero::internal::gen_helpers::SerializeString(1, type_, msg);
+ }
+
+ // Field 2: prefix
+ if (_has_field_[2]) {
+ ::protozero::internal::gen_helpers::SerializeString(2, prefix_, msg);
}
protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
}
-} // namespace perfetto
-} // namespace protos
-} // namespace gen
-#if defined(__GNUC__) || defined(__clang__)
-#pragma GCC diagnostic pop
-#endif
-// gen_amalgamated begin source: gen/protos/perfetto/config/track_event/track_event_config.gen.cc
-// gen_amalgamated expanded: #include "perfetto/protozero/gen_field_helpers.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/message.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/packed_repeated_fields.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/proto_decoder.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/scattered_heap_buffer.h"
-// DO NOT EDIT. Autogenerated by Perfetto cppgen_plugin
-#if defined(__GNUC__) || defined(__clang__)
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wfloat-equal"
-#endif
-// gen_amalgamated expanded: #include "protos/perfetto/config/track_event/track_event_config.gen.h"
-
-namespace perfetto {
-namespace protos {
-namespace gen {
-TrackEventConfig::TrackEventConfig() = default;
-TrackEventConfig::~TrackEventConfig() = default;
-TrackEventConfig::TrackEventConfig(const TrackEventConfig&) = default;
-TrackEventConfig& TrackEventConfig::operator=(const TrackEventConfig&) = default;
-TrackEventConfig::TrackEventConfig(TrackEventConfig&&) noexcept = default;
-TrackEventConfig& TrackEventConfig::operator=(TrackEventConfig&&) = default;
+FtraceConfig_CompactSchedConfig::FtraceConfig_CompactSchedConfig() = default;
+FtraceConfig_CompactSchedConfig::~FtraceConfig_CompactSchedConfig() = default;
+FtraceConfig_CompactSchedConfig::FtraceConfig_CompactSchedConfig(const FtraceConfig_CompactSchedConfig&) = default;
+FtraceConfig_CompactSchedConfig& FtraceConfig_CompactSchedConfig::operator=(const FtraceConfig_CompactSchedConfig&) = default;
+FtraceConfig_CompactSchedConfig::FtraceConfig_CompactSchedConfig(FtraceConfig_CompactSchedConfig&&) noexcept = default;
+FtraceConfig_CompactSchedConfig& FtraceConfig_CompactSchedConfig::operator=(FtraceConfig_CompactSchedConfig&&) = default;
-bool TrackEventConfig::operator==(const TrackEventConfig& other) const {
+bool FtraceConfig_CompactSchedConfig::operator==(const FtraceConfig_CompactSchedConfig& other) const {
return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
- && ::protozero::internal::gen_helpers::EqualsField(disabled_categories_, other.disabled_categories_)
- && ::protozero::internal::gen_helpers::EqualsField(enabled_categories_, other.enabled_categories_)
- && ::protozero::internal::gen_helpers::EqualsField(disabled_tags_, other.disabled_tags_)
- && ::protozero::internal::gen_helpers::EqualsField(enabled_tags_, other.enabled_tags_)
- && ::protozero::internal::gen_helpers::EqualsField(disable_incremental_timestamps_, other.disable_incremental_timestamps_)
- && ::protozero::internal::gen_helpers::EqualsField(timestamp_unit_multiplier_, other.timestamp_unit_multiplier_)
- && ::protozero::internal::gen_helpers::EqualsField(filter_debug_annotations_, other.filter_debug_annotations_)
- && ::protozero::internal::gen_helpers::EqualsField(enable_thread_time_sampling_, other.enable_thread_time_sampling_)
- && ::protozero::internal::gen_helpers::EqualsField(thread_time_subsampling_ns_, other.thread_time_subsampling_ns_)
- && ::protozero::internal::gen_helpers::EqualsField(filter_dynamic_event_names_, other.filter_dynamic_event_names_);
+ && ::protozero::internal::gen_helpers::EqualsField(enabled_, other.enabled_);
}
-bool TrackEventConfig::ParseFromArray(const void* raw, size_t size) {
- disabled_categories_.clear();
- enabled_categories_.clear();
- disabled_tags_.clear();
- enabled_tags_.clear();
+bool FtraceConfig_CompactSchedConfig::ParseFromArray(const void* raw, size_t size) {
unknown_fields_.clear();
bool packed_error = false;
@@ -27377,39 +26810,8 @@ bool TrackEventConfig::ParseFromArray(const void* raw, size_t size) {
_has_field_.set(field.id());
}
switch (field.id()) {
- case 1 /* disabled_categories */:
- disabled_categories_.emplace_back();
- ::protozero::internal::gen_helpers::DeserializeString(field, &disabled_categories_.back());
- break;
- case 2 /* enabled_categories */:
- enabled_categories_.emplace_back();
- ::protozero::internal::gen_helpers::DeserializeString(field, &enabled_categories_.back());
- break;
- case 3 /* disabled_tags */:
- disabled_tags_.emplace_back();
- ::protozero::internal::gen_helpers::DeserializeString(field, &disabled_tags_.back());
- break;
- case 4 /* enabled_tags */:
- enabled_tags_.emplace_back();
- ::protozero::internal::gen_helpers::DeserializeString(field, &enabled_tags_.back());
- break;
- case 5 /* disable_incremental_timestamps */:
- field.get(&disable_incremental_timestamps_);
- break;
- case 6 /* timestamp_unit_multiplier */:
- field.get(×tamp_unit_multiplier_);
- break;
- case 7 /* filter_debug_annotations */:
- field.get(&filter_debug_annotations_);
- break;
- case 8 /* enable_thread_time_sampling */:
- field.get(&enable_thread_time_sampling_);
- break;
- case 10 /* thread_time_subsampling_ns */:
- field.get(&thread_time_subsampling_ns_);
- break;
- case 9 /* filter_dynamic_event_names */:
- field.get(&filter_dynamic_event_names_);
+ case 1 /* enabled */:
+ field.get(&enabled_);
break;
default:
field.SerializeAndAppendTo(&unknown_fields_);
@@ -27419,67 +26821,22 @@ bool TrackEventConfig::ParseFromArray(const void* raw, size_t size) {
return !packed_error && !dec.bytes_left();
}
-std::string TrackEventConfig::SerializeAsString() const {
+std::string FtraceConfig_CompactSchedConfig::SerializeAsString() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsString();
}
-std::vector<uint8_t> TrackEventConfig::SerializeAsArray() const {
+std::vector<uint8_t> FtraceConfig_CompactSchedConfig::SerializeAsArray() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsArray();
}
-void TrackEventConfig::Serialize(::protozero::Message* msg) const {
- // Field 1: disabled_categories
- for (auto& it : disabled_categories_) {
- ::protozero::internal::gen_helpers::SerializeString(1, it, msg);
- }
-
- // Field 2: enabled_categories
- for (auto& it : enabled_categories_) {
- ::protozero::internal::gen_helpers::SerializeString(2, it, msg);
- }
-
- // Field 3: disabled_tags
- for (auto& it : disabled_tags_) {
- ::protozero::internal::gen_helpers::SerializeString(3, it, msg);
- }
-
- // Field 4: enabled_tags
- for (auto& it : enabled_tags_) {
- ::protozero::internal::gen_helpers::SerializeString(4, it, msg);
- }
-
- // Field 5: disable_incremental_timestamps
- if (_has_field_[5]) {
- ::protozero::internal::gen_helpers::SerializeTinyVarInt(5, disable_incremental_timestamps_, msg);
- }
-
- // Field 6: timestamp_unit_multiplier
- if (_has_field_[6]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(6, timestamp_unit_multiplier_, msg);
- }
-
- // Field 7: filter_debug_annotations
- if (_has_field_[7]) {
- ::protozero::internal::gen_helpers::SerializeTinyVarInt(7, filter_debug_annotations_, msg);
- }
-
- // Field 8: enable_thread_time_sampling
- if (_has_field_[8]) {
- ::protozero::internal::gen_helpers::SerializeTinyVarInt(8, enable_thread_time_sampling_, msg);
- }
-
- // Field 10: thread_time_subsampling_ns
- if (_has_field_[10]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(10, thread_time_subsampling_ns_, msg);
- }
-
- // Field 9: filter_dynamic_event_names
- if (_has_field_[9]) {
- ::protozero::internal::gen_helpers::SerializeTinyVarInt(9, filter_dynamic_event_names_, msg);
+void FtraceConfig_CompactSchedConfig::Serialize(::protozero::Message* msg) const {
+ // Field 1: enabled
+ if (_has_field_[1]) {
+ ::protozero::internal::gen_helpers::SerializeTinyVarInt(1, enabled_, msg);
}
protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
@@ -27491,7 +26848,7 @@ void TrackEventConfig::Serialize(::protozero::Message* msg) const {
#if defined(__GNUC__) || defined(__clang__)
#pragma GCC diagnostic pop
#endif
-// gen_amalgamated begin source: gen/protos/perfetto/config/chrome/chrome_config.gen.cc
+// gen_amalgamated begin source: gen/protos/perfetto/config/gpu/gpu_counter_config.gen.cc
// gen_amalgamated expanded: #include "perfetto/protozero/gen_field_helpers.h"
// gen_amalgamated expanded: #include "perfetto/protozero/message.h"
// gen_amalgamated expanded: #include "perfetto/protozero/packed_repeated_fields.h"
@@ -27502,30 +26859,32 @@ void TrackEventConfig::Serialize(::protozero::Message* msg) const {
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wfloat-equal"
#endif
-// gen_amalgamated expanded: #include "protos/perfetto/config/chrome/chrome_config.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/config/gpu/gpu_counter_config.gen.h"
namespace perfetto {
namespace protos {
namespace gen {
-ChromeConfig::ChromeConfig() = default;
-ChromeConfig::~ChromeConfig() = default;
-ChromeConfig::ChromeConfig(const ChromeConfig&) = default;
-ChromeConfig& ChromeConfig::operator=(const ChromeConfig&) = default;
-ChromeConfig::ChromeConfig(ChromeConfig&&) noexcept = default;
-ChromeConfig& ChromeConfig::operator=(ChromeConfig&&) = default;
+GpuCounterConfig::GpuCounterConfig() = default;
+GpuCounterConfig::~GpuCounterConfig() = default;
+GpuCounterConfig::GpuCounterConfig(const GpuCounterConfig&) = default;
+GpuCounterConfig& GpuCounterConfig::operator=(const GpuCounterConfig&) = default;
+GpuCounterConfig::GpuCounterConfig(GpuCounterConfig&&) noexcept = default;
+GpuCounterConfig& GpuCounterConfig::operator=(GpuCounterConfig&&) = default;
-bool ChromeConfig::operator==(const ChromeConfig& other) const {
+bool GpuCounterConfig::operator==(const GpuCounterConfig& other) const {
return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
- && ::protozero::internal::gen_helpers::EqualsField(trace_config_, other.trace_config_)
- && ::protozero::internal::gen_helpers::EqualsField(privacy_filtering_enabled_, other.privacy_filtering_enabled_)
- && ::protozero::internal::gen_helpers::EqualsField(convert_to_legacy_json_, other.convert_to_legacy_json_)
- && ::protozero::internal::gen_helpers::EqualsField(client_priority_, other.client_priority_)
- && ::protozero::internal::gen_helpers::EqualsField(json_agent_label_filter_, other.json_agent_label_filter_)
- && ::protozero::internal::gen_helpers::EqualsField(event_package_name_filter_enabled_, other.event_package_name_filter_enabled_);
+ && ::protozero::internal::gen_helpers::EqualsField(counter_period_ns_, other.counter_period_ns_)
+ && ::protozero::internal::gen_helpers::EqualsField(counter_ids_, other.counter_ids_)
+ && ::protozero::internal::gen_helpers::EqualsField(counter_names_, other.counter_names_)
+ && ::protozero::internal::gen_helpers::EqualsField(instrumented_sampling_, other.instrumented_sampling_)
+ && ::protozero::internal::gen_helpers::EqualsField(instrumented_sampling_config_, other.instrumented_sampling_config_)
+ && ::protozero::internal::gen_helpers::EqualsField(fix_gpu_clock_, other.fix_gpu_clock_);
}
-bool ChromeConfig::ParseFromArray(const void* raw, size_t size) {
+bool GpuCounterConfig::ParseFromArray(const void* raw, size_t size) {
+ counter_ids_.clear();
+ counter_names_.clear();
unknown_fields_.clear();
bool packed_error = false;
@@ -27535,23 +26894,25 @@ bool ChromeConfig::ParseFromArray(const void* raw, size_t size) {
_has_field_.set(field.id());
}
switch (field.id()) {
- case 1 /* trace_config */:
- ::protozero::internal::gen_helpers::DeserializeString(field, &trace_config_);
+ case 1 /* counter_period_ns */:
+ field.get(&counter_period_ns_);
break;
- case 2 /* privacy_filtering_enabled */:
- field.get(&privacy_filtering_enabled_);
+ case 2 /* counter_ids */:
+ counter_ids_.emplace_back();
+ field.get(&counter_ids_.back());
break;
- case 3 /* convert_to_legacy_json */:
- field.get(&convert_to_legacy_json_);
+ case 6 /* counter_names */:
+ counter_names_.emplace_back();
+ ::protozero::internal::gen_helpers::DeserializeString(field, &counter_names_.back());
break;
- case 4 /* client_priority */:
- field.get(&client_priority_);
+ case 3 /* instrumented_sampling */:
+ field.get(&instrumented_sampling_);
break;
- case 5 /* json_agent_label_filter */:
- ::protozero::internal::gen_helpers::DeserializeString(field, &json_agent_label_filter_);
+ case 5 /* instrumented_sampling_config */:
+ (*instrumented_sampling_config_).ParseFromArray(field.data(), field.size());
break;
- case 6 /* event_package_name_filter_enabled */:
- field.get(&event_package_name_filter_enabled_);
+ case 4 /* fix_gpu_clock */:
+ field.get(&fix_gpu_clock_);
break;
default:
field.SerializeAndAppendTo(&unknown_fields_);
@@ -27561,93 +26922,79 @@ bool ChromeConfig::ParseFromArray(const void* raw, size_t size) {
return !packed_error && !dec.bytes_left();
}
-std::string ChromeConfig::SerializeAsString() const {
+std::string GpuCounterConfig::SerializeAsString() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsString();
}
-std::vector<uint8_t> ChromeConfig::SerializeAsArray() const {
+std::vector<uint8_t> GpuCounterConfig::SerializeAsArray() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsArray();
}
-void ChromeConfig::Serialize(::protozero::Message* msg) const {
- // Field 1: trace_config
+void GpuCounterConfig::Serialize(::protozero::Message* msg) const {
+ // Field 1: counter_period_ns
if (_has_field_[1]) {
- ::protozero::internal::gen_helpers::SerializeString(1, trace_config_, msg);
+ ::protozero::internal::gen_helpers::SerializeVarInt(1, counter_period_ns_, msg);
}
- // Field 2: privacy_filtering_enabled
- if (_has_field_[2]) {
- ::protozero::internal::gen_helpers::SerializeTinyVarInt(2, privacy_filtering_enabled_, msg);
+ // Field 2: counter_ids
+ for (auto& it : counter_ids_) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(2, it, msg);
}
- // Field 3: convert_to_legacy_json
- if (_has_field_[3]) {
- ::protozero::internal::gen_helpers::SerializeTinyVarInt(3, convert_to_legacy_json_, msg);
+ // Field 6: counter_names
+ for (auto& it : counter_names_) {
+ ::protozero::internal::gen_helpers::SerializeString(6, it, msg);
}
- // Field 4: client_priority
- if (_has_field_[4]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(4, client_priority_, msg);
+ // Field 3: instrumented_sampling
+ if (_has_field_[3]) {
+ ::protozero::internal::gen_helpers::SerializeTinyVarInt(3, instrumented_sampling_, msg);
}
- // Field 5: json_agent_label_filter
+ // Field 5: instrumented_sampling_config
if (_has_field_[5]) {
- ::protozero::internal::gen_helpers::SerializeString(5, json_agent_label_filter_, msg);
+ (*instrumented_sampling_config_).Serialize(msg->BeginNestedMessage<::protozero::Message>(5));
}
- // Field 6: event_package_name_filter_enabled
- if (_has_field_[6]) {
- ::protozero::internal::gen_helpers::SerializeTinyVarInt(6, event_package_name_filter_enabled_, msg);
+ // Field 4: fix_gpu_clock
+ if (_has_field_[4]) {
+ ::protozero::internal::gen_helpers::SerializeTinyVarInt(4, fix_gpu_clock_, msg);
}
protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
}
-} // namespace perfetto
-} // namespace protos
-} // namespace gen
-#if defined(__GNUC__) || defined(__clang__)
-#pragma GCC diagnostic pop
-#endif
-// gen_amalgamated begin source: gen/protos/perfetto/config/chrome/histogram_samples.gen.cc
-// gen_amalgamated expanded: #include "perfetto/protozero/gen_field_helpers.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/message.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/packed_repeated_fields.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/proto_decoder.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/scattered_heap_buffer.h"
-// DO NOT EDIT. Autogenerated by Perfetto cppgen_plugin
-#if defined(__GNUC__) || defined(__clang__)
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wfloat-equal"
-#endif
-// gen_amalgamated expanded: #include "protos/perfetto/config/chrome/histogram_samples.gen.h"
-
-namespace perfetto {
-namespace protos {
-namespace gen {
-ChromiumHistogramSamplesConfig::ChromiumHistogramSamplesConfig() = default;
-ChromiumHistogramSamplesConfig::~ChromiumHistogramSamplesConfig() = default;
-ChromiumHistogramSamplesConfig::ChromiumHistogramSamplesConfig(const ChromiumHistogramSamplesConfig&) = default;
-ChromiumHistogramSamplesConfig& ChromiumHistogramSamplesConfig::operator=(const ChromiumHistogramSamplesConfig&) = default;
-ChromiumHistogramSamplesConfig::ChromiumHistogramSamplesConfig(ChromiumHistogramSamplesConfig&&) noexcept = default;
-ChromiumHistogramSamplesConfig& ChromiumHistogramSamplesConfig::operator=(ChromiumHistogramSamplesConfig&&) = default;
+GpuCounterConfig_InstrumentedSamplingConfig::GpuCounterConfig_InstrumentedSamplingConfig() = default;
+GpuCounterConfig_InstrumentedSamplingConfig::~GpuCounterConfig_InstrumentedSamplingConfig() = default;
+GpuCounterConfig_InstrumentedSamplingConfig::GpuCounterConfig_InstrumentedSamplingConfig(const GpuCounterConfig_InstrumentedSamplingConfig&) = default;
+GpuCounterConfig_InstrumentedSamplingConfig& GpuCounterConfig_InstrumentedSamplingConfig::operator=(const GpuCounterConfig_InstrumentedSamplingConfig&) = default;
+GpuCounterConfig_InstrumentedSamplingConfig::GpuCounterConfig_InstrumentedSamplingConfig(GpuCounterConfig_InstrumentedSamplingConfig&&) noexcept = default;
+GpuCounterConfig_InstrumentedSamplingConfig& GpuCounterConfig_InstrumentedSamplingConfig::operator=(GpuCounterConfig_InstrumentedSamplingConfig&&) = default;
-bool ChromiumHistogramSamplesConfig::operator==(const ChromiumHistogramSamplesConfig& other) const {
+bool GpuCounterConfig_InstrumentedSamplingConfig::operator==(const GpuCounterConfig_InstrumentedSamplingConfig& other) const {
return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
- && ::protozero::internal::gen_helpers::EqualsField(histograms_, other.histograms_)
- && ::protozero::internal::gen_helpers::EqualsField(filter_histogram_names_, other.filter_histogram_names_);
+ && ::protozero::internal::gen_helpers::EqualsField(activity_name_filters_, other.activity_name_filters_)
+ && ::protozero::internal::gen_helpers::EqualsField(activity_tx_include_globs_, other.activity_tx_include_globs_)
+ && ::protozero::internal::gen_helpers::EqualsField(activity_tx_exclude_globs_, other.activity_tx_exclude_globs_)
+ && ::protozero::internal::gen_helpers::EqualsField(activity_ranges_, other.activity_ranges_);
}
-int ChromiumHistogramSamplesConfig::histograms_size() const { return static_cast<int>(histograms_.size()); }
-void ChromiumHistogramSamplesConfig::clear_histograms() { histograms_.clear(); }
-ChromiumHistogramSamplesConfig_HistogramSample* ChromiumHistogramSamplesConfig::add_histograms() { histograms_.emplace_back(); return &histograms_.back(); }
-bool ChromiumHistogramSamplesConfig::ParseFromArray(const void* raw, size_t size) {
- histograms_.clear();
+int GpuCounterConfig_InstrumentedSamplingConfig::activity_name_filters_size() const { return static_cast<int>(activity_name_filters_.size()); }
+void GpuCounterConfig_InstrumentedSamplingConfig::clear_activity_name_filters() { activity_name_filters_.clear(); }
+GpuCounterConfig_InstrumentedSamplingConfig_ActivityNameFilter* GpuCounterConfig_InstrumentedSamplingConfig::add_activity_name_filters() { activity_name_filters_.emplace_back(); return &activity_name_filters_.back(); }
+int GpuCounterConfig_InstrumentedSamplingConfig::activity_ranges_size() const { return static_cast<int>(activity_ranges_.size()); }
+void GpuCounterConfig_InstrumentedSamplingConfig::clear_activity_ranges() { activity_ranges_.clear(); }
+GpuCounterConfig_InstrumentedSamplingConfig_ActivityRange* GpuCounterConfig_InstrumentedSamplingConfig::add_activity_ranges() { activity_ranges_.emplace_back(); return &activity_ranges_.back(); }
+bool GpuCounterConfig_InstrumentedSamplingConfig::ParseFromArray(const void* raw, size_t size) {
+ activity_name_filters_.clear();
+ activity_tx_include_globs_.clear();
+ activity_tx_exclude_globs_.clear();
+ activity_ranges_.clear();
unknown_fields_.clear();
bool packed_error = false;
@@ -27657,12 +27004,21 @@ bool ChromiumHistogramSamplesConfig::ParseFromArray(const void* raw, size_t size
_has_field_.set(field.id());
}
switch (field.id()) {
- case 1 /* histograms */:
- histograms_.emplace_back();
- histograms_.back().ParseFromArray(field.data(), field.size());
+ case 3 /* activity_name_filters */:
+ activity_name_filters_.emplace_back();
+ activity_name_filters_.back().ParseFromArray(field.data(), field.size());
break;
- case 2 /* filter_histogram_names */:
- field.get(&filter_histogram_names_);
+ case 6 /* activity_tx_include_globs */:
+ activity_tx_include_globs_.emplace_back();
+ ::protozero::internal::gen_helpers::DeserializeString(field, &activity_tx_include_globs_.back());
+ break;
+ case 7 /* activity_tx_exclude_globs */:
+ activity_tx_exclude_globs_.emplace_back();
+ ::protozero::internal::gen_helpers::DeserializeString(field, &activity_tx_exclude_globs_.back());
+ break;
+ case 5 /* activity_ranges */:
+ activity_ranges_.emplace_back();
+ activity_ranges_.back().ParseFromArray(field.data(), field.size());
break;
default:
field.SerializeAndAppendTo(&unknown_fields_);
@@ -27672,48 +27028,57 @@ bool ChromiumHistogramSamplesConfig::ParseFromArray(const void* raw, size_t size
return !packed_error && !dec.bytes_left();
}
-std::string ChromiumHistogramSamplesConfig::SerializeAsString() const {
+std::string GpuCounterConfig_InstrumentedSamplingConfig::SerializeAsString() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsString();
}
-std::vector<uint8_t> ChromiumHistogramSamplesConfig::SerializeAsArray() const {
+std::vector<uint8_t> GpuCounterConfig_InstrumentedSamplingConfig::SerializeAsArray() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsArray();
}
-void ChromiumHistogramSamplesConfig::Serialize(::protozero::Message* msg) const {
- // Field 1: histograms
- for (auto& it : histograms_) {
- it.Serialize(msg->BeginNestedMessage<::protozero::Message>(1));
+void GpuCounterConfig_InstrumentedSamplingConfig::Serialize(::protozero::Message* msg) const {
+ // Field 3: activity_name_filters
+ for (auto& it : activity_name_filters_) {
+ it.Serialize(msg->BeginNestedMessage<::protozero::Message>(3));
}
- // Field 2: filter_histogram_names
- if (_has_field_[2]) {
- ::protozero::internal::gen_helpers::SerializeTinyVarInt(2, filter_histogram_names_, msg);
+ // Field 6: activity_tx_include_globs
+ for (auto& it : activity_tx_include_globs_) {
+ ::protozero::internal::gen_helpers::SerializeString(6, it, msg);
+ }
+
+ // Field 7: activity_tx_exclude_globs
+ for (auto& it : activity_tx_exclude_globs_) {
+ ::protozero::internal::gen_helpers::SerializeString(7, it, msg);
+ }
+
+ // Field 5: activity_ranges
+ for (auto& it : activity_ranges_) {
+ it.Serialize(msg->BeginNestedMessage<::protozero::Message>(5));
}
protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
}
-ChromiumHistogramSamplesConfig_HistogramSample::ChromiumHistogramSamplesConfig_HistogramSample() = default;
-ChromiumHistogramSamplesConfig_HistogramSample::~ChromiumHistogramSamplesConfig_HistogramSample() = default;
-ChromiumHistogramSamplesConfig_HistogramSample::ChromiumHistogramSamplesConfig_HistogramSample(const ChromiumHistogramSamplesConfig_HistogramSample&) = default;
-ChromiumHistogramSamplesConfig_HistogramSample& ChromiumHistogramSamplesConfig_HistogramSample::operator=(const ChromiumHistogramSamplesConfig_HistogramSample&) = default;
-ChromiumHistogramSamplesConfig_HistogramSample::ChromiumHistogramSamplesConfig_HistogramSample(ChromiumHistogramSamplesConfig_HistogramSample&&) noexcept = default;
-ChromiumHistogramSamplesConfig_HistogramSample& ChromiumHistogramSamplesConfig_HistogramSample::operator=(ChromiumHistogramSamplesConfig_HistogramSample&&) = default;
+GpuCounterConfig_InstrumentedSamplingConfig_ActivityRange::GpuCounterConfig_InstrumentedSamplingConfig_ActivityRange() = default;
+GpuCounterConfig_InstrumentedSamplingConfig_ActivityRange::~GpuCounterConfig_InstrumentedSamplingConfig_ActivityRange() = default;
+GpuCounterConfig_InstrumentedSamplingConfig_ActivityRange::GpuCounterConfig_InstrumentedSamplingConfig_ActivityRange(const GpuCounterConfig_InstrumentedSamplingConfig_ActivityRange&) = default;
+GpuCounterConfig_InstrumentedSamplingConfig_ActivityRange& GpuCounterConfig_InstrumentedSamplingConfig_ActivityRange::operator=(const GpuCounterConfig_InstrumentedSamplingConfig_ActivityRange&) = default;
+GpuCounterConfig_InstrumentedSamplingConfig_ActivityRange::GpuCounterConfig_InstrumentedSamplingConfig_ActivityRange(GpuCounterConfig_InstrumentedSamplingConfig_ActivityRange&&) noexcept = default;
+GpuCounterConfig_InstrumentedSamplingConfig_ActivityRange& GpuCounterConfig_InstrumentedSamplingConfig_ActivityRange::operator=(GpuCounterConfig_InstrumentedSamplingConfig_ActivityRange&&) = default;
-bool ChromiumHistogramSamplesConfig_HistogramSample::operator==(const ChromiumHistogramSamplesConfig_HistogramSample& other) const {
+bool GpuCounterConfig_InstrumentedSamplingConfig_ActivityRange::operator==(const GpuCounterConfig_InstrumentedSamplingConfig_ActivityRange& other) const {
return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
- && ::protozero::internal::gen_helpers::EqualsField(histogram_name_, other.histogram_name_)
- && ::protozero::internal::gen_helpers::EqualsField(min_value_, other.min_value_)
- && ::protozero::internal::gen_helpers::EqualsField(max_value_, other.max_value_);
+ && ::protozero::internal::gen_helpers::EqualsField(skip_, other.skip_)
+ && ::protozero::internal::gen_helpers::EqualsField(count_, other.count_);
}
-bool ChromiumHistogramSamplesConfig_HistogramSample::ParseFromArray(const void* raw, size_t size) {
+bool GpuCounterConfig_InstrumentedSamplingConfig_ActivityRange::ParseFromArray(const void* raw, size_t size) {
unknown_fields_.clear();
bool packed_error = false;
@@ -27723,14 +27088,11 @@ bool ChromiumHistogramSamplesConfig_HistogramSample::ParseFromArray(const void*
_has_field_.set(field.id());
}
switch (field.id()) {
- case 1 /* histogram_name */:
- ::protozero::internal::gen_helpers::DeserializeString(field, &histogram_name_);
- break;
- case 2 /* min_value */:
- field.get(&min_value_);
+ case 1 /* skip */:
+ field.get(&skip_);
break;
- case 3 /* max_value */:
- field.get(&max_value_);
+ case 2 /* count */:
+ field.get(&count_);
break;
default:
field.SerializeAndAppendTo(&unknown_fields_);
@@ -27740,134 +27102,47 @@ bool ChromiumHistogramSamplesConfig_HistogramSample::ParseFromArray(const void*
return !packed_error && !dec.bytes_left();
}
-std::string ChromiumHistogramSamplesConfig_HistogramSample::SerializeAsString() const {
+std::string GpuCounterConfig_InstrumentedSamplingConfig_ActivityRange::SerializeAsString() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsString();
}
-std::vector<uint8_t> ChromiumHistogramSamplesConfig_HistogramSample::SerializeAsArray() const {
+std::vector<uint8_t> GpuCounterConfig_InstrumentedSamplingConfig_ActivityRange::SerializeAsArray() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsArray();
}
-void ChromiumHistogramSamplesConfig_HistogramSample::Serialize(::protozero::Message* msg) const {
- // Field 1: histogram_name
+void GpuCounterConfig_InstrumentedSamplingConfig_ActivityRange::Serialize(::protozero::Message* msg) const {
+ // Field 1: skip
if (_has_field_[1]) {
- ::protozero::internal::gen_helpers::SerializeString(1, histogram_name_, msg);
+ ::protozero::internal::gen_helpers::SerializeVarInt(1, skip_, msg);
}
- // Field 2: min_value
+ // Field 2: count
if (_has_field_[2]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(2, min_value_, msg);
- }
-
- // Field 3: max_value
- if (_has_field_[3]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(3, max_value_, msg);
+ ::protozero::internal::gen_helpers::SerializeVarInt(2, count_, msg);
}
protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
}
-} // namespace perfetto
-} // namespace protos
-} // namespace gen
-#if defined(__GNUC__) || defined(__clang__)
-#pragma GCC diagnostic pop
-#endif
-// gen_amalgamated begin source: gen/protos/perfetto/config/chrome/scenario_config.gen.cc
-// gen_amalgamated expanded: #include "perfetto/protozero/gen_field_helpers.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/message.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/packed_repeated_fields.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/proto_decoder.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/scattered_heap_buffer.h"
-// DO NOT EDIT. Autogenerated by Perfetto cppgen_plugin
-#if defined(__GNUC__) || defined(__clang__)
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wfloat-equal"
-#endif
-// gen_amalgamated expanded: #include "protos/perfetto/config/chrome/scenario_config.gen.h"
-// gen_amalgamated expanded: #include "protos/perfetto/config/trace_config.gen.h"
-// gen_amalgamated expanded: #include "protos/perfetto/config/priority_boost/priority_boost_config.gen.h"
-// gen_amalgamated expanded: #include "protos/perfetto/config/data_source_config.gen.h"
-// gen_amalgamated expanded: #include "protos/perfetto/config/qnx/qnx_config.gen.h"
-// gen_amalgamated expanded: #include "protos/perfetto/config/linux/journald_config.gen.h"
-// gen_amalgamated expanded: #include "protos/perfetto/config/chrome/histogram_samples.gen.h"
-// gen_amalgamated expanded: #include "protos/perfetto/config/system_info/system_info_config.gen.h"
-// gen_amalgamated expanded: #include "protos/perfetto/config/track_event/track_event_config.gen.h"
-// gen_amalgamated expanded: #include "protos/perfetto/config/test_config.gen.h"
-// gen_amalgamated expanded: #include "protos/perfetto/config/sys_stats/sys_stats_config.gen.h"
-// gen_amalgamated expanded: #include "protos/perfetto/common/sys_stats_counters.gen.h"
-// gen_amalgamated expanded: #include "protos/perfetto/config/profiling/perf_event_config.gen.h"
-// gen_amalgamated expanded: #include "protos/perfetto/common/perf_events.gen.h"
-// gen_amalgamated expanded: #include "protos/perfetto/config/profiling/java_hprof_config.gen.h"
-// gen_amalgamated expanded: #include "protos/perfetto/config/profiling/smaps_config.gen.h"
-// gen_amalgamated expanded: #include "protos/perfetto/config/profiling/heapprofd_config.gen.h"
-// gen_amalgamated expanded: #include "protos/perfetto/config/process_stats/process_stats_config.gen.h"
-// gen_amalgamated expanded: #include "protos/perfetto/config/statsd/statsd_tracing_config.gen.h"
-// gen_amalgamated expanded: #include "protos/perfetto/config/statsd/atom_ids.gen.h"
-// gen_amalgamated expanded: #include "protos/perfetto/config/protovm/protovm_config.gen.h"
-// gen_amalgamated expanded: #include "protos/perfetto/config/power/android_power_config.gen.h"
-// gen_amalgamated expanded: #include "protos/perfetto/config/interceptor_config.gen.h"
-// gen_amalgamated expanded: #include "protos/perfetto/config/interceptors/console_config.gen.h"
-// gen_amalgamated expanded: #include "protos/perfetto/config/inode_file/inode_file_config.gen.h"
-// gen_amalgamated expanded: #include "protos/perfetto/config/gpu/gpu_renderstages_config.gen.h"
-// gen_amalgamated expanded: #include "protos/perfetto/config/gpu/vulkan_memory_config.gen.h"
-// gen_amalgamated expanded: #include "protos/perfetto/config/gpu/gpu_counter_config.gen.h"
-// gen_amalgamated expanded: #include "protos/perfetto/config/ftrace/frozen_ftrace_config.gen.h"
-// gen_amalgamated expanded: #include "protos/perfetto/config/ftrace/ftrace_config.gen.h"
-// gen_amalgamated expanded: #include "protos/perfetto/config/chrome/system_metrics.gen.h"
-// gen_amalgamated expanded: #include "protos/perfetto/config/etw/etw_config.gen.h"
-// gen_amalgamated expanded: #include "protos/perfetto/config/chrome/v8_config.gen.h"
-// gen_amalgamated expanded: #include "protos/perfetto/config/chrome/chrome_config.gen.h"
-// gen_amalgamated expanded: #include "protos/perfetto/config/android/windowmanager_config.gen.h"
-// gen_amalgamated expanded: #include "protos/perfetto/config/android/user_list_config.gen.h"
-// gen_amalgamated expanded: #include "protos/perfetto/config/android/surfaceflinger_transactions_config.gen.h"
-// gen_amalgamated expanded: #include "protos/perfetto/config/android/surfaceflinger_layers_config.gen.h"
-// gen_amalgamated expanded: #include "protos/perfetto/config/android/display_video_config.gen.h"
-// gen_amalgamated expanded: #include "protos/perfetto/config/android/protolog_config.gen.h"
-// gen_amalgamated expanded: #include "protos/perfetto/config/android/pixel_modem_config.gen.h"
-// gen_amalgamated expanded: #include "protos/perfetto/config/android/packages_list_config.gen.h"
-// gen_amalgamated expanded: #include "protos/perfetto/config/android/network_trace_config.gen.h"
-// gen_amalgamated expanded: #include "protos/perfetto/config/android/kernel_wakelocks_config.gen.h"
-// gen_amalgamated expanded: #include "protos/perfetto/config/android/inputmethod_config.gen.h"
-// gen_amalgamated expanded: #include "protos/perfetto/config/android/cpu_per_uid_config.gen.h"
-// gen_amalgamated expanded: #include "protos/perfetto/config/android/app_wakelock_config.gen.h"
-// gen_amalgamated expanded: #include "protos/perfetto/config/android/android_sdk_sysprop_guard_config.gen.h"
-// gen_amalgamated expanded: #include "protos/perfetto/config/android/android_system_property_config.gen.h"
-// gen_amalgamated expanded: #include "protos/perfetto/config/android/android_polled_state_config.gen.h"
-// gen_amalgamated expanded: #include "protos/perfetto/config/android/android_log_config.gen.h"
-// gen_amalgamated expanded: #include "protos/perfetto/common/android_log_constants.gen.h"
-// gen_amalgamated expanded: #include "protos/perfetto/config/android/android_input_event_config.gen.h"
-// gen_amalgamated expanded: #include "protos/perfetto/config/android/android_game_intervention_list_config.gen.h"
-// gen_amalgamated expanded: #include "protos/perfetto/config/android/android_aflags_config.gen.h"
-// gen_amalgamated expanded: #include "protos/perfetto/common/trace_attributes.gen.h"
-// gen_amalgamated expanded: #include "protos/perfetto/common/semantic_type.gen.h"
-// gen_amalgamated expanded: #include "protos/perfetto/common/builtin_clock.gen.h"
-
-namespace perfetto {
-namespace protos {
-namespace gen {
-TracingTriggerRulesConfig::TracingTriggerRulesConfig() = default;
-TracingTriggerRulesConfig::~TracingTriggerRulesConfig() = default;
-TracingTriggerRulesConfig::TracingTriggerRulesConfig(const TracingTriggerRulesConfig&) = default;
-TracingTriggerRulesConfig& TracingTriggerRulesConfig::operator=(const TracingTriggerRulesConfig&) = default;
-TracingTriggerRulesConfig::TracingTriggerRulesConfig(TracingTriggerRulesConfig&&) noexcept = default;
-TracingTriggerRulesConfig& TracingTriggerRulesConfig::operator=(TracingTriggerRulesConfig&&) = default;
+GpuCounterConfig_InstrumentedSamplingConfig_ActivityNameFilter::GpuCounterConfig_InstrumentedSamplingConfig_ActivityNameFilter() = default;
+GpuCounterConfig_InstrumentedSamplingConfig_ActivityNameFilter::~GpuCounterConfig_InstrumentedSamplingConfig_ActivityNameFilter() = default;
+GpuCounterConfig_InstrumentedSamplingConfig_ActivityNameFilter::GpuCounterConfig_InstrumentedSamplingConfig_ActivityNameFilter(const GpuCounterConfig_InstrumentedSamplingConfig_ActivityNameFilter&) = default;
+GpuCounterConfig_InstrumentedSamplingConfig_ActivityNameFilter& GpuCounterConfig_InstrumentedSamplingConfig_ActivityNameFilter::operator=(const GpuCounterConfig_InstrumentedSamplingConfig_ActivityNameFilter&) = default;
+GpuCounterConfig_InstrumentedSamplingConfig_ActivityNameFilter::GpuCounterConfig_InstrumentedSamplingConfig_ActivityNameFilter(GpuCounterConfig_InstrumentedSamplingConfig_ActivityNameFilter&&) noexcept = default;
+GpuCounterConfig_InstrumentedSamplingConfig_ActivityNameFilter& GpuCounterConfig_InstrumentedSamplingConfig_ActivityNameFilter::operator=(GpuCounterConfig_InstrumentedSamplingConfig_ActivityNameFilter&&) = default;
-bool TracingTriggerRulesConfig::operator==(const TracingTriggerRulesConfig& other) const {
+bool GpuCounterConfig_InstrumentedSamplingConfig_ActivityNameFilter::operator==(const GpuCounterConfig_InstrumentedSamplingConfig_ActivityNameFilter& other) const {
return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
- && ::protozero::internal::gen_helpers::EqualsField(rules_, other.rules_);
+ && ::protozero::internal::gen_helpers::EqualsField(name_glob_, other.name_glob_)
+ && ::protozero::internal::gen_helpers::EqualsField(name_base_, other.name_base_);
}
-int TracingTriggerRulesConfig::rules_size() const { return static_cast<int>(rules_.size()); }
-void TracingTriggerRulesConfig::clear_rules() { rules_.clear(); }
-TriggerRule* TracingTriggerRulesConfig::add_rules() { rules_.emplace_back(); return &rules_.back(); }
-bool TracingTriggerRulesConfig::ParseFromArray(const void* raw, size_t size) {
- rules_.clear();
+bool GpuCounterConfig_InstrumentedSamplingConfig_ActivityNameFilter::ParseFromArray(const void* raw, size_t size) {
unknown_fields_.clear();
bool packed_error = false;
@@ -27877,9 +27152,11 @@ bool TracingTriggerRulesConfig::ParseFromArray(const void* raw, size_t size) {
_has_field_.set(field.id());
}
switch (field.id()) {
- case 1 /* rules */:
- rules_.emplace_back();
- rules_.back().ParseFromArray(field.data(), field.size());
+ case 1 /* name_glob */:
+ ::protozero::internal::gen_helpers::DeserializeString(field, &name_glob_);
+ break;
+ case 2 /* name_base */:
+ field.get(&name_base_);
break;
default:
field.SerializeAndAppendTo(&unknown_fields_);
@@ -27889,47 +27166,72 @@ bool TracingTriggerRulesConfig::ParseFromArray(const void* raw, size_t size) {
return !packed_error && !dec.bytes_left();
}
-std::string TracingTriggerRulesConfig::SerializeAsString() const {
+std::string GpuCounterConfig_InstrumentedSamplingConfig_ActivityNameFilter::SerializeAsString() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsString();
}
-std::vector<uint8_t> TracingTriggerRulesConfig::SerializeAsArray() const {
+std::vector<uint8_t> GpuCounterConfig_InstrumentedSamplingConfig_ActivityNameFilter::SerializeAsArray() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsArray();
}
-void TracingTriggerRulesConfig::Serialize(::protozero::Message* msg) const {
- // Field 1: rules
- for (auto& it : rules_) {
- it.Serialize(msg->BeginNestedMessage<::protozero::Message>(1));
+void GpuCounterConfig_InstrumentedSamplingConfig_ActivityNameFilter::Serialize(::protozero::Message* msg) const {
+ // Field 1: name_glob
+ if (_has_field_[1]) {
+ ::protozero::internal::gen_helpers::SerializeString(1, name_glob_, msg);
+ }
+
+ // Field 2: name_base
+ if (_has_field_[2]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(2, name_base_, msg);
}
protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
}
+} // namespace perfetto
+} // namespace protos
+} // namespace gen
+#if defined(__GNUC__) || defined(__clang__)
+#pragma GCC diagnostic pop
+#endif
+// gen_amalgamated begin source: gen/protos/perfetto/config/gpu/gpu_renderstages_config.gen.cc
+// gen_amalgamated expanded: #include "perfetto/protozero/gen_field_helpers.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/message.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/packed_repeated_fields.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/proto_decoder.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/scattered_heap_buffer.h"
+// DO NOT EDIT. Autogenerated by Perfetto cppgen_plugin
+#if defined(__GNUC__) || defined(__clang__)
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wfloat-equal"
+#endif
+// gen_amalgamated expanded: #include "protos/perfetto/config/gpu/gpu_renderstages_config.gen.h"
-TriggerRule::TriggerRule() = default;
-TriggerRule::~TriggerRule() = default;
-TriggerRule::TriggerRule(const TriggerRule&) = default;
-TriggerRule& TriggerRule::operator=(const TriggerRule&) = default;
-TriggerRule::TriggerRule(TriggerRule&&) noexcept = default;
-TriggerRule& TriggerRule::operator=(TriggerRule&&) = default;
+namespace perfetto {
+namespace protos {
+namespace gen {
-bool TriggerRule::operator==(const TriggerRule& other) const {
+GpuRenderStagesConfig::GpuRenderStagesConfig() = default;
+GpuRenderStagesConfig::~GpuRenderStagesConfig() = default;
+GpuRenderStagesConfig::GpuRenderStagesConfig(const GpuRenderStagesConfig&) = default;
+GpuRenderStagesConfig& GpuRenderStagesConfig::operator=(const GpuRenderStagesConfig&) = default;
+GpuRenderStagesConfig::GpuRenderStagesConfig(GpuRenderStagesConfig&&) noexcept = default;
+GpuRenderStagesConfig& GpuRenderStagesConfig::operator=(GpuRenderStagesConfig&&) = default;
+
+bool GpuRenderStagesConfig::operator==(const GpuRenderStagesConfig& other) const {
return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
- && ::protozero::internal::gen_helpers::EqualsField(name_, other.name_)
- && ::protozero::internal::gen_helpers::EqualsField(trigger_chance_, other.trigger_chance_)
- && ::protozero::internal::gen_helpers::EqualsField(delay_ms_, other.delay_ms_)
- && ::protozero::internal::gen_helpers::EqualsField(activation_delay_ms_, other.activation_delay_ms_)
- && ::protozero::internal::gen_helpers::EqualsField(manual_trigger_name_, other.manual_trigger_name_)
- && ::protozero::internal::gen_helpers::EqualsField(histogram_, other.histogram_)
- && ::protozero::internal::gen_helpers::EqualsField(repeating_interval_, other.repeating_interval_);
+ && ::protozero::internal::gen_helpers::EqualsField(full_loadstore_, other.full_loadstore_)
+ && ::protozero::internal::gen_helpers::EqualsField(low_overhead_, other.low_overhead_)
+ && ::protozero::internal::gen_helpers::EqualsField(trace_metrics_, other.trace_metrics_)
+ && ::protozero::internal::gen_helpers::EqualsField(drawcall_stages_, other.drawcall_stages_);
}
-bool TriggerRule::ParseFromArray(const void* raw, size_t size) {
+bool GpuRenderStagesConfig::ParseFromArray(const void* raw, size_t size) {
+ trace_metrics_.clear();
unknown_fields_.clear();
bool packed_error = false;
@@ -27939,26 +27241,18 @@ bool TriggerRule::ParseFromArray(const void* raw, size_t size) {
_has_field_.set(field.id());
}
switch (field.id()) {
- case 1 /* name */:
- ::protozero::internal::gen_helpers::DeserializeString(field, &name_);
- break;
- case 2 /* trigger_chance */:
- field.get(&trigger_chance_);
- break;
- case 3 /* delay_ms */:
- field.get(&delay_ms_);
- break;
- case 8 /* activation_delay_ms */:
- field.get(&activation_delay_ms_);
+ case 1 /* full_loadstore */:
+ field.get(&full_loadstore_);
break;
- case 4 /* manual_trigger_name */:
- ::protozero::internal::gen_helpers::DeserializeString(field, &manual_trigger_name_);
+ case 2 /* low_overhead */:
+ field.get(&low_overhead_);
break;
- case 5 /* histogram */:
- (*histogram_).ParseFromArray(field.data(), field.size());
+ case 3 /* trace_metrics */:
+ trace_metrics_.emplace_back();
+ ::protozero::internal::gen_helpers::DeserializeString(field, &trace_metrics_.back());
break;
- case 6 /* repeating_interval */:
- (*repeating_interval_).ParseFromArray(field.data(), field.size());
+ case 4 /* drawcall_stages */:
+ field.get(&drawcall_stages_);
break;
default:
field.SerializeAndAppendTo(&unknown_fields_);
@@ -27968,72 +27262,79 @@ bool TriggerRule::ParseFromArray(const void* raw, size_t size) {
return !packed_error && !dec.bytes_left();
}
-std::string TriggerRule::SerializeAsString() const {
+std::string GpuRenderStagesConfig::SerializeAsString() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsString();
}
-std::vector<uint8_t> TriggerRule::SerializeAsArray() const {
+std::vector<uint8_t> GpuRenderStagesConfig::SerializeAsArray() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsArray();
}
-void TriggerRule::Serialize(::protozero::Message* msg) const {
- // Field 1: name
+void GpuRenderStagesConfig::Serialize(::protozero::Message* msg) const {
+ // Field 1: full_loadstore
if (_has_field_[1]) {
- ::protozero::internal::gen_helpers::SerializeString(1, name_, msg);
+ ::protozero::internal::gen_helpers::SerializeTinyVarInt(1, full_loadstore_, msg);
}
- // Field 2: trigger_chance
+ // Field 2: low_overhead
if (_has_field_[2]) {
- ::protozero::internal::gen_helpers::SerializeFixed(2, trigger_chance_, msg);
- }
-
- // Field 3: delay_ms
- if (_has_field_[3]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(3, delay_ms_, msg);
+ ::protozero::internal::gen_helpers::SerializeTinyVarInt(2, low_overhead_, msg);
}
- // Field 8: activation_delay_ms
- if (_has_field_[8]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(8, activation_delay_ms_, msg);
+ // Field 3: trace_metrics
+ for (auto& it : trace_metrics_) {
+ ::protozero::internal::gen_helpers::SerializeString(3, it, msg);
}
- // Field 4: manual_trigger_name
+ // Field 4: drawcall_stages
if (_has_field_[4]) {
- ::protozero::internal::gen_helpers::SerializeString(4, manual_trigger_name_, msg);
- }
-
- // Field 5: histogram
- if (_has_field_[5]) {
- (*histogram_).Serialize(msg->BeginNestedMessage<::protozero::Message>(5));
- }
-
- // Field 6: repeating_interval
- if (_has_field_[6]) {
- (*repeating_interval_).Serialize(msg->BeginNestedMessage<::protozero::Message>(6));
+ ::protozero::internal::gen_helpers::SerializeTinyVarInt(4, drawcall_stages_, msg);
}
protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
}
+} // namespace perfetto
+} // namespace protos
+} // namespace gen
+#if defined(__GNUC__) || defined(__clang__)
+#pragma GCC diagnostic pop
+#endif
+// gen_amalgamated begin source: gen/protos/perfetto/config/gpu/vulkan_memory_config.gen.cc
+// gen_amalgamated expanded: #include "perfetto/protozero/gen_field_helpers.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/message.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/packed_repeated_fields.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/proto_decoder.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/scattered_heap_buffer.h"
+// DO NOT EDIT. Autogenerated by Perfetto cppgen_plugin
+#if defined(__GNUC__) || defined(__clang__)
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wfloat-equal"
+#endif
+// gen_amalgamated expanded: #include "protos/perfetto/config/gpu/vulkan_memory_config.gen.h"
+
+namespace perfetto {
+namespace protos {
+namespace gen {
-TriggerRule_RepeatingInterval::TriggerRule_RepeatingInterval() = default;
-TriggerRule_RepeatingInterval::~TriggerRule_RepeatingInterval() = default;
-TriggerRule_RepeatingInterval::TriggerRule_RepeatingInterval(const TriggerRule_RepeatingInterval&) = default;
-TriggerRule_RepeatingInterval& TriggerRule_RepeatingInterval::operator=(const TriggerRule_RepeatingInterval&) = default;
-TriggerRule_RepeatingInterval::TriggerRule_RepeatingInterval(TriggerRule_RepeatingInterval&&) noexcept = default;
-TriggerRule_RepeatingInterval& TriggerRule_RepeatingInterval::operator=(TriggerRule_RepeatingInterval&&) = default;
+VulkanMemoryConfig::VulkanMemoryConfig() = default;
+VulkanMemoryConfig::~VulkanMemoryConfig() = default;
+VulkanMemoryConfig::VulkanMemoryConfig(const VulkanMemoryConfig&) = default;
+VulkanMemoryConfig& VulkanMemoryConfig::operator=(const VulkanMemoryConfig&) = default;
+VulkanMemoryConfig::VulkanMemoryConfig(VulkanMemoryConfig&&) noexcept = default;
+VulkanMemoryConfig& VulkanMemoryConfig::operator=(VulkanMemoryConfig&&) = default;
-bool TriggerRule_RepeatingInterval::operator==(const TriggerRule_RepeatingInterval& other) const {
+bool VulkanMemoryConfig::operator==(const VulkanMemoryConfig& other) const {
return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
- && ::protozero::internal::gen_helpers::EqualsField(period_ms_, other.period_ms_)
- && ::protozero::internal::gen_helpers::EqualsField(randomized_, other.randomized_);
+ && ::protozero::internal::gen_helpers::EqualsField(track_driver_memory_usage_, other.track_driver_memory_usage_)
+ && ::protozero::internal::gen_helpers::EqualsField(track_device_memory_usage_, other.track_device_memory_usage_);
}
-bool TriggerRule_RepeatingInterval::ParseFromArray(const void* raw, size_t size) {
+bool VulkanMemoryConfig::ParseFromArray(const void* raw, size_t size) {
unknown_fields_.clear();
bool packed_error = false;
@@ -28043,11 +27344,11 @@ bool TriggerRule_RepeatingInterval::ParseFromArray(const void* raw, size_t size)
_has_field_.set(field.id());
}
switch (field.id()) {
- case 1 /* period_ms */:
- field.get(&period_ms_);
+ case 1 /* track_driver_memory_usage */:
+ field.get(&track_driver_memory_usage_);
break;
- case 2 /* randomized */:
- field.get(&randomized_);
+ case 2 /* track_device_memory_usage */:
+ field.get(&track_device_memory_usage_);
break;
default:
field.SerializeAndAppendTo(&unknown_fields_);
@@ -28057,48 +27358,78 @@ bool TriggerRule_RepeatingInterval::ParseFromArray(const void* raw, size_t size)
return !packed_error && !dec.bytes_left();
}
-std::string TriggerRule_RepeatingInterval::SerializeAsString() const {
+std::string VulkanMemoryConfig::SerializeAsString() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsString();
}
-std::vector<uint8_t> TriggerRule_RepeatingInterval::SerializeAsArray() const {
+std::vector<uint8_t> VulkanMemoryConfig::SerializeAsArray() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsArray();
}
-void TriggerRule_RepeatingInterval::Serialize(::protozero::Message* msg) const {
- // Field 1: period_ms
+void VulkanMemoryConfig::Serialize(::protozero::Message* msg) const {
+ // Field 1: track_driver_memory_usage
if (_has_field_[1]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(1, period_ms_, msg);
+ ::protozero::internal::gen_helpers::SerializeTinyVarInt(1, track_driver_memory_usage_, msg);
}
- // Field 2: randomized
+ // Field 2: track_device_memory_usage
if (_has_field_[2]) {
- ::protozero::internal::gen_helpers::SerializeTinyVarInt(2, randomized_, msg);
+ ::protozero::internal::gen_helpers::SerializeTinyVarInt(2, track_device_memory_usage_, msg);
}
protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
}
+} // namespace perfetto
+} // namespace protos
+} // namespace gen
+#if defined(__GNUC__) || defined(__clang__)
+#pragma GCC diagnostic pop
+#endif
+// gen_amalgamated begin source: gen/protos/perfetto/config/inode_file/inode_file_config.gen.cc
+// gen_amalgamated expanded: #include "perfetto/protozero/gen_field_helpers.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/message.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/packed_repeated_fields.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/proto_decoder.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/scattered_heap_buffer.h"
+// DO NOT EDIT. Autogenerated by Perfetto cppgen_plugin
+#if defined(__GNUC__) || defined(__clang__)
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wfloat-equal"
+#endif
+// gen_amalgamated expanded: #include "protos/perfetto/config/inode_file/inode_file_config.gen.h"
+
+namespace perfetto {
+namespace protos {
+namespace gen {
-TriggerRule_HistogramTrigger::TriggerRule_HistogramTrigger() = default;
-TriggerRule_HistogramTrigger::~TriggerRule_HistogramTrigger() = default;
-TriggerRule_HistogramTrigger::TriggerRule_HistogramTrigger(const TriggerRule_HistogramTrigger&) = default;
-TriggerRule_HistogramTrigger& TriggerRule_HistogramTrigger::operator=(const TriggerRule_HistogramTrigger&) = default;
-TriggerRule_HistogramTrigger::TriggerRule_HistogramTrigger(TriggerRule_HistogramTrigger&&) noexcept = default;
-TriggerRule_HistogramTrigger& TriggerRule_HistogramTrigger::operator=(TriggerRule_HistogramTrigger&&) = default;
+InodeFileConfig::InodeFileConfig() = default;
+InodeFileConfig::~InodeFileConfig() = default;
+InodeFileConfig::InodeFileConfig(const InodeFileConfig&) = default;
+InodeFileConfig& InodeFileConfig::operator=(const InodeFileConfig&) = default;
+InodeFileConfig::InodeFileConfig(InodeFileConfig&&) noexcept = default;
+InodeFileConfig& InodeFileConfig::operator=(InodeFileConfig&&) = default;
-bool TriggerRule_HistogramTrigger::operator==(const TriggerRule_HistogramTrigger& other) const {
+bool InodeFileConfig::operator==(const InodeFileConfig& other) const {
return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
- && ::protozero::internal::gen_helpers::EqualsField(histogram_name_, other.histogram_name_)
- && ::protozero::internal::gen_helpers::EqualsField(min_value_, other.min_value_)
- && ::protozero::internal::gen_helpers::EqualsField(max_value_, other.max_value_);
+ && ::protozero::internal::gen_helpers::EqualsField(scan_interval_ms_, other.scan_interval_ms_)
+ && ::protozero::internal::gen_helpers::EqualsField(scan_delay_ms_, other.scan_delay_ms_)
+ && ::protozero::internal::gen_helpers::EqualsField(scan_batch_size_, other.scan_batch_size_)
+ && ::protozero::internal::gen_helpers::EqualsField(do_not_scan_, other.do_not_scan_)
+ && ::protozero::internal::gen_helpers::EqualsField(scan_mount_points_, other.scan_mount_points_)
+ && ::protozero::internal::gen_helpers::EqualsField(mount_point_mapping_, other.mount_point_mapping_);
}
-bool TriggerRule_HistogramTrigger::ParseFromArray(const void* raw, size_t size) {
+int InodeFileConfig::mount_point_mapping_size() const { return static_cast<int>(mount_point_mapping_.size()); }
+void InodeFileConfig::clear_mount_point_mapping() { mount_point_mapping_.clear(); }
+InodeFileConfig_MountPointMappingEntry* InodeFileConfig::add_mount_point_mapping() { mount_point_mapping_.emplace_back(); return &mount_point_mapping_.back(); }
+bool InodeFileConfig::ParseFromArray(const void* raw, size_t size) {
+ scan_mount_points_.clear();
+ mount_point_mapping_.clear();
unknown_fields_.clear();
bool packed_error = false;
@@ -28108,14 +27439,25 @@ bool TriggerRule_HistogramTrigger::ParseFromArray(const void* raw, size_t size)
_has_field_.set(field.id());
}
switch (field.id()) {
- case 1 /* histogram_name */:
- ::protozero::internal::gen_helpers::DeserializeString(field, &histogram_name_);
+ case 1 /* scan_interval_ms */:
+ field.get(&scan_interval_ms_);
break;
- case 2 /* min_value */:
- field.get(&min_value_);
+ case 2 /* scan_delay_ms */:
+ field.get(&scan_delay_ms_);
break;
- case 3 /* max_value */:
- field.get(&max_value_);
+ case 3 /* scan_batch_size */:
+ field.get(&scan_batch_size_);
+ break;
+ case 4 /* do_not_scan */:
+ field.get(&do_not_scan_);
+ break;
+ case 5 /* scan_mount_points */:
+ scan_mount_points_.emplace_back();
+ ::protozero::internal::gen_helpers::DeserializeString(field, &scan_mount_points_.back());
+ break;
+ case 6 /* mount_point_mapping */:
+ mount_point_mapping_.emplace_back();
+ mount_point_mapping_.back().ParseFromArray(field.data(), field.size());
break;
default:
field.SerializeAndAppendTo(&unknown_fields_);
@@ -28125,55 +27467,68 @@ bool TriggerRule_HistogramTrigger::ParseFromArray(const void* raw, size_t size)
return !packed_error && !dec.bytes_left();
}
-std::string TriggerRule_HistogramTrigger::SerializeAsString() const {
+std::string InodeFileConfig::SerializeAsString() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsString();
}
-std::vector<uint8_t> TriggerRule_HistogramTrigger::SerializeAsArray() const {
+std::vector<uint8_t> InodeFileConfig::SerializeAsArray() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsArray();
}
-void TriggerRule_HistogramTrigger::Serialize(::protozero::Message* msg) const {
- // Field 1: histogram_name
+void InodeFileConfig::Serialize(::protozero::Message* msg) const {
+ // Field 1: scan_interval_ms
if (_has_field_[1]) {
- ::protozero::internal::gen_helpers::SerializeString(1, histogram_name_, msg);
+ ::protozero::internal::gen_helpers::SerializeVarInt(1, scan_interval_ms_, msg);
}
- // Field 2: min_value
+ // Field 2: scan_delay_ms
if (_has_field_[2]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(2, min_value_, msg);
+ ::protozero::internal::gen_helpers::SerializeVarInt(2, scan_delay_ms_, msg);
}
- // Field 3: max_value
+ // Field 3: scan_batch_size
if (_has_field_[3]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(3, max_value_, msg);
+ ::protozero::internal::gen_helpers::SerializeVarInt(3, scan_batch_size_, msg);
+ }
+
+ // Field 4: do_not_scan
+ if (_has_field_[4]) {
+ ::protozero::internal::gen_helpers::SerializeTinyVarInt(4, do_not_scan_, msg);
+ }
+
+ // Field 5: scan_mount_points
+ for (auto& it : scan_mount_points_) {
+ ::protozero::internal::gen_helpers::SerializeString(5, it, msg);
+ }
+
+ // Field 6: mount_point_mapping
+ for (auto& it : mount_point_mapping_) {
+ it.Serialize(msg->BeginNestedMessage<::protozero::Message>(6));
}
protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
}
-ChromeFieldTracingConfig::ChromeFieldTracingConfig() = default;
-ChromeFieldTracingConfig::~ChromeFieldTracingConfig() = default;
-ChromeFieldTracingConfig::ChromeFieldTracingConfig(const ChromeFieldTracingConfig&) = default;
-ChromeFieldTracingConfig& ChromeFieldTracingConfig::operator=(const ChromeFieldTracingConfig&) = default;
-ChromeFieldTracingConfig::ChromeFieldTracingConfig(ChromeFieldTracingConfig&&) noexcept = default;
-ChromeFieldTracingConfig& ChromeFieldTracingConfig::operator=(ChromeFieldTracingConfig&&) = default;
+InodeFileConfig_MountPointMappingEntry::InodeFileConfig_MountPointMappingEntry() = default;
+InodeFileConfig_MountPointMappingEntry::~InodeFileConfig_MountPointMappingEntry() = default;
+InodeFileConfig_MountPointMappingEntry::InodeFileConfig_MountPointMappingEntry(const InodeFileConfig_MountPointMappingEntry&) = default;
+InodeFileConfig_MountPointMappingEntry& InodeFileConfig_MountPointMappingEntry::operator=(const InodeFileConfig_MountPointMappingEntry&) = default;
+InodeFileConfig_MountPointMappingEntry::InodeFileConfig_MountPointMappingEntry(InodeFileConfig_MountPointMappingEntry&&) noexcept = default;
+InodeFileConfig_MountPointMappingEntry& InodeFileConfig_MountPointMappingEntry::operator=(InodeFileConfig_MountPointMappingEntry&&) = default;
-bool ChromeFieldTracingConfig::operator==(const ChromeFieldTracingConfig& other) const {
+bool InodeFileConfig_MountPointMappingEntry::operator==(const InodeFileConfig_MountPointMappingEntry& other) const {
return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
- && ::protozero::internal::gen_helpers::EqualsField(scenarios_, other.scenarios_);
+ && ::protozero::internal::gen_helpers::EqualsField(mountpoint_, other.mountpoint_)
+ && ::protozero::internal::gen_helpers::EqualsField(scan_roots_, other.scan_roots_);
}
-int ChromeFieldTracingConfig::scenarios_size() const { return static_cast<int>(scenarios_.size()); }
-void ChromeFieldTracingConfig::clear_scenarios() { scenarios_.clear(); }
-ScenarioConfig* ChromeFieldTracingConfig::add_scenarios() { scenarios_.emplace_back(); return &scenarios_.back(); }
-bool ChromeFieldTracingConfig::ParseFromArray(const void* raw, size_t size) {
- scenarios_.clear();
+bool InodeFileConfig_MountPointMappingEntry::ParseFromArray(const void* raw, size_t size) {
+ scan_roots_.clear();
unknown_fields_.clear();
bool packed_error = false;
@@ -28183,9 +27538,12 @@ bool ChromeFieldTracingConfig::ParseFromArray(const void* raw, size_t size) {
_has_field_.set(field.id());
}
switch (field.id()) {
- case 1 /* scenarios */:
- scenarios_.emplace_back();
- scenarios_.back().ParseFromArray(field.data(), field.size());
+ case 1 /* mountpoint */:
+ ::protozero::internal::gen_helpers::DeserializeString(field, &mountpoint_);
+ break;
+ case 2 /* scan_roots */:
+ scan_roots_.emplace_back();
+ ::protozero::internal::gen_helpers::DeserializeString(field, &scan_roots_.back());
break;
default:
field.SerializeAndAppendTo(&unknown_fields_);
@@ -28195,69 +27553,69 @@ bool ChromeFieldTracingConfig::ParseFromArray(const void* raw, size_t size) {
return !packed_error && !dec.bytes_left();
}
-std::string ChromeFieldTracingConfig::SerializeAsString() const {
+std::string InodeFileConfig_MountPointMappingEntry::SerializeAsString() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsString();
}
-std::vector<uint8_t> ChromeFieldTracingConfig::SerializeAsArray() const {
+std::vector<uint8_t> InodeFileConfig_MountPointMappingEntry::SerializeAsArray() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsArray();
}
-void ChromeFieldTracingConfig::Serialize(::protozero::Message* msg) const {
- // Field 1: scenarios
- for (auto& it : scenarios_) {
- it.Serialize(msg->BeginNestedMessage<::protozero::Message>(1));
+void InodeFileConfig_MountPointMappingEntry::Serialize(::protozero::Message* msg) const {
+ // Field 1: mountpoint
+ if (_has_field_[1]) {
+ ::protozero::internal::gen_helpers::SerializeString(1, mountpoint_, msg);
+ }
+
+ // Field 2: scan_roots
+ for (auto& it : scan_roots_) {
+ ::protozero::internal::gen_helpers::SerializeString(2, it, msg);
}
protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
}
+} // namespace perfetto
+} // namespace protos
+} // namespace gen
+#if defined(__GNUC__) || defined(__clang__)
+#pragma GCC diagnostic pop
+#endif
+// gen_amalgamated begin source: gen/protos/perfetto/config/interceptors/console_config.gen.cc
+// gen_amalgamated expanded: #include "perfetto/protozero/gen_field_helpers.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/message.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/packed_repeated_fields.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/proto_decoder.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/scattered_heap_buffer.h"
+// DO NOT EDIT. Autogenerated by Perfetto cppgen_plugin
+#if defined(__GNUC__) || defined(__clang__)
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wfloat-equal"
+#endif
+// gen_amalgamated expanded: #include "protos/perfetto/config/interceptors/console_config.gen.h"
-ScenarioConfig::ScenarioConfig() = default;
-ScenarioConfig::~ScenarioConfig() = default;
-ScenarioConfig::ScenarioConfig(const ScenarioConfig&) = default;
-ScenarioConfig& ScenarioConfig::operator=(const ScenarioConfig&) = default;
-ScenarioConfig::ScenarioConfig(ScenarioConfig&&) noexcept = default;
-ScenarioConfig& ScenarioConfig::operator=(ScenarioConfig&&) = default;
+namespace perfetto {
+namespace protos {
+namespace gen {
-bool ScenarioConfig::operator==(const ScenarioConfig& other) const {
- return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
- && ::protozero::internal::gen_helpers::EqualsField(scenario_name_, other.scenario_name_)
- && ::protozero::internal::gen_helpers::EqualsField(scenario_description_, other.scenario_description_)
- && ::protozero::internal::gen_helpers::EqualsField(start_rules_, other.start_rules_)
- && ::protozero::internal::gen_helpers::EqualsField(stop_rules_, other.stop_rules_)
- && ::protozero::internal::gen_helpers::EqualsField(upload_rules_, other.upload_rules_)
- && ::protozero::internal::gen_helpers::EqualsField(setup_rules_, other.setup_rules_)
- && ::protozero::internal::gen_helpers::EqualsField(trace_config_, other.trace_config_)
- && ::protozero::internal::gen_helpers::EqualsField(nested_scenarios_, other.nested_scenarios_)
- && ::protozero::internal::gen_helpers::EqualsField(use_system_backend_, other.use_system_backend_);
-}
+ConsoleConfig::ConsoleConfig() = default;
+ConsoleConfig::~ConsoleConfig() = default;
+ConsoleConfig::ConsoleConfig(const ConsoleConfig&) = default;
+ConsoleConfig& ConsoleConfig::operator=(const ConsoleConfig&) = default;
+ConsoleConfig::ConsoleConfig(ConsoleConfig&&) noexcept = default;
+ConsoleConfig& ConsoleConfig::operator=(ConsoleConfig&&) = default;
-int ScenarioConfig::start_rules_size() const { return static_cast<int>(start_rules_.size()); }
-void ScenarioConfig::clear_start_rules() { start_rules_.clear(); }
-TriggerRule* ScenarioConfig::add_start_rules() { start_rules_.emplace_back(); return &start_rules_.back(); }
-int ScenarioConfig::stop_rules_size() const { return static_cast<int>(stop_rules_.size()); }
-void ScenarioConfig::clear_stop_rules() { stop_rules_.clear(); }
-TriggerRule* ScenarioConfig::add_stop_rules() { stop_rules_.emplace_back(); return &stop_rules_.back(); }
-int ScenarioConfig::upload_rules_size() const { return static_cast<int>(upload_rules_.size()); }
-void ScenarioConfig::clear_upload_rules() { upload_rules_.clear(); }
-TriggerRule* ScenarioConfig::add_upload_rules() { upload_rules_.emplace_back(); return &upload_rules_.back(); }
-int ScenarioConfig::setup_rules_size() const { return static_cast<int>(setup_rules_.size()); }
-void ScenarioConfig::clear_setup_rules() { setup_rules_.clear(); }
-TriggerRule* ScenarioConfig::add_setup_rules() { setup_rules_.emplace_back(); return &setup_rules_.back(); }
-int ScenarioConfig::nested_scenarios_size() const { return static_cast<int>(nested_scenarios_.size()); }
-void ScenarioConfig::clear_nested_scenarios() { nested_scenarios_.clear(); }
-NestedScenarioConfig* ScenarioConfig::add_nested_scenarios() { nested_scenarios_.emplace_back(); return &nested_scenarios_.back(); }
-bool ScenarioConfig::ParseFromArray(const void* raw, size_t size) {
- start_rules_.clear();
- stop_rules_.clear();
- upload_rules_.clear();
- setup_rules_.clear();
- nested_scenarios_.clear();
+bool ConsoleConfig::operator==(const ConsoleConfig& other) const {
+ return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
+ && ::protozero::internal::gen_helpers::EqualsField(output_, other.output_)
+ && ::protozero::internal::gen_helpers::EqualsField(enable_colors_, other.enable_colors_);
+}
+
+bool ConsoleConfig::ParseFromArray(const void* raw, size_t size) {
unknown_fields_.clear();
bool packed_error = false;
@@ -28267,37 +27625,11 @@ bool ScenarioConfig::ParseFromArray(const void* raw, size_t size) {
_has_field_.set(field.id());
}
switch (field.id()) {
- case 1 /* scenario_name */:
- ::protozero::internal::gen_helpers::DeserializeString(field, &scenario_name_);
- break;
- case 9 /* scenario_description */:
- ::protozero::internal::gen_helpers::DeserializeString(field, &scenario_description_);
- break;
- case 2 /* start_rules */:
- start_rules_.emplace_back();
- start_rules_.back().ParseFromArray(field.data(), field.size());
- break;
- case 3 /* stop_rules */:
- stop_rules_.emplace_back();
- stop_rules_.back().ParseFromArray(field.data(), field.size());
- break;
- case 4 /* upload_rules */:
- upload_rules_.emplace_back();
- upload_rules_.back().ParseFromArray(field.data(), field.size());
- break;
- case 5 /* setup_rules */:
- setup_rules_.emplace_back();
- setup_rules_.back().ParseFromArray(field.data(), field.size());
- break;
- case 6 /* trace_config */:
- (*trace_config_).ParseFromArray(field.data(), field.size());
- break;
- case 7 /* nested_scenarios */:
- nested_scenarios_.emplace_back();
- nested_scenarios_.back().ParseFromArray(field.data(), field.size());
+ case 1 /* output */:
+ field.get(&output_);
break;
- case 8 /* use_system_backend */:
- field.get(&use_system_backend_);
+ case 2 /* enable_colors */:
+ field.get(&enable_colors_);
break;
default:
field.SerializeAndAppendTo(&unknown_fields_);
@@ -28307,96 +27639,72 @@ bool ScenarioConfig::ParseFromArray(const void* raw, size_t size) {
return !packed_error && !dec.bytes_left();
}
-std::string ScenarioConfig::SerializeAsString() const {
+std::string ConsoleConfig::SerializeAsString() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsString();
}
-std::vector<uint8_t> ScenarioConfig::SerializeAsArray() const {
+std::vector<uint8_t> ConsoleConfig::SerializeAsArray() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsArray();
}
-void ScenarioConfig::Serialize(::protozero::Message* msg) const {
- // Field 1: scenario_name
+void ConsoleConfig::Serialize(::protozero::Message* msg) const {
+ // Field 1: output
if (_has_field_[1]) {
- ::protozero::internal::gen_helpers::SerializeString(1, scenario_name_, msg);
- }
-
- // Field 9: scenario_description
- if (_has_field_[9]) {
- ::protozero::internal::gen_helpers::SerializeString(9, scenario_description_, msg);
- }
-
- // Field 2: start_rules
- for (auto& it : start_rules_) {
- it.Serialize(msg->BeginNestedMessage<::protozero::Message>(2));
- }
-
- // Field 3: stop_rules
- for (auto& it : stop_rules_) {
- it.Serialize(msg->BeginNestedMessage<::protozero::Message>(3));
- }
-
- // Field 4: upload_rules
- for (auto& it : upload_rules_) {
- it.Serialize(msg->BeginNestedMessage<::protozero::Message>(4));
- }
-
- // Field 5: setup_rules
- for (auto& it : setup_rules_) {
- it.Serialize(msg->BeginNestedMessage<::protozero::Message>(5));
- }
-
- // Field 6: trace_config
- if (_has_field_[6]) {
- (*trace_config_).Serialize(msg->BeginNestedMessage<::protozero::Message>(6));
- }
-
- // Field 7: nested_scenarios
- for (auto& it : nested_scenarios_) {
- it.Serialize(msg->BeginNestedMessage<::protozero::Message>(7));
+ ::protozero::internal::gen_helpers::SerializeVarInt(1, output_, msg);
}
- // Field 8: use_system_backend
- if (_has_field_[8]) {
- ::protozero::internal::gen_helpers::SerializeTinyVarInt(8, use_system_backend_, msg);
+ // Field 2: enable_colors
+ if (_has_field_[2]) {
+ ::protozero::internal::gen_helpers::SerializeTinyVarInt(2, enable_colors_, msg);
}
protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
}
+} // namespace perfetto
+} // namespace protos
+} // namespace gen
+#if defined(__GNUC__) || defined(__clang__)
+#pragma GCC diagnostic pop
+#endif
+// gen_amalgamated begin source: gen/protos/perfetto/config/linux/journald_config.gen.cc
+// gen_amalgamated expanded: #include "perfetto/protozero/gen_field_helpers.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/message.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/packed_repeated_fields.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/proto_decoder.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/scattered_heap_buffer.h"
+// DO NOT EDIT. Autogenerated by Perfetto cppgen_plugin
+#if defined(__GNUC__) || defined(__clang__)
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wfloat-equal"
+#endif
+// gen_amalgamated expanded: #include "protos/perfetto/config/linux/journald_config.gen.h"
+
+namespace perfetto {
+namespace protos {
+namespace gen {
-NestedScenarioConfig::NestedScenarioConfig() = default;
-NestedScenarioConfig::~NestedScenarioConfig() = default;
-NestedScenarioConfig::NestedScenarioConfig(const NestedScenarioConfig&) = default;
-NestedScenarioConfig& NestedScenarioConfig::operator=(const NestedScenarioConfig&) = default;
-NestedScenarioConfig::NestedScenarioConfig(NestedScenarioConfig&&) noexcept = default;
-NestedScenarioConfig& NestedScenarioConfig::operator=(NestedScenarioConfig&&) = default;
+SystemdJournaldConfig::SystemdJournaldConfig() = default;
+SystemdJournaldConfig::~SystemdJournaldConfig() = default;
+SystemdJournaldConfig::SystemdJournaldConfig(const SystemdJournaldConfig&) = default;
+SystemdJournaldConfig& SystemdJournaldConfig::operator=(const SystemdJournaldConfig&) = default;
+SystemdJournaldConfig::SystemdJournaldConfig(SystemdJournaldConfig&&) noexcept = default;
+SystemdJournaldConfig& SystemdJournaldConfig::operator=(SystemdJournaldConfig&&) = default;
-bool NestedScenarioConfig::operator==(const NestedScenarioConfig& other) const {
+bool SystemdJournaldConfig::operator==(const SystemdJournaldConfig& other) const {
return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
- && ::protozero::internal::gen_helpers::EqualsField(scenario_name_, other.scenario_name_)
- && ::protozero::internal::gen_helpers::EqualsField(start_rules_, other.start_rules_)
- && ::protozero::internal::gen_helpers::EqualsField(stop_rules_, other.stop_rules_)
- && ::protozero::internal::gen_helpers::EqualsField(upload_rules_, other.upload_rules_);
+ && ::protozero::internal::gen_helpers::EqualsField(min_prio_, other.min_prio_)
+ && ::protozero::internal::gen_helpers::EqualsField(filter_identifiers_, other.filter_identifiers_)
+ && ::protozero::internal::gen_helpers::EqualsField(filter_units_, other.filter_units_);
}
-int NestedScenarioConfig::start_rules_size() const { return static_cast<int>(start_rules_.size()); }
-void NestedScenarioConfig::clear_start_rules() { start_rules_.clear(); }
-TriggerRule* NestedScenarioConfig::add_start_rules() { start_rules_.emplace_back(); return &start_rules_.back(); }
-int NestedScenarioConfig::stop_rules_size() const { return static_cast<int>(stop_rules_.size()); }
-void NestedScenarioConfig::clear_stop_rules() { stop_rules_.clear(); }
-TriggerRule* NestedScenarioConfig::add_stop_rules() { stop_rules_.emplace_back(); return &stop_rules_.back(); }
-int NestedScenarioConfig::upload_rules_size() const { return static_cast<int>(upload_rules_.size()); }
-void NestedScenarioConfig::clear_upload_rules() { upload_rules_.clear(); }
-TriggerRule* NestedScenarioConfig::add_upload_rules() { upload_rules_.emplace_back(); return &upload_rules_.back(); }
-bool NestedScenarioConfig::ParseFromArray(const void* raw, size_t size) {
- start_rules_.clear();
- stop_rules_.clear();
- upload_rules_.clear();
+bool SystemdJournaldConfig::ParseFromArray(const void* raw, size_t size) {
+ filter_identifiers_.clear();
+ filter_units_.clear();
unknown_fields_.clear();
bool packed_error = false;
@@ -28406,20 +27714,16 @@ bool NestedScenarioConfig::ParseFromArray(const void* raw, size_t size) {
_has_field_.set(field.id());
}
switch (field.id()) {
- case 1 /* scenario_name */:
- ::protozero::internal::gen_helpers::DeserializeString(field, &scenario_name_);
- break;
- case 2 /* start_rules */:
- start_rules_.emplace_back();
- start_rules_.back().ParseFromArray(field.data(), field.size());
+ case 1 /* min_prio */:
+ field.get(&min_prio_);
break;
- case 3 /* stop_rules */:
- stop_rules_.emplace_back();
- stop_rules_.back().ParseFromArray(field.data(), field.size());
+ case 2 /* filter_identifiers */:
+ filter_identifiers_.emplace_back();
+ ::protozero::internal::gen_helpers::DeserializeString(field, &filter_identifiers_.back());
break;
- case 4 /* upload_rules */:
- upload_rules_.emplace_back();
- upload_rules_.back().ParseFromArray(field.data(), field.size());
+ case 3 /* filter_units */:
+ filter_units_.emplace_back();
+ ::protozero::internal::gen_helpers::DeserializeString(field, &filter_units_.back());
break;
default:
field.SerializeAndAppendTo(&unknown_fields_);
@@ -28429,37 +27733,32 @@ bool NestedScenarioConfig::ParseFromArray(const void* raw, size_t size) {
return !packed_error && !dec.bytes_left();
}
-std::string NestedScenarioConfig::SerializeAsString() const {
+std::string SystemdJournaldConfig::SerializeAsString() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsString();
}
-std::vector<uint8_t> NestedScenarioConfig::SerializeAsArray() const {
+std::vector<uint8_t> SystemdJournaldConfig::SerializeAsArray() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsArray();
}
-void NestedScenarioConfig::Serialize(::protozero::Message* msg) const {
- // Field 1: scenario_name
+void SystemdJournaldConfig::Serialize(::protozero::Message* msg) const {
+ // Field 1: min_prio
if (_has_field_[1]) {
- ::protozero::internal::gen_helpers::SerializeString(1, scenario_name_, msg);
- }
-
- // Field 2: start_rules
- for (auto& it : start_rules_) {
- it.Serialize(msg->BeginNestedMessage<::protozero::Message>(2));
+ ::protozero::internal::gen_helpers::SerializeVarInt(1, min_prio_, msg);
}
- // Field 3: stop_rules
- for (auto& it : stop_rules_) {
- it.Serialize(msg->BeginNestedMessage<::protozero::Message>(3));
+ // Field 2: filter_identifiers
+ for (auto& it : filter_identifiers_) {
+ ::protozero::internal::gen_helpers::SerializeString(2, it, msg);
}
- // Field 4: upload_rules
- for (auto& it : upload_rules_) {
- it.Serialize(msg->BeginNestedMessage<::protozero::Message>(4));
+ // Field 3: filter_units
+ for (auto& it : filter_units_) {
+ ::protozero::internal::gen_helpers::SerializeString(3, it, msg);
}
protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
@@ -28471,7 +27770,7 @@ void NestedScenarioConfig::Serialize(::protozero::Message* msg) const {
#if defined(__GNUC__) || defined(__clang__)
#pragma GCC diagnostic pop
#endif
-// gen_amalgamated begin source: gen/protos/perfetto/config/chrome/system_metrics.gen.cc
+// gen_amalgamated begin source: gen/protos/perfetto/config/power/android_power_config.gen.cc
// gen_amalgamated expanded: #include "perfetto/protozero/gen_field_helpers.h"
// gen_amalgamated expanded: #include "perfetto/protozero/message.h"
// gen_amalgamated expanded: #include "perfetto/protozero/packed_repeated_fields.h"
@@ -28482,25 +27781,30 @@ void NestedScenarioConfig::Serialize(::protozero::Message* msg) const {
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wfloat-equal"
#endif
-// gen_amalgamated expanded: #include "protos/perfetto/config/chrome/system_metrics.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/config/power/android_power_config.gen.h"
namespace perfetto {
namespace protos {
namespace gen {
-ChromiumSystemMetricsConfig::ChromiumSystemMetricsConfig() = default;
-ChromiumSystemMetricsConfig::~ChromiumSystemMetricsConfig() = default;
-ChromiumSystemMetricsConfig::ChromiumSystemMetricsConfig(const ChromiumSystemMetricsConfig&) = default;
-ChromiumSystemMetricsConfig& ChromiumSystemMetricsConfig::operator=(const ChromiumSystemMetricsConfig&) = default;
-ChromiumSystemMetricsConfig::ChromiumSystemMetricsConfig(ChromiumSystemMetricsConfig&&) noexcept = default;
-ChromiumSystemMetricsConfig& ChromiumSystemMetricsConfig::operator=(ChromiumSystemMetricsConfig&&) = default;
+AndroidPowerConfig::AndroidPowerConfig() = default;
+AndroidPowerConfig::~AndroidPowerConfig() = default;
+AndroidPowerConfig::AndroidPowerConfig(const AndroidPowerConfig&) = default;
+AndroidPowerConfig& AndroidPowerConfig::operator=(const AndroidPowerConfig&) = default;
+AndroidPowerConfig::AndroidPowerConfig(AndroidPowerConfig&&) noexcept = default;
+AndroidPowerConfig& AndroidPowerConfig::operator=(AndroidPowerConfig&&) = default;
-bool ChromiumSystemMetricsConfig::operator==(const ChromiumSystemMetricsConfig& other) const {
+bool AndroidPowerConfig::operator==(const AndroidPowerConfig& other) const {
return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
- && ::protozero::internal::gen_helpers::EqualsField(sampling_interval_ms_, other.sampling_interval_ms_);
+ && ::protozero::internal::gen_helpers::EqualsField(battery_poll_ms_, other.battery_poll_ms_)
+ && ::protozero::internal::gen_helpers::EqualsField(battery_counters_, other.battery_counters_)
+ && ::protozero::internal::gen_helpers::EqualsField(collect_power_rails_, other.collect_power_rails_)
+ && ::protozero::internal::gen_helpers::EqualsField(collect_energy_estimation_breakdown_, other.collect_energy_estimation_breakdown_)
+ && ::protozero::internal::gen_helpers::EqualsField(collect_entity_state_residency_, other.collect_entity_state_residency_);
}
-bool ChromiumSystemMetricsConfig::ParseFromArray(const void* raw, size_t size) {
+bool AndroidPowerConfig::ParseFromArray(const void* raw, size_t size) {
+ battery_counters_.clear();
unknown_fields_.clear();
bool packed_error = false;
@@ -28510,8 +27814,21 @@ bool ChromiumSystemMetricsConfig::ParseFromArray(const void* raw, size_t size) {
_has_field_.set(field.id());
}
switch (field.id()) {
- case 1 /* sampling_interval_ms */:
- field.get(&sampling_interval_ms_);
+ case 1 /* battery_poll_ms */:
+ field.get(&battery_poll_ms_);
+ break;
+ case 2 /* battery_counters */:
+ battery_counters_.emplace_back();
+ field.get(&battery_counters_.back());
+ break;
+ case 3 /* collect_power_rails */:
+ field.get(&collect_power_rails_);
+ break;
+ case 4 /* collect_energy_estimation_breakdown */:
+ field.get(&collect_energy_estimation_breakdown_);
+ break;
+ case 5 /* collect_entity_state_residency */:
+ field.get(&collect_entity_state_residency_);
break;
default:
field.SerializeAndAppendTo(&unknown_fields_);
@@ -28521,22 +27838,42 @@ bool ChromiumSystemMetricsConfig::ParseFromArray(const void* raw, size_t size) {
return !packed_error && !dec.bytes_left();
}
-std::string ChromiumSystemMetricsConfig::SerializeAsString() const {
+std::string AndroidPowerConfig::SerializeAsString() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsString();
}
-std::vector<uint8_t> ChromiumSystemMetricsConfig::SerializeAsArray() const {
+std::vector<uint8_t> AndroidPowerConfig::SerializeAsArray() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsArray();
}
-void ChromiumSystemMetricsConfig::Serialize(::protozero::Message* msg) const {
- // Field 1: sampling_interval_ms
+void AndroidPowerConfig::Serialize(::protozero::Message* msg) const {
+ // Field 1: battery_poll_ms
if (_has_field_[1]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(1, sampling_interval_ms_, msg);
+ ::protozero::internal::gen_helpers::SerializeVarInt(1, battery_poll_ms_, msg);
+ }
+
+ // Field 2: battery_counters
+ for (auto& it : battery_counters_) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(2, it, msg);
+ }
+
+ // Field 3: collect_power_rails
+ if (_has_field_[3]) {
+ ::protozero::internal::gen_helpers::SerializeTinyVarInt(3, collect_power_rails_, msg);
+ }
+
+ // Field 4: collect_energy_estimation_breakdown
+ if (_has_field_[4]) {
+ ::protozero::internal::gen_helpers::SerializeTinyVarInt(4, collect_energy_estimation_breakdown_, msg);
+ }
+
+ // Field 5: collect_entity_state_residency
+ if (_has_field_[5]) {
+ ::protozero::internal::gen_helpers::SerializeTinyVarInt(5, collect_entity_state_residency_, msg);
}
protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
@@ -28548,7 +27885,7 @@ void ChromiumSystemMetricsConfig::Serialize(::protozero::Message* msg) const {
#if defined(__GNUC__) || defined(__clang__)
#pragma GCC diagnostic pop
#endif
-// gen_amalgamated begin source: gen/protos/perfetto/config/chrome/v8_config.gen.cc
+// gen_amalgamated begin source: gen/protos/perfetto/config/priority_boost/priority_boost_config.gen.cc
// gen_amalgamated expanded: #include "perfetto/protozero/gen_field_helpers.h"
// gen_amalgamated expanded: #include "perfetto/protozero/message.h"
// gen_amalgamated expanded: #include "perfetto/protozero/packed_repeated_fields.h"
@@ -28559,26 +27896,26 @@ void ChromiumSystemMetricsConfig::Serialize(::protozero::Message* msg) const {
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wfloat-equal"
#endif
-// gen_amalgamated expanded: #include "protos/perfetto/config/chrome/v8_config.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/config/priority_boost/priority_boost_config.gen.h"
namespace perfetto {
namespace protos {
namespace gen {
-V8Config::V8Config() = default;
-V8Config::~V8Config() = default;
-V8Config::V8Config(const V8Config&) = default;
-V8Config& V8Config::operator=(const V8Config&) = default;
-V8Config::V8Config(V8Config&&) noexcept = default;
-V8Config& V8Config::operator=(V8Config&&) = default;
+PriorityBoostConfig::PriorityBoostConfig() = default;
+PriorityBoostConfig::~PriorityBoostConfig() = default;
+PriorityBoostConfig::PriorityBoostConfig(const PriorityBoostConfig&) = default;
+PriorityBoostConfig& PriorityBoostConfig::operator=(const PriorityBoostConfig&) = default;
+PriorityBoostConfig::PriorityBoostConfig(PriorityBoostConfig&&) noexcept = default;
+PriorityBoostConfig& PriorityBoostConfig::operator=(PriorityBoostConfig&&) = default;
-bool V8Config::operator==(const V8Config& other) const {
+bool PriorityBoostConfig::operator==(const PriorityBoostConfig& other) const {
return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
- && ::protozero::internal::gen_helpers::EqualsField(log_script_sources_, other.log_script_sources_)
- && ::protozero::internal::gen_helpers::EqualsField(log_instructions_, other.log_instructions_);
+ && ::protozero::internal::gen_helpers::EqualsField(policy_, other.policy_)
+ && ::protozero::internal::gen_helpers::EqualsField(priority_, other.priority_);
}
-bool V8Config::ParseFromArray(const void* raw, size_t size) {
+bool PriorityBoostConfig::ParseFromArray(const void* raw, size_t size) {
unknown_fields_.clear();
bool packed_error = false;
@@ -28588,11 +27925,11 @@ bool V8Config::ParseFromArray(const void* raw, size_t size) {
_has_field_.set(field.id());
}
switch (field.id()) {
- case 1 /* log_script_sources */:
- field.get(&log_script_sources_);
+ case 1 /* policy */:
+ field.get(&policy_);
break;
- case 2 /* log_instructions */:
- field.get(&log_instructions_);
+ case 2 /* priority */:
+ field.get(&priority_);
break;
default:
field.SerializeAndAppendTo(&unknown_fields_);
@@ -28602,27 +27939,27 @@ bool V8Config::ParseFromArray(const void* raw, size_t size) {
return !packed_error && !dec.bytes_left();
}
-std::string V8Config::SerializeAsString() const {
+std::string PriorityBoostConfig::SerializeAsString() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsString();
}
-std::vector<uint8_t> V8Config::SerializeAsArray() const {
+std::vector<uint8_t> PriorityBoostConfig::SerializeAsArray() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsArray();
}
-void V8Config::Serialize(::protozero::Message* msg) const {
- // Field 1: log_script_sources
+void PriorityBoostConfig::Serialize(::protozero::Message* msg) const {
+ // Field 1: policy
if (_has_field_[1]) {
- ::protozero::internal::gen_helpers::SerializeTinyVarInt(1, log_script_sources_, msg);
+ ::protozero::internal::gen_helpers::SerializeVarInt(1, policy_, msg);
}
- // Field 2: log_instructions
+ // Field 2: priority
if (_has_field_[2]) {
- ::protozero::internal::gen_helpers::SerializeTinyVarInt(2, log_instructions_, msg);
+ ::protozero::internal::gen_helpers::SerializeVarInt(2, priority_, msg);
}
protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
@@ -28634,7 +27971,7 @@ void V8Config::Serialize(::protozero::Message* msg) const {
#if defined(__GNUC__) || defined(__clang__)
#pragma GCC diagnostic pop
#endif
-// gen_amalgamated begin source: gen/protos/perfetto/config/data_source_config.gen.cc
+// gen_amalgamated begin source: gen/protos/perfetto/config/process_stats/process_stats_config.gen.cc
// gen_amalgamated expanded: #include "perfetto/protozero/gen_field_helpers.h"
// gen_amalgamated expanded: #include "perfetto/protozero/message.h"
// gen_amalgamated expanded: #include "perfetto/protozero/packed_repeated_fields.h"
@@ -28645,88 +27982,36 @@ void V8Config::Serialize(::protozero::Message* msg) const {
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wfloat-equal"
#endif
-// gen_amalgamated expanded: #include "protos/perfetto/config/data_source_config.gen.h"
-// gen_amalgamated expanded: #include "protos/perfetto/config/system_info/system_info_config.gen.h"
-// gen_amalgamated expanded: #include "protos/perfetto/config/test_config.gen.h"
-// gen_amalgamated expanded: #include "protos/perfetto/config/priority_boost/priority_boost_config.gen.h"
-// gen_amalgamated expanded: #include "protos/perfetto/config/protovm/protovm_config.gen.h"
-// gen_amalgamated expanded: #include "protos/perfetto/config/interceptor_config.gen.h"
-// gen_amalgamated expanded: #include "protos/perfetto/config/interceptors/console_config.gen.h"
-// gen_amalgamated expanded: #include "protos/perfetto/config/chrome/chrome_config.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/config/process_stats/process_stats_config.gen.h"
namespace perfetto {
namespace protos {
namespace gen {
-DataSourceConfig::DataSourceConfig() = default;
-DataSourceConfig::~DataSourceConfig() = default;
-DataSourceConfig::DataSourceConfig(const DataSourceConfig&) = default;
-DataSourceConfig& DataSourceConfig::operator=(const DataSourceConfig&) = default;
-DataSourceConfig::DataSourceConfig(DataSourceConfig&&) noexcept = default;
-DataSourceConfig& DataSourceConfig::operator=(DataSourceConfig&&) = default;
+ProcessStatsConfig::ProcessStatsConfig() = default;
+ProcessStatsConfig::~ProcessStatsConfig() = default;
+ProcessStatsConfig::ProcessStatsConfig(const ProcessStatsConfig&) = default;
+ProcessStatsConfig& ProcessStatsConfig::operator=(const ProcessStatsConfig&) = default;
+ProcessStatsConfig::ProcessStatsConfig(ProcessStatsConfig&&) noexcept = default;
+ProcessStatsConfig& ProcessStatsConfig::operator=(ProcessStatsConfig&&) = default;
-bool DataSourceConfig::operator==(const DataSourceConfig& other) const {
+bool ProcessStatsConfig::operator==(const ProcessStatsConfig& other) const {
return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
- && ::protozero::internal::gen_helpers::EqualsField(name_, other.name_)
- && ::protozero::internal::gen_helpers::EqualsField(target_buffer_, other.target_buffer_)
- && ::protozero::internal::gen_helpers::EqualsField(target_buffer_name_, other.target_buffer_name_)
- && ::protozero::internal::gen_helpers::EqualsField(trace_duration_ms_, other.trace_duration_ms_)
- && ::protozero::internal::gen_helpers::EqualsField(prefer_suspend_clock_for_duration_, other.prefer_suspend_clock_for_duration_)
- && ::protozero::internal::gen_helpers::EqualsField(stop_timeout_ms_, other.stop_timeout_ms_)
- && ::protozero::internal::gen_helpers::EqualsField(enable_extra_guardrails_, other.enable_extra_guardrails_)
- && ::protozero::internal::gen_helpers::EqualsField(session_initiator_, other.session_initiator_)
- && ::protozero::internal::gen_helpers::EqualsField(tracing_session_id_, other.tracing_session_id_)
- && ::protozero::internal::gen_helpers::EqualsField(buffer_exhausted_policy_, other.buffer_exhausted_policy_)
- && ::protozero::internal::gen_helpers::EqualsField(priority_boost_, other.priority_boost_)
- && ::protozero::internal::gen_helpers::EqualsField(protovm_config_, other.protovm_config_)
- && ::protozero::internal::gen_helpers::EqualsField(ftrace_config_, other.ftrace_config_)
- && ::protozero::internal::gen_helpers::EqualsField(inode_file_config_, other.inode_file_config_)
- && ::protozero::internal::gen_helpers::EqualsField(process_stats_config_, other.process_stats_config_)
- && ::protozero::internal::gen_helpers::EqualsField(sys_stats_config_, other.sys_stats_config_)
- && ::protozero::internal::gen_helpers::EqualsField(heapprofd_config_, other.heapprofd_config_)
- && ::protozero::internal::gen_helpers::EqualsField(java_hprof_config_, other.java_hprof_config_)
- && ::protozero::internal::gen_helpers::EqualsField(android_power_config_, other.android_power_config_)
- && ::protozero::internal::gen_helpers::EqualsField(android_log_config_, other.android_log_config_)
- && ::protozero::internal::gen_helpers::EqualsField(gpu_counter_config_, other.gpu_counter_config_)
- && ::protozero::internal::gen_helpers::EqualsField(android_game_intervention_list_config_, other.android_game_intervention_list_config_)
- && ::protozero::internal::gen_helpers::EqualsField(packages_list_config_, other.packages_list_config_)
- && ::protozero::internal::gen_helpers::EqualsField(perf_event_config_, other.perf_event_config_)
- && ::protozero::internal::gen_helpers::EqualsField(vulkan_memory_config_, other.vulkan_memory_config_)
- && ::protozero::internal::gen_helpers::EqualsField(track_event_config_, other.track_event_config_)
- && ::protozero::internal::gen_helpers::EqualsField(android_polled_state_config_, other.android_polled_state_config_)
- && ::protozero::internal::gen_helpers::EqualsField(android_system_property_config_, other.android_system_property_config_)
- && ::protozero::internal::gen_helpers::EqualsField(statsd_tracing_config_, other.statsd_tracing_config_)
- && ::protozero::internal::gen_helpers::EqualsField(system_info_config_, other.system_info_config_)
- && ::protozero::internal::gen_helpers::EqualsField(frozen_ftrace_config_, other.frozen_ftrace_config_)
- && ::protozero::internal::gen_helpers::EqualsField(chrome_config_, other.chrome_config_)
- && ::protozero::internal::gen_helpers::EqualsField(v8_config_, other.v8_config_)
- && ::protozero::internal::gen_helpers::EqualsField(interceptor_config_, other.interceptor_config_)
- && ::protozero::internal::gen_helpers::EqualsField(network_packet_trace_config_, other.network_packet_trace_config_)
- && ::protozero::internal::gen_helpers::EqualsField(surfaceflinger_layers_config_, other.surfaceflinger_layers_config_)
- && ::protozero::internal::gen_helpers::EqualsField(surfaceflinger_transactions_config_, other.surfaceflinger_transactions_config_)
- && ::protozero::internal::gen_helpers::EqualsField(android_sdk_sysprop_guard_config_, other.android_sdk_sysprop_guard_config_)
- && ::protozero::internal::gen_helpers::EqualsField(etw_config_, other.etw_config_)
- && ::protozero::internal::gen_helpers::EqualsField(protolog_config_, other.protolog_config_)
- && ::protozero::internal::gen_helpers::EqualsField(android_input_event_config_, other.android_input_event_config_)
- && ::protozero::internal::gen_helpers::EqualsField(pixel_modem_config_, other.pixel_modem_config_)
- && ::protozero::internal::gen_helpers::EqualsField(windowmanager_config_, other.windowmanager_config_)
- && ::protozero::internal::gen_helpers::EqualsField(chromium_system_metrics_, other.chromium_system_metrics_)
- && ::protozero::internal::gen_helpers::EqualsField(kernel_wakelocks_config_, other.kernel_wakelocks_config_)
- && ::protozero::internal::gen_helpers::EqualsField(gpu_renderstages_config_, other.gpu_renderstages_config_)
- && ::protozero::internal::gen_helpers::EqualsField(chromium_histogram_samples_, other.chromium_histogram_samples_)
- && ::protozero::internal::gen_helpers::EqualsField(app_wakelocks_config_, other.app_wakelocks_config_)
- && ::protozero::internal::gen_helpers::EqualsField(cpu_per_uid_config_, other.cpu_per_uid_config_)
- && ::protozero::internal::gen_helpers::EqualsField(user_list_config_, other.user_list_config_)
- && ::protozero::internal::gen_helpers::EqualsField(inputmethod_config_, other.inputmethod_config_)
- && ::protozero::internal::gen_helpers::EqualsField(android_aflags_config_, other.android_aflags_config_)
- && ::protozero::internal::gen_helpers::EqualsField(journald_config_, other.journald_config_)
- && ::protozero::internal::gen_helpers::EqualsField(display_video_config_, other.display_video_config_)
- && ::protozero::internal::gen_helpers::EqualsField(qnx_config_, other.qnx_config_)
- && ::protozero::internal::gen_helpers::EqualsField(legacy_config_, other.legacy_config_)
- && ::protozero::internal::gen_helpers::EqualsField(for_testing_, other.for_testing_);
+ && ::protozero::internal::gen_helpers::EqualsField(quirks_, other.quirks_)
+ && ::protozero::internal::gen_helpers::EqualsField(scan_all_processes_on_start_, other.scan_all_processes_on_start_)
+ && ::protozero::internal::gen_helpers::EqualsField(record_thread_names_, other.record_thread_names_)
+ && ::protozero::internal::gen_helpers::EqualsField(proc_stats_poll_ms_, other.proc_stats_poll_ms_)
+ && ::protozero::internal::gen_helpers::EqualsField(proc_stats_cache_ttl_ms_, other.proc_stats_cache_ttl_ms_)
+ && ::protozero::internal::gen_helpers::EqualsField(scan_smaps_rollup_, other.scan_smaps_rollup_)
+ && ::protozero::internal::gen_helpers::EqualsField(record_process_age_, other.record_process_age_)
+ && ::protozero::internal::gen_helpers::EqualsField(record_process_runtime_, other.record_process_runtime_)
+ && ::protozero::internal::gen_helpers::EqualsField(record_process_dmabuf_rss_, other.record_process_dmabuf_rss_)
+ && ::protozero::internal::gen_helpers::EqualsField(resolve_process_fds_, other.resolve_process_fds_)
+ && ::protozero::internal::gen_helpers::EqualsField(skip_main_thread_message_, other.skip_main_thread_message_);
}
-bool DataSourceConfig::ParseFromArray(const void* raw, size_t size) {
+bool ProcessStatsConfig::ParseFromArray(const void* raw, size_t size) {
+ quirks_.clear();
unknown_fields_.clear();
bool packed_error = false;
@@ -28736,176 +28021,276 @@ bool DataSourceConfig::ParseFromArray(const void* raw, size_t size) {
_has_field_.set(field.id());
}
switch (field.id()) {
- case 1 /* name */:
- ::protozero::internal::gen_helpers::DeserializeString(field, &name_);
- break;
- case 2 /* target_buffer */:
- field.get(&target_buffer_);
- break;
- case 11 /* target_buffer_name */:
- ::protozero::internal::gen_helpers::DeserializeString(field, &target_buffer_name_);
- break;
- case 3 /* trace_duration_ms */:
- field.get(&trace_duration_ms_);
- break;
- case 122 /* prefer_suspend_clock_for_duration */:
- field.get(&prefer_suspend_clock_for_duration_);
- break;
- case 7 /* stop_timeout_ms */:
- field.get(&stop_timeout_ms_);
- break;
- case 6 /* enable_extra_guardrails */:
- field.get(&enable_extra_guardrails_);
- break;
- case 8 /* session_initiator */:
- field.get(&session_initiator_);
- break;
- case 4 /* tracing_session_id */:
- field.get(&tracing_session_id_);
- break;
- case 9 /* buffer_exhausted_policy */:
- field.get(&buffer_exhausted_policy_);
+ case 1 /* quirks */:
+ quirks_.emplace_back();
+ field.get(&quirks_.back());
break;
- case 10 /* priority_boost */:
- (*priority_boost_).ParseFromArray(field.data(), field.size());
+ case 2 /* scan_all_processes_on_start */:
+ field.get(&scan_all_processes_on_start_);
break;
- case 12 /* protovm_config */:
- (*protovm_config_).ParseFromArray(field.data(), field.size());
+ case 3 /* record_thread_names */:
+ field.get(&record_thread_names_);
break;
- case 100 /* ftrace_config */:
- ::protozero::internal::gen_helpers::DeserializeString(field, &ftrace_config_);
+ case 4 /* proc_stats_poll_ms */:
+ field.get(&proc_stats_poll_ms_);
break;
- case 102 /* inode_file_config */:
- ::protozero::internal::gen_helpers::DeserializeString(field, &inode_file_config_);
+ case 6 /* proc_stats_cache_ttl_ms */:
+ field.get(&proc_stats_cache_ttl_ms_);
break;
- case 103 /* process_stats_config */:
- ::protozero::internal::gen_helpers::DeserializeString(field, &process_stats_config_);
+ case 10 /* scan_smaps_rollup */:
+ field.get(&scan_smaps_rollup_);
break;
- case 104 /* sys_stats_config */:
- ::protozero::internal::gen_helpers::DeserializeString(field, &sys_stats_config_);
+ case 11 /* record_process_age */:
+ field.get(&record_process_age_);
break;
- case 105 /* heapprofd_config */:
- ::protozero::internal::gen_helpers::DeserializeString(field, &heapprofd_config_);
+ case 12 /* record_process_runtime */:
+ field.get(&record_process_runtime_);
break;
- case 110 /* java_hprof_config */:
- ::protozero::internal::gen_helpers::DeserializeString(field, &java_hprof_config_);
+ case 13 /* record_process_dmabuf_rss */:
+ field.get(&record_process_dmabuf_rss_);
break;
- case 106 /* android_power_config */:
- ::protozero::internal::gen_helpers::DeserializeString(field, &android_power_config_);
+ case 9 /* resolve_process_fds */:
+ field.get(&resolve_process_fds_);
break;
- case 107 /* android_log_config */:
- ::protozero::internal::gen_helpers::DeserializeString(field, &android_log_config_);
+ case 14 /* skip_main_thread_message */:
+ field.get(&skip_main_thread_message_);
break;
- case 108 /* gpu_counter_config */:
- ::protozero::internal::gen_helpers::DeserializeString(field, &gpu_counter_config_);
+ default:
+ field.SerializeAndAppendTo(&unknown_fields_);
break;
- case 116 /* android_game_intervention_list_config */:
- ::protozero::internal::gen_helpers::DeserializeString(field, &android_game_intervention_list_config_);
- break;
- case 109 /* packages_list_config */:
- ::protozero::internal::gen_helpers::DeserializeString(field, &packages_list_config_);
- break;
- case 111 /* perf_event_config */:
- ::protozero::internal::gen_helpers::DeserializeString(field, &perf_event_config_);
- break;
- case 112 /* vulkan_memory_config */:
- ::protozero::internal::gen_helpers::DeserializeString(field, &vulkan_memory_config_);
- break;
- case 113 /* track_event_config */:
- ::protozero::internal::gen_helpers::DeserializeString(field, &track_event_config_);
- break;
- case 114 /* android_polled_state_config */:
- ::protozero::internal::gen_helpers::DeserializeString(field, &android_polled_state_config_);
- break;
- case 118 /* android_system_property_config */:
- ::protozero::internal::gen_helpers::DeserializeString(field, &android_system_property_config_);
- break;
- case 117 /* statsd_tracing_config */:
- ::protozero::internal::gen_helpers::DeserializeString(field, &statsd_tracing_config_);
- break;
- case 119 /* system_info_config */:
- (*system_info_config_).ParseFromArray(field.data(), field.size());
- break;
- case 136 /* frozen_ftrace_config */:
- ::protozero::internal::gen_helpers::DeserializeString(field, &frozen_ftrace_config_);
- break;
- case 101 /* chrome_config */:
- (*chrome_config_).ParseFromArray(field.data(), field.size());
- break;
- case 127 /* v8_config */:
- ::protozero::internal::gen_helpers::DeserializeString(field, &v8_config_);
+ }
+ }
+ return !packed_error && !dec.bytes_left();
+}
+
+std::string ProcessStatsConfig::SerializeAsString() const {
+ ::protozero::internal::gen_helpers::MessageSerializer msg;
+ Serialize(msg.get());
+ return msg.SerializeAsString();
+}
+
+std::vector<uint8_t> ProcessStatsConfig::SerializeAsArray() const {
+ ::protozero::internal::gen_helpers::MessageSerializer msg;
+ Serialize(msg.get());
+ return msg.SerializeAsArray();
+}
+
+void ProcessStatsConfig::Serialize(::protozero::Message* msg) const {
+ // Field 1: quirks
+ for (auto& it : quirks_) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(1, it, msg);
+ }
+
+ // Field 2: scan_all_processes_on_start
+ if (_has_field_[2]) {
+ ::protozero::internal::gen_helpers::SerializeTinyVarInt(2, scan_all_processes_on_start_, msg);
+ }
+
+ // Field 3: record_thread_names
+ if (_has_field_[3]) {
+ ::protozero::internal::gen_helpers::SerializeTinyVarInt(3, record_thread_names_, msg);
+ }
+
+ // Field 4: proc_stats_poll_ms
+ if (_has_field_[4]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(4, proc_stats_poll_ms_, msg);
+ }
+
+ // Field 6: proc_stats_cache_ttl_ms
+ if (_has_field_[6]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(6, proc_stats_cache_ttl_ms_, msg);
+ }
+
+ // Field 10: scan_smaps_rollup
+ if (_has_field_[10]) {
+ ::protozero::internal::gen_helpers::SerializeTinyVarInt(10, scan_smaps_rollup_, msg);
+ }
+
+ // Field 11: record_process_age
+ if (_has_field_[11]) {
+ ::protozero::internal::gen_helpers::SerializeTinyVarInt(11, record_process_age_, msg);
+ }
+
+ // Field 12: record_process_runtime
+ if (_has_field_[12]) {
+ ::protozero::internal::gen_helpers::SerializeTinyVarInt(12, record_process_runtime_, msg);
+ }
+
+ // Field 13: record_process_dmabuf_rss
+ if (_has_field_[13]) {
+ ::protozero::internal::gen_helpers::SerializeTinyVarInt(13, record_process_dmabuf_rss_, msg);
+ }
+
+ // Field 9: resolve_process_fds
+ if (_has_field_[9]) {
+ ::protozero::internal::gen_helpers::SerializeTinyVarInt(9, resolve_process_fds_, msg);
+ }
+
+ // Field 14: skip_main_thread_message
+ if (_has_field_[14]) {
+ ::protozero::internal::gen_helpers::SerializeTinyVarInt(14, skip_main_thread_message_, msg);
+ }
+
+ protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
+}
+
+} // namespace perfetto
+} // namespace protos
+} // namespace gen
+#if defined(__GNUC__) || defined(__clang__)
+#pragma GCC diagnostic pop
+#endif
+// gen_amalgamated begin source: gen/protos/perfetto/config/profiling/heapprofd_config.gen.cc
+// gen_amalgamated expanded: #include "perfetto/protozero/gen_field_helpers.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/message.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/packed_repeated_fields.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/proto_decoder.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/scattered_heap_buffer.h"
+// DO NOT EDIT. Autogenerated by Perfetto cppgen_plugin
+#if defined(__GNUC__) || defined(__clang__)
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wfloat-equal"
+#endif
+// gen_amalgamated expanded: #include "protos/perfetto/config/profiling/heapprofd_config.gen.h"
+
+namespace perfetto {
+namespace protos {
+namespace gen {
+
+HeapprofdConfig::HeapprofdConfig() = default;
+HeapprofdConfig::~HeapprofdConfig() = default;
+HeapprofdConfig::HeapprofdConfig(const HeapprofdConfig&) = default;
+HeapprofdConfig& HeapprofdConfig::operator=(const HeapprofdConfig&) = default;
+HeapprofdConfig::HeapprofdConfig(HeapprofdConfig&&) noexcept = default;
+HeapprofdConfig& HeapprofdConfig::operator=(HeapprofdConfig&&) = default;
+
+bool HeapprofdConfig::operator==(const HeapprofdConfig& other) const {
+ return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
+ && ::protozero::internal::gen_helpers::EqualsField(sampling_interval_bytes_, other.sampling_interval_bytes_)
+ && ::protozero::internal::gen_helpers::EqualsField(adaptive_sampling_shmem_threshold_, other.adaptive_sampling_shmem_threshold_)
+ && ::protozero::internal::gen_helpers::EqualsField(adaptive_sampling_max_sampling_interval_bytes_, other.adaptive_sampling_max_sampling_interval_bytes_)
+ && ::protozero::internal::gen_helpers::EqualsField(process_cmdline_, other.process_cmdline_)
+ && ::protozero::internal::gen_helpers::EqualsField(pid_, other.pid_)
+ && ::protozero::internal::gen_helpers::EqualsField(target_installed_by_, other.target_installed_by_)
+ && ::protozero::internal::gen_helpers::EqualsField(heaps_, other.heaps_)
+ && ::protozero::internal::gen_helpers::EqualsField(exclude_heaps_, other.exclude_heaps_)
+ && ::protozero::internal::gen_helpers::EqualsField(stream_allocations_, other.stream_allocations_)
+ && ::protozero::internal::gen_helpers::EqualsField(heap_sampling_intervals_, other.heap_sampling_intervals_)
+ && ::protozero::internal::gen_helpers::EqualsField(all_heaps_, other.all_heaps_)
+ && ::protozero::internal::gen_helpers::EqualsField(all_, other.all_)
+ && ::protozero::internal::gen_helpers::EqualsField(min_anonymous_memory_kb_, other.min_anonymous_memory_kb_)
+ && ::protozero::internal::gen_helpers::EqualsField(max_heapprofd_memory_kb_, other.max_heapprofd_memory_kb_)
+ && ::protozero::internal::gen_helpers::EqualsField(max_heapprofd_cpu_secs_, other.max_heapprofd_cpu_secs_)
+ && ::protozero::internal::gen_helpers::EqualsField(skip_symbol_prefix_, other.skip_symbol_prefix_)
+ && ::protozero::internal::gen_helpers::EqualsField(continuous_dump_config_, other.continuous_dump_config_)
+ && ::protozero::internal::gen_helpers::EqualsField(shmem_size_bytes_, other.shmem_size_bytes_)
+ && ::protozero::internal::gen_helpers::EqualsField(block_client_, other.block_client_)
+ && ::protozero::internal::gen_helpers::EqualsField(block_client_timeout_us_, other.block_client_timeout_us_)
+ && ::protozero::internal::gen_helpers::EqualsField(no_startup_, other.no_startup_)
+ && ::protozero::internal::gen_helpers::EqualsField(no_running_, other.no_running_)
+ && ::protozero::internal::gen_helpers::EqualsField(dump_at_max_, other.dump_at_max_)
+ && ::protozero::internal::gen_helpers::EqualsField(disable_fork_teardown_, other.disable_fork_teardown_)
+ && ::protozero::internal::gen_helpers::EqualsField(disable_vfork_detection_, other.disable_vfork_detection_);
+}
+
+bool HeapprofdConfig::ParseFromArray(const void* raw, size_t size) {
+ process_cmdline_.clear();
+ pid_.clear();
+ target_installed_by_.clear();
+ heaps_.clear();
+ exclude_heaps_.clear();
+ heap_sampling_intervals_.clear();
+ skip_symbol_prefix_.clear();
+ unknown_fields_.clear();
+ bool packed_error = false;
+
+ ::protozero::ProtoDecoder dec(raw, size);
+ for (auto field = dec.ReadField(); field.valid(); field = dec.ReadField()) {
+ if (field.id() < _has_field_.size()) {
+ _has_field_.set(field.id());
+ }
+ switch (field.id()) {
+ case 1 /* sampling_interval_bytes */:
+ field.get(&sampling_interval_bytes_);
break;
- case 115 /* interceptor_config */:
- (*interceptor_config_).ParseFromArray(field.data(), field.size());
+ case 24 /* adaptive_sampling_shmem_threshold */:
+ field.get(&adaptive_sampling_shmem_threshold_);
break;
- case 120 /* network_packet_trace_config */:
- ::protozero::internal::gen_helpers::DeserializeString(field, &network_packet_trace_config_);
+ case 25 /* adaptive_sampling_max_sampling_interval_bytes */:
+ field.get(&adaptive_sampling_max_sampling_interval_bytes_);
break;
- case 121 /* surfaceflinger_layers_config */:
- ::protozero::internal::gen_helpers::DeserializeString(field, &surfaceflinger_layers_config_);
+ case 2 /* process_cmdline */:
+ process_cmdline_.emplace_back();
+ ::protozero::internal::gen_helpers::DeserializeString(field, &process_cmdline_.back());
break;
- case 123 /* surfaceflinger_transactions_config */:
- ::protozero::internal::gen_helpers::DeserializeString(field, &surfaceflinger_transactions_config_);
+ case 4 /* pid */:
+ pid_.emplace_back();
+ field.get(&pid_.back());
break;
- case 124 /* android_sdk_sysprop_guard_config */:
- ::protozero::internal::gen_helpers::DeserializeString(field, &android_sdk_sysprop_guard_config_);
+ case 26 /* target_installed_by */:
+ target_installed_by_.emplace_back();
+ ::protozero::internal::gen_helpers::DeserializeString(field, &target_installed_by_.back());
break;
- case 125 /* etw_config */:
- ::protozero::internal::gen_helpers::DeserializeString(field, &etw_config_);
+ case 20 /* heaps */:
+ heaps_.emplace_back();
+ ::protozero::internal::gen_helpers::DeserializeString(field, &heaps_.back());
break;
- case 126 /* protolog_config */:
- ::protozero::internal::gen_helpers::DeserializeString(field, &protolog_config_);
+ case 27 /* exclude_heaps */:
+ exclude_heaps_.emplace_back();
+ ::protozero::internal::gen_helpers::DeserializeString(field, &exclude_heaps_.back());
break;
- case 128 /* android_input_event_config */:
- ::protozero::internal::gen_helpers::DeserializeString(field, &android_input_event_config_);
+ case 23 /* stream_allocations */:
+ field.get(&stream_allocations_);
break;
- case 129 /* pixel_modem_config */:
- ::protozero::internal::gen_helpers::DeserializeString(field, &pixel_modem_config_);
+ case 22 /* heap_sampling_intervals */:
+ heap_sampling_intervals_.emplace_back();
+ field.get(&heap_sampling_intervals_.back());
break;
- case 130 /* windowmanager_config */:
- ::protozero::internal::gen_helpers::DeserializeString(field, &windowmanager_config_);
+ case 21 /* all_heaps */:
+ field.get(&all_heaps_);
break;
- case 131 /* chromium_system_metrics */:
- ::protozero::internal::gen_helpers::DeserializeString(field, &chromium_system_metrics_);
+ case 5 /* all */:
+ field.get(&all_);
break;
- case 132 /* kernel_wakelocks_config */:
- ::protozero::internal::gen_helpers::DeserializeString(field, &kernel_wakelocks_config_);
+ case 15 /* min_anonymous_memory_kb */:
+ field.get(&min_anonymous_memory_kb_);
break;
- case 133 /* gpu_renderstages_config */:
- ::protozero::internal::gen_helpers::DeserializeString(field, &gpu_renderstages_config_);
+ case 16 /* max_heapprofd_memory_kb */:
+ field.get(&max_heapprofd_memory_kb_);
break;
- case 134 /* chromium_histogram_samples */:
- ::protozero::internal::gen_helpers::DeserializeString(field, &chromium_histogram_samples_);
+ case 17 /* max_heapprofd_cpu_secs */:
+ field.get(&max_heapprofd_cpu_secs_);
break;
- case 135 /* app_wakelocks_config */:
- ::protozero::internal::gen_helpers::DeserializeString(field, &app_wakelocks_config_);
+ case 7 /* skip_symbol_prefix */:
+ skip_symbol_prefix_.emplace_back();
+ ::protozero::internal::gen_helpers::DeserializeString(field, &skip_symbol_prefix_.back());
break;
- case 137 /* cpu_per_uid_config */:
- ::protozero::internal::gen_helpers::DeserializeString(field, &cpu_per_uid_config_);
+ case 6 /* continuous_dump_config */:
+ (*continuous_dump_config_).ParseFromArray(field.data(), field.size());
break;
- case 138 /* user_list_config */:
- ::protozero::internal::gen_helpers::DeserializeString(field, &user_list_config_);
+ case 8 /* shmem_size_bytes */:
+ field.get(&shmem_size_bytes_);
break;
- case 139 /* inputmethod_config */:
- ::protozero::internal::gen_helpers::DeserializeString(field, &inputmethod_config_);
+ case 9 /* block_client */:
+ field.get(&block_client_);
break;
- case 140 /* android_aflags_config */:
- ::protozero::internal::gen_helpers::DeserializeString(field, &android_aflags_config_);
+ case 14 /* block_client_timeout_us */:
+ field.get(&block_client_timeout_us_);
break;
- case 141 /* journald_config */:
- ::protozero::internal::gen_helpers::DeserializeString(field, &journald_config_);
+ case 10 /* no_startup */:
+ field.get(&no_startup_);
break;
- case 142 /* display_video_config */:
- ::protozero::internal::gen_helpers::DeserializeString(field, &display_video_config_);
+ case 11 /* no_running */:
+ field.get(&no_running_);
break;
- case 150 /* qnx_config */:
- ::protozero::internal::gen_helpers::DeserializeString(field, &qnx_config_);
+ case 13 /* dump_at_max */:
+ field.get(&dump_at_max_);
break;
- case 1000 /* legacy_config */:
- ::protozero::internal::gen_helpers::DeserializeString(field, &legacy_config_);
+ case 18 /* disable_fork_teardown */:
+ field.get(&disable_fork_teardown_);
break;
- case 1001 /* for_testing */:
- (*for_testing_).ParseFromArray(field.data(), field.size());
+ case 19 /* disable_vfork_detection */:
+ field.get(&disable_vfork_detection_);
break;
default:
field.SerializeAndAppendTo(&unknown_fields_);
@@ -28915,302 +28300,206 @@ bool DataSourceConfig::ParseFromArray(const void* raw, size_t size) {
return !packed_error && !dec.bytes_left();
}
-std::string DataSourceConfig::SerializeAsString() const {
+std::string HeapprofdConfig::SerializeAsString() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsString();
}
-std::vector<uint8_t> DataSourceConfig::SerializeAsArray() const {
+std::vector<uint8_t> HeapprofdConfig::SerializeAsArray() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsArray();
}
-void DataSourceConfig::Serialize(::protozero::Message* msg) const {
- // Field 1: name
+void HeapprofdConfig::Serialize(::protozero::Message* msg) const {
+ // Field 1: sampling_interval_bytes
if (_has_field_[1]) {
- ::protozero::internal::gen_helpers::SerializeString(1, name_, msg);
+ ::protozero::internal::gen_helpers::SerializeVarInt(1, sampling_interval_bytes_, msg);
}
- // Field 2: target_buffer
- if (_has_field_[2]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(2, target_buffer_, msg);
+ // Field 24: adaptive_sampling_shmem_threshold
+ if (_has_field_[24]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(24, adaptive_sampling_shmem_threshold_, msg);
}
- // Field 11: target_buffer_name
- if (_has_field_[11]) {
- ::protozero::internal::gen_helpers::SerializeString(11, target_buffer_name_, msg);
+ // Field 25: adaptive_sampling_max_sampling_interval_bytes
+ if (_has_field_[25]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(25, adaptive_sampling_max_sampling_interval_bytes_, msg);
}
- // Field 3: trace_duration_ms
- if (_has_field_[3]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(3, trace_duration_ms_, msg);
+ // Field 2: process_cmdline
+ for (auto& it : process_cmdline_) {
+ ::protozero::internal::gen_helpers::SerializeString(2, it, msg);
}
- // Field 122: prefer_suspend_clock_for_duration
- if (_has_field_[122]) {
- ::protozero::internal::gen_helpers::SerializeTinyVarInt(122, prefer_suspend_clock_for_duration_, msg);
+ // Field 4: pid
+ for (auto& it : pid_) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(4, it, msg);
}
- // Field 7: stop_timeout_ms
- if (_has_field_[7]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(7, stop_timeout_ms_, msg);
+ // Field 26: target_installed_by
+ for (auto& it : target_installed_by_) {
+ ::protozero::internal::gen_helpers::SerializeString(26, it, msg);
}
- // Field 6: enable_extra_guardrails
- if (_has_field_[6]) {
- ::protozero::internal::gen_helpers::SerializeTinyVarInt(6, enable_extra_guardrails_, msg);
+ // Field 20: heaps
+ for (auto& it : heaps_) {
+ ::protozero::internal::gen_helpers::SerializeString(20, it, msg);
}
- // Field 8: session_initiator
- if (_has_field_[8]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(8, session_initiator_, msg);
+ // Field 27: exclude_heaps
+ for (auto& it : exclude_heaps_) {
+ ::protozero::internal::gen_helpers::SerializeString(27, it, msg);
}
- // Field 4: tracing_session_id
- if (_has_field_[4]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(4, tracing_session_id_, msg);
+ // Field 23: stream_allocations
+ if (_has_field_[23]) {
+ ::protozero::internal::gen_helpers::SerializeTinyVarInt(23, stream_allocations_, msg);
}
- // Field 9: buffer_exhausted_policy
- if (_has_field_[9]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(9, buffer_exhausted_policy_, msg);
+ // Field 22: heap_sampling_intervals
+ for (auto& it : heap_sampling_intervals_) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(22, it, msg);
}
- // Field 10: priority_boost
- if (_has_field_[10]) {
- (*priority_boost_).Serialize(msg->BeginNestedMessage<::protozero::Message>(10));
+ // Field 21: all_heaps
+ if (_has_field_[21]) {
+ ::protozero::internal::gen_helpers::SerializeTinyVarInt(21, all_heaps_, msg);
}
- // Field 12: protovm_config
- if (_has_field_[12]) {
- (*protovm_config_).Serialize(msg->BeginNestedMessage<::protozero::Message>(12));
+ // Field 5: all
+ if (_has_field_[5]) {
+ ::protozero::internal::gen_helpers::SerializeTinyVarInt(5, all_, msg);
}
- // Field 100: ftrace_config
- if (_has_field_[100]) {
- msg->AppendString(100, ftrace_config_);
+ // Field 15: min_anonymous_memory_kb
+ if (_has_field_[15]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(15, min_anonymous_memory_kb_, msg);
}
- // Field 102: inode_file_config
- if (_has_field_[102]) {
- msg->AppendString(102, inode_file_config_);
+ // Field 16: max_heapprofd_memory_kb
+ if (_has_field_[16]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(16, max_heapprofd_memory_kb_, msg);
}
- // Field 103: process_stats_config
- if (_has_field_[103]) {
- msg->AppendString(103, process_stats_config_);
+ // Field 17: max_heapprofd_cpu_secs
+ if (_has_field_[17]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(17, max_heapprofd_cpu_secs_, msg);
}
- // Field 104: sys_stats_config
- if (_has_field_[104]) {
- msg->AppendString(104, sys_stats_config_);
+ // Field 7: skip_symbol_prefix
+ for (auto& it : skip_symbol_prefix_) {
+ ::protozero::internal::gen_helpers::SerializeString(7, it, msg);
}
- // Field 105: heapprofd_config
- if (_has_field_[105]) {
- msg->AppendString(105, heapprofd_config_);
+ // Field 6: continuous_dump_config
+ if (_has_field_[6]) {
+ (*continuous_dump_config_).Serialize(msg->BeginNestedMessage<::protozero::Message>(6));
}
- // Field 110: java_hprof_config
- if (_has_field_[110]) {
- msg->AppendString(110, java_hprof_config_);
+ // Field 8: shmem_size_bytes
+ if (_has_field_[8]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(8, shmem_size_bytes_, msg);
}
- // Field 106: android_power_config
- if (_has_field_[106]) {
- msg->AppendString(106, android_power_config_);
+ // Field 9: block_client
+ if (_has_field_[9]) {
+ ::protozero::internal::gen_helpers::SerializeTinyVarInt(9, block_client_, msg);
}
- // Field 107: android_log_config
- if (_has_field_[107]) {
- msg->AppendString(107, android_log_config_);
+ // Field 14: block_client_timeout_us
+ if (_has_field_[14]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(14, block_client_timeout_us_, msg);
}
- // Field 108: gpu_counter_config
- if (_has_field_[108]) {
- msg->AppendString(108, gpu_counter_config_);
+ // Field 10: no_startup
+ if (_has_field_[10]) {
+ ::protozero::internal::gen_helpers::SerializeTinyVarInt(10, no_startup_, msg);
}
- // Field 116: android_game_intervention_list_config
- if (_has_field_[116]) {
- msg->AppendString(116, android_game_intervention_list_config_);
+ // Field 11: no_running
+ if (_has_field_[11]) {
+ ::protozero::internal::gen_helpers::SerializeTinyVarInt(11, no_running_, msg);
}
- // Field 109: packages_list_config
- if (_has_field_[109]) {
- msg->AppendString(109, packages_list_config_);
+ // Field 13: dump_at_max
+ if (_has_field_[13]) {
+ ::protozero::internal::gen_helpers::SerializeTinyVarInt(13, dump_at_max_, msg);
}
- // Field 111: perf_event_config
- if (_has_field_[111]) {
- msg->AppendString(111, perf_event_config_);
+ // Field 18: disable_fork_teardown
+ if (_has_field_[18]) {
+ ::protozero::internal::gen_helpers::SerializeTinyVarInt(18, disable_fork_teardown_, msg);
}
- // Field 112: vulkan_memory_config
- if (_has_field_[112]) {
- msg->AppendString(112, vulkan_memory_config_);
+ // Field 19: disable_vfork_detection
+ if (_has_field_[19]) {
+ ::protozero::internal::gen_helpers::SerializeTinyVarInt(19, disable_vfork_detection_, msg);
}
- // Field 113: track_event_config
- if (_has_field_[113]) {
- msg->AppendString(113, track_event_config_);
- }
+ protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
+}
- // Field 114: android_polled_state_config
- if (_has_field_[114]) {
- msg->AppendString(114, android_polled_state_config_);
- }
- // Field 118: android_system_property_config
- if (_has_field_[118]) {
- msg->AppendString(118, android_system_property_config_);
- }
+HeapprofdConfig_ContinuousDumpConfig::HeapprofdConfig_ContinuousDumpConfig() = default;
+HeapprofdConfig_ContinuousDumpConfig::~HeapprofdConfig_ContinuousDumpConfig() = default;
+HeapprofdConfig_ContinuousDumpConfig::HeapprofdConfig_ContinuousDumpConfig(const HeapprofdConfig_ContinuousDumpConfig&) = default;
+HeapprofdConfig_ContinuousDumpConfig& HeapprofdConfig_ContinuousDumpConfig::operator=(const HeapprofdConfig_ContinuousDumpConfig&) = default;
+HeapprofdConfig_ContinuousDumpConfig::HeapprofdConfig_ContinuousDumpConfig(HeapprofdConfig_ContinuousDumpConfig&&) noexcept = default;
+HeapprofdConfig_ContinuousDumpConfig& HeapprofdConfig_ContinuousDumpConfig::operator=(HeapprofdConfig_ContinuousDumpConfig&&) = default;
- // Field 117: statsd_tracing_config
- if (_has_field_[117]) {
- msg->AppendString(117, statsd_tracing_config_);
- }
+bool HeapprofdConfig_ContinuousDumpConfig::operator==(const HeapprofdConfig_ContinuousDumpConfig& other) const {
+ return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
+ && ::protozero::internal::gen_helpers::EqualsField(dump_phase_ms_, other.dump_phase_ms_)
+ && ::protozero::internal::gen_helpers::EqualsField(dump_interval_ms_, other.dump_interval_ms_);
+}
- // Field 119: system_info_config
- if (_has_field_[119]) {
- (*system_info_config_).Serialize(msg->BeginNestedMessage<::protozero::Message>(119));
- }
+bool HeapprofdConfig_ContinuousDumpConfig::ParseFromArray(const void* raw, size_t size) {
+ unknown_fields_.clear();
+ bool packed_error = false;
- // Field 136: frozen_ftrace_config
- if (_has_field_[136]) {
- msg->AppendString(136, frozen_ftrace_config_);
+ ::protozero::ProtoDecoder dec(raw, size);
+ for (auto field = dec.ReadField(); field.valid(); field = dec.ReadField()) {
+ if (field.id() < _has_field_.size()) {
+ _has_field_.set(field.id());
+ }
+ switch (field.id()) {
+ case 5 /* dump_phase_ms */:
+ field.get(&dump_phase_ms_);
+ break;
+ case 6 /* dump_interval_ms */:
+ field.get(&dump_interval_ms_);
+ break;
+ default:
+ field.SerializeAndAppendTo(&unknown_fields_);
+ break;
+ }
}
+ return !packed_error && !dec.bytes_left();
+}
- // Field 101: chrome_config
- if (_has_field_[101]) {
- (*chrome_config_).Serialize(msg->BeginNestedMessage<::protozero::Message>(101));
- }
+std::string HeapprofdConfig_ContinuousDumpConfig::SerializeAsString() const {
+ ::protozero::internal::gen_helpers::MessageSerializer msg;
+ Serialize(msg.get());
+ return msg.SerializeAsString();
+}
- // Field 127: v8_config
- if (_has_field_[127]) {
- msg->AppendString(127, v8_config_);
- }
-
- // Field 115: interceptor_config
- if (_has_field_[115]) {
- (*interceptor_config_).Serialize(msg->BeginNestedMessage<::protozero::Message>(115));
- }
-
- // Field 120: network_packet_trace_config
- if (_has_field_[120]) {
- msg->AppendString(120, network_packet_trace_config_);
- }
-
- // Field 121: surfaceflinger_layers_config
- if (_has_field_[121]) {
- msg->AppendString(121, surfaceflinger_layers_config_);
- }
-
- // Field 123: surfaceflinger_transactions_config
- if (_has_field_[123]) {
- msg->AppendString(123, surfaceflinger_transactions_config_);
- }
-
- // Field 124: android_sdk_sysprop_guard_config
- if (_has_field_[124]) {
- msg->AppendString(124, android_sdk_sysprop_guard_config_);
- }
-
- // Field 125: etw_config
- if (_has_field_[125]) {
- msg->AppendString(125, etw_config_);
- }
-
- // Field 126: protolog_config
- if (_has_field_[126]) {
- msg->AppendString(126, protolog_config_);
- }
-
- // Field 128: android_input_event_config
- if (_has_field_[128]) {
- msg->AppendString(128, android_input_event_config_);
- }
-
- // Field 129: pixel_modem_config
- if (_has_field_[129]) {
- msg->AppendString(129, pixel_modem_config_);
- }
-
- // Field 130: windowmanager_config
- if (_has_field_[130]) {
- msg->AppendString(130, windowmanager_config_);
- }
-
- // Field 131: chromium_system_metrics
- if (_has_field_[131]) {
- msg->AppendString(131, chromium_system_metrics_);
- }
-
- // Field 132: kernel_wakelocks_config
- if (_has_field_[132]) {
- msg->AppendString(132, kernel_wakelocks_config_);
- }
-
- // Field 133: gpu_renderstages_config
- if (_has_field_[133]) {
- msg->AppendString(133, gpu_renderstages_config_);
- }
-
- // Field 134: chromium_histogram_samples
- if (_has_field_[134]) {
- msg->AppendString(134, chromium_histogram_samples_);
- }
-
- // Field 135: app_wakelocks_config
- if (_has_field_[135]) {
- msg->AppendString(135, app_wakelocks_config_);
- }
-
- // Field 137: cpu_per_uid_config
- if (_has_field_[137]) {
- msg->AppendString(137, cpu_per_uid_config_);
- }
-
- // Field 138: user_list_config
- if (_has_field_[138]) {
- msg->AppendString(138, user_list_config_);
- }
-
- // Field 139: inputmethod_config
- if (_has_field_[139]) {
- msg->AppendString(139, inputmethod_config_);
- }
-
- // Field 140: android_aflags_config
- if (_has_field_[140]) {
- msg->AppendString(140, android_aflags_config_);
- }
-
- // Field 141: journald_config
- if (_has_field_[141]) {
- msg->AppendString(141, journald_config_);
- }
-
- // Field 142: display_video_config
- if (_has_field_[142]) {
- msg->AppendString(142, display_video_config_);
- }
-
- // Field 150: qnx_config
- if (_has_field_[150]) {
- msg->AppendString(150, qnx_config_);
- }
+std::vector<uint8_t> HeapprofdConfig_ContinuousDumpConfig::SerializeAsArray() const {
+ ::protozero::internal::gen_helpers::MessageSerializer msg;
+ Serialize(msg.get());
+ return msg.SerializeAsArray();
+}
- // Field 1000: legacy_config
- if (_has_field_[1000]) {
- ::protozero::internal::gen_helpers::SerializeString(1000, legacy_config_, msg);
+void HeapprofdConfig_ContinuousDumpConfig::Serialize(::protozero::Message* msg) const {
+ // Field 5: dump_phase_ms
+ if (_has_field_[5]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(5, dump_phase_ms_, msg);
}
- // Field 1001: for_testing
- if (_has_field_[1001]) {
- (*for_testing_).Serialize(msg->BeginNestedMessage<::protozero::Message>(1001));
+ // Field 6: dump_interval_ms
+ if (_has_field_[6]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(6, dump_interval_ms_, msg);
}
protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
@@ -29222,7 +28511,7 @@ void DataSourceConfig::Serialize(::protozero::Message* msg) const {
#if defined(__GNUC__) || defined(__clang__)
#pragma GCC diagnostic pop
#endif
-// gen_amalgamated begin source: gen/protos/perfetto/config/etw/etw_config.gen.cc
+// gen_amalgamated begin source: gen/protos/perfetto/config/profiling/java_hprof_config.gen.cc
// gen_amalgamated expanded: #include "perfetto/protozero/gen_field_helpers.h"
// gen_amalgamated expanded: #include "perfetto/protozero/message.h"
// gen_amalgamated expanded: #include "perfetto/protozero/packed_repeated_fields.h"
@@ -29233,38 +28522,39 @@ void DataSourceConfig::Serialize(::protozero::Message* msg) const {
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wfloat-equal"
#endif
-// gen_amalgamated expanded: #include "protos/perfetto/config/etw/etw_config.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/config/profiling/java_hprof_config.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/config/profiling/smaps_config.gen.h"
namespace perfetto {
namespace protos {
namespace gen {
-EtwConfig::EtwConfig() = default;
-EtwConfig::~EtwConfig() = default;
-EtwConfig::EtwConfig(const EtwConfig&) = default;
-EtwConfig& EtwConfig::operator=(const EtwConfig&) = default;
-EtwConfig::EtwConfig(EtwConfig&&) noexcept = default;
-EtwConfig& EtwConfig::operator=(EtwConfig&&) = default;
+JavaHprofConfig::JavaHprofConfig() = default;
+JavaHprofConfig::~JavaHprofConfig() = default;
+JavaHprofConfig::JavaHprofConfig(const JavaHprofConfig&) = default;
+JavaHprofConfig& JavaHprofConfig::operator=(const JavaHprofConfig&) = default;
+JavaHprofConfig::JavaHprofConfig(JavaHprofConfig&&) noexcept = default;
+JavaHprofConfig& JavaHprofConfig::operator=(JavaHprofConfig&&) = default;
-bool EtwConfig::operator==(const EtwConfig& other) const {
+bool JavaHprofConfig::operator==(const JavaHprofConfig& other) const {
return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
- && ::protozero::internal::gen_helpers::EqualsField(kernel_flags_, other.kernel_flags_)
- && ::protozero::internal::gen_helpers::EqualsField(scheduler_provider_events_, other.scheduler_provider_events_)
- && ::protozero::internal::gen_helpers::EqualsField(memory_provider_events_, other.memory_provider_events_)
- && ::protozero::internal::gen_helpers::EqualsField(file_provider_events_, other.file_provider_events_)
- && ::protozero::internal::gen_helpers::EqualsField(stack_sampling_events_, other.stack_sampling_events_)
- && ::protozero::internal::gen_helpers::EqualsField(disk_provider_events_, other.disk_provider_events_)
- && ::protozero::internal::gen_helpers::EqualsField(system_io_provider_events_, other.system_io_provider_events_);
+ && ::protozero::internal::gen_helpers::EqualsField(process_cmdline_, other.process_cmdline_)
+ && ::protozero::internal::gen_helpers::EqualsField(pid_, other.pid_)
+ && ::protozero::internal::gen_helpers::EqualsField(target_installed_by_, other.target_installed_by_)
+ && ::protozero::internal::gen_helpers::EqualsField(continuous_dump_config_, other.continuous_dump_config_)
+ && ::protozero::internal::gen_helpers::EqualsField(min_anonymous_memory_kb_, other.min_anonymous_memory_kb_)
+ && ::protozero::internal::gen_helpers::EqualsField(min_java_heap_size_kb_, other.min_java_heap_size_kb_)
+ && ::protozero::internal::gen_helpers::EqualsField(dump_smaps_, other.dump_smaps_)
+ && ::protozero::internal::gen_helpers::EqualsField(smaps_config_, other.smaps_config_)
+ && ::protozero::internal::gen_helpers::EqualsField(ignored_types_, other.ignored_types_)
+ && ::protozero::internal::gen_helpers::EqualsField(dump_oome_callstack_, other.dump_oome_callstack_);
}
-bool EtwConfig::ParseFromArray(const void* raw, size_t size) {
- kernel_flags_.clear();
- scheduler_provider_events_.clear();
- memory_provider_events_.clear();
- file_provider_events_.clear();
- stack_sampling_events_.clear();
- disk_provider_events_.clear();
- system_io_provider_events_.clear();
+bool JavaHprofConfig::ParseFromArray(const void* raw, size_t size) {
+ process_cmdline_.clear();
+ pid_.clear();
+ target_installed_by_.clear();
+ ignored_types_.clear();
unknown_fields_.clear();
bool packed_error = false;
@@ -29274,33 +28564,39 @@ bool EtwConfig::ParseFromArray(const void* raw, size_t size) {
_has_field_.set(field.id());
}
switch (field.id()) {
- case 1 /* kernel_flags */:
- kernel_flags_.emplace_back();
- field.get(&kernel_flags_.back());
+ case 1 /* process_cmdline */:
+ process_cmdline_.emplace_back();
+ ::protozero::internal::gen_helpers::DeserializeString(field, &process_cmdline_.back());
break;
- case 2 /* scheduler_provider_events */:
- scheduler_provider_events_.emplace_back();
- ::protozero::internal::gen_helpers::DeserializeString(field, &scheduler_provider_events_.back());
+ case 2 /* pid */:
+ pid_.emplace_back();
+ field.get(&pid_.back());
break;
- case 3 /* memory_provider_events */:
- memory_provider_events_.emplace_back();
- ::protozero::internal::gen_helpers::DeserializeString(field, &memory_provider_events_.back());
+ case 7 /* target_installed_by */:
+ target_installed_by_.emplace_back();
+ ::protozero::internal::gen_helpers::DeserializeString(field, &target_installed_by_.back());
break;
- case 4 /* file_provider_events */:
- file_provider_events_.emplace_back();
- ::protozero::internal::gen_helpers::DeserializeString(field, &file_provider_events_.back());
+ case 3 /* continuous_dump_config */:
+ (*continuous_dump_config_).ParseFromArray(field.data(), field.size());
break;
- case 5 /* stack_sampling_events */:
- stack_sampling_events_.emplace_back();
- ::protozero::internal::gen_helpers::DeserializeString(field, &stack_sampling_events_.back());
+ case 4 /* min_anonymous_memory_kb */:
+ field.get(&min_anonymous_memory_kb_);
break;
- case 6 /* disk_provider_events */:
- disk_provider_events_.emplace_back();
- ::protozero::internal::gen_helpers::DeserializeString(field, &disk_provider_events_.back());
+ case 9 /* min_java_heap_size_kb */:
+ field.get(&min_java_heap_size_kb_);
break;
- case 7 /* system_io_provider_events */:
- system_io_provider_events_.emplace_back();
- ::protozero::internal::gen_helpers::DeserializeString(field, &system_io_provider_events_.back());
+ case 5 /* dump_smaps */:
+ field.get(&dump_smaps_);
+ break;
+ case 8 /* smaps_config */:
+ (*smaps_config_).ParseFromArray(field.data(), field.size());
+ break;
+ case 6 /* ignored_types */:
+ ignored_types_.emplace_back();
+ ::protozero::internal::gen_helpers::DeserializeString(field, &ignored_types_.back());
+ break;
+ case 10 /* dump_oome_callstack */:
+ field.get(&dump_oome_callstack_);
break;
default:
field.SerializeAndAppendTo(&unknown_fields_);
@@ -29310,95 +28606,88 @@ bool EtwConfig::ParseFromArray(const void* raw, size_t size) {
return !packed_error && !dec.bytes_left();
}
-std::string EtwConfig::SerializeAsString() const {
+std::string JavaHprofConfig::SerializeAsString() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsString();
}
-std::vector<uint8_t> EtwConfig::SerializeAsArray() const {
+std::vector<uint8_t> JavaHprofConfig::SerializeAsArray() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsArray();
}
-void EtwConfig::Serialize(::protozero::Message* msg) const {
- // Field 1: kernel_flags
- for (auto& it : kernel_flags_) {
- ::protozero::internal::gen_helpers::SerializeVarInt(1, it, msg);
+void JavaHprofConfig::Serialize(::protozero::Message* msg) const {
+ // Field 1: process_cmdline
+ for (auto& it : process_cmdline_) {
+ ::protozero::internal::gen_helpers::SerializeString(1, it, msg);
}
- // Field 2: scheduler_provider_events
- for (auto& it : scheduler_provider_events_) {
- ::protozero::internal::gen_helpers::SerializeString(2, it, msg);
+ // Field 2: pid
+ for (auto& it : pid_) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(2, it, msg);
}
- // Field 3: memory_provider_events
- for (auto& it : memory_provider_events_) {
- ::protozero::internal::gen_helpers::SerializeString(3, it, msg);
+ // Field 7: target_installed_by
+ for (auto& it : target_installed_by_) {
+ ::protozero::internal::gen_helpers::SerializeString(7, it, msg);
}
- // Field 4: file_provider_events
- for (auto& it : file_provider_events_) {
- ::protozero::internal::gen_helpers::SerializeString(4, it, msg);
+ // Field 3: continuous_dump_config
+ if (_has_field_[3]) {
+ (*continuous_dump_config_).Serialize(msg->BeginNestedMessage<::protozero::Message>(3));
}
- // Field 5: stack_sampling_events
- for (auto& it : stack_sampling_events_) {
- ::protozero::internal::gen_helpers::SerializeString(5, it, msg);
+ // Field 4: min_anonymous_memory_kb
+ if (_has_field_[4]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(4, min_anonymous_memory_kb_, msg);
}
- // Field 6: disk_provider_events
- for (auto& it : disk_provider_events_) {
+ // Field 9: min_java_heap_size_kb
+ if (_has_field_[9]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(9, min_java_heap_size_kb_, msg);
+ }
+
+ // Field 5: dump_smaps
+ if (_has_field_[5]) {
+ ::protozero::internal::gen_helpers::SerializeTinyVarInt(5, dump_smaps_, msg);
+ }
+
+ // Field 8: smaps_config
+ if (_has_field_[8]) {
+ (*smaps_config_).Serialize(msg->BeginNestedMessage<::protozero::Message>(8));
+ }
+
+ // Field 6: ignored_types
+ for (auto& it : ignored_types_) {
::protozero::internal::gen_helpers::SerializeString(6, it, msg);
}
- // Field 7: system_io_provider_events
- for (auto& it : system_io_provider_events_) {
- ::protozero::internal::gen_helpers::SerializeString(7, it, msg);
+ // Field 10: dump_oome_callstack
+ if (_has_field_[10]) {
+ ::protozero::internal::gen_helpers::SerializeTinyVarInt(10, dump_oome_callstack_, msg);
}
protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
}
-} // namespace perfetto
-} // namespace protos
-} // namespace gen
-#if defined(__GNUC__) || defined(__clang__)
-#pragma GCC diagnostic pop
-#endif
-// gen_amalgamated begin source: gen/protos/perfetto/config/interceptor_config.gen.cc
-// gen_amalgamated expanded: #include "perfetto/protozero/gen_field_helpers.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/message.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/packed_repeated_fields.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/proto_decoder.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/scattered_heap_buffer.h"
-// DO NOT EDIT. Autogenerated by Perfetto cppgen_plugin
-#if defined(__GNUC__) || defined(__clang__)
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wfloat-equal"
-#endif
-// gen_amalgamated expanded: #include "protos/perfetto/config/interceptor_config.gen.h"
-// gen_amalgamated expanded: #include "protos/perfetto/config/interceptors/console_config.gen.h"
-
-namespace perfetto {
-namespace protos {
-namespace gen {
-InterceptorConfig::InterceptorConfig() = default;
-InterceptorConfig::~InterceptorConfig() = default;
-InterceptorConfig::InterceptorConfig(const InterceptorConfig&) = default;
-InterceptorConfig& InterceptorConfig::operator=(const InterceptorConfig&) = default;
-InterceptorConfig::InterceptorConfig(InterceptorConfig&&) noexcept = default;
-InterceptorConfig& InterceptorConfig::operator=(InterceptorConfig&&) = default;
+JavaHprofConfig_ContinuousDumpConfig::JavaHprofConfig_ContinuousDumpConfig() = default;
+JavaHprofConfig_ContinuousDumpConfig::~JavaHprofConfig_ContinuousDumpConfig() = default;
+JavaHprofConfig_ContinuousDumpConfig::JavaHprofConfig_ContinuousDumpConfig(const JavaHprofConfig_ContinuousDumpConfig&) = default;
+JavaHprofConfig_ContinuousDumpConfig& JavaHprofConfig_ContinuousDumpConfig::operator=(const JavaHprofConfig_ContinuousDumpConfig&) = default;
+JavaHprofConfig_ContinuousDumpConfig::JavaHprofConfig_ContinuousDumpConfig(JavaHprofConfig_ContinuousDumpConfig&&) noexcept = default;
+JavaHprofConfig_ContinuousDumpConfig& JavaHprofConfig_ContinuousDumpConfig::operator=(JavaHprofConfig_ContinuousDumpConfig&&) = default;
-bool InterceptorConfig::operator==(const InterceptorConfig& other) const {
+bool JavaHprofConfig_ContinuousDumpConfig::operator==(const JavaHprofConfig_ContinuousDumpConfig& other) const {
return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
- && ::protozero::internal::gen_helpers::EqualsField(name_, other.name_)
- && ::protozero::internal::gen_helpers::EqualsField(console_config_, other.console_config_);
+ && ::protozero::internal::gen_helpers::EqualsField(dump_phase_ms_, other.dump_phase_ms_)
+ && ::protozero::internal::gen_helpers::EqualsField(dump_interval_ms_, other.dump_interval_ms_)
+ && ::protozero::internal::gen_helpers::EqualsField(scan_pids_only_on_start_, other.scan_pids_only_on_start_);
}
-bool InterceptorConfig::ParseFromArray(const void* raw, size_t size) {
+bool JavaHprofConfig_ContinuousDumpConfig::ParseFromArray(const void* raw, size_t size) {
unknown_fields_.clear();
bool packed_error = false;
@@ -29408,11 +28697,14 @@ bool InterceptorConfig::ParseFromArray(const void* raw, size_t size) {
_has_field_.set(field.id());
}
switch (field.id()) {
- case 1 /* name */:
- ::protozero::internal::gen_helpers::DeserializeString(field, &name_);
+ case 1 /* dump_phase_ms */:
+ field.get(&dump_phase_ms_);
break;
- case 100 /* console_config */:
- (*console_config_).ParseFromArray(field.data(), field.size());
+ case 2 /* dump_interval_ms */:
+ field.get(&dump_interval_ms_);
+ break;
+ case 3 /* scan_pids_only_on_start */:
+ field.get(&scan_pids_only_on_start_);
break;
default:
field.SerializeAndAppendTo(&unknown_fields_);
@@ -29422,27 +28714,32 @@ bool InterceptorConfig::ParseFromArray(const void* raw, size_t size) {
return !packed_error && !dec.bytes_left();
}
-std::string InterceptorConfig::SerializeAsString() const {
+std::string JavaHprofConfig_ContinuousDumpConfig::SerializeAsString() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsString();
}
-std::vector<uint8_t> InterceptorConfig::SerializeAsArray() const {
+std::vector<uint8_t> JavaHprofConfig_ContinuousDumpConfig::SerializeAsArray() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsArray();
}
-void InterceptorConfig::Serialize(::protozero::Message* msg) const {
- // Field 1: name
+void JavaHprofConfig_ContinuousDumpConfig::Serialize(::protozero::Message* msg) const {
+ // Field 1: dump_phase_ms
if (_has_field_[1]) {
- ::protozero::internal::gen_helpers::SerializeString(1, name_, msg);
+ ::protozero::internal::gen_helpers::SerializeVarInt(1, dump_phase_ms_, msg);
}
- // Field 100: console_config
- if (_has_field_[100]) {
- (*console_config_).Serialize(msg->BeginNestedMessage<::protozero::Message>(100));
+ // Field 2: dump_interval_ms
+ if (_has_field_[2]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(2, dump_interval_ms_, msg);
+ }
+
+ // Field 3: scan_pids_only_on_start
+ if (_has_field_[3]) {
+ ::protozero::internal::gen_helpers::SerializeTinyVarInt(3, scan_pids_only_on_start_, msg);
}
protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
@@ -29454,7 +28751,7 @@ void InterceptorConfig::Serialize(::protozero::Message* msg) const {
#if defined(__GNUC__) || defined(__clang__)
#pragma GCC diagnostic pop
#endif
-// gen_amalgamated begin source: gen/protos/perfetto/config/stress_test_config.gen.cc
+// gen_amalgamated begin source: gen/protos/perfetto/config/profiling/perf_event_config.gen.cc
// gen_amalgamated expanded: #include "perfetto/protozero/gen_field_helpers.h"
// gen_amalgamated expanded: #include "perfetto/protozero/message.h"
// gen_amalgamated expanded: #include "perfetto/protozero/packed_repeated_fields.h"
@@ -29465,92 +28762,57 @@ void InterceptorConfig::Serialize(::protozero::Message* msg) const {
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wfloat-equal"
#endif
-// gen_amalgamated expanded: #include "protos/perfetto/config/stress_test_config.gen.h"
-// gen_amalgamated expanded: #include "protos/perfetto/config/trace_config.gen.h"
-// gen_amalgamated expanded: #include "protos/perfetto/config/priority_boost/priority_boost_config.gen.h"
-// gen_amalgamated expanded: #include "protos/perfetto/config/data_source_config.gen.h"
-// gen_amalgamated expanded: #include "protos/perfetto/config/qnx/qnx_config.gen.h"
-// gen_amalgamated expanded: #include "protos/perfetto/config/linux/journald_config.gen.h"
-// gen_amalgamated expanded: #include "protos/perfetto/config/chrome/histogram_samples.gen.h"
-// gen_amalgamated expanded: #include "protos/perfetto/config/system_info/system_info_config.gen.h"
-// gen_amalgamated expanded: #include "protos/perfetto/config/track_event/track_event_config.gen.h"
-// gen_amalgamated expanded: #include "protos/perfetto/config/test_config.gen.h"
-// gen_amalgamated expanded: #include "protos/perfetto/config/sys_stats/sys_stats_config.gen.h"
-// gen_amalgamated expanded: #include "protos/perfetto/common/sys_stats_counters.gen.h"
// gen_amalgamated expanded: #include "protos/perfetto/config/profiling/perf_event_config.gen.h"
// gen_amalgamated expanded: #include "protos/perfetto/common/perf_events.gen.h"
-// gen_amalgamated expanded: #include "protos/perfetto/config/profiling/java_hprof_config.gen.h"
-// gen_amalgamated expanded: #include "protos/perfetto/config/profiling/smaps_config.gen.h"
-// gen_amalgamated expanded: #include "protos/perfetto/config/profiling/heapprofd_config.gen.h"
-// gen_amalgamated expanded: #include "protos/perfetto/config/process_stats/process_stats_config.gen.h"
-// gen_amalgamated expanded: #include "protos/perfetto/config/statsd/statsd_tracing_config.gen.h"
-// gen_amalgamated expanded: #include "protos/perfetto/config/statsd/atom_ids.gen.h"
-// gen_amalgamated expanded: #include "protos/perfetto/config/protovm/protovm_config.gen.h"
-// gen_amalgamated expanded: #include "protos/perfetto/config/power/android_power_config.gen.h"
-// gen_amalgamated expanded: #include "protos/perfetto/config/interceptor_config.gen.h"
-// gen_amalgamated expanded: #include "protos/perfetto/config/interceptors/console_config.gen.h"
-// gen_amalgamated expanded: #include "protos/perfetto/config/inode_file/inode_file_config.gen.h"
-// gen_amalgamated expanded: #include "protos/perfetto/config/gpu/gpu_renderstages_config.gen.h"
-// gen_amalgamated expanded: #include "protos/perfetto/config/gpu/vulkan_memory_config.gen.h"
-// gen_amalgamated expanded: #include "protos/perfetto/config/gpu/gpu_counter_config.gen.h"
-// gen_amalgamated expanded: #include "protos/perfetto/config/ftrace/frozen_ftrace_config.gen.h"
-// gen_amalgamated expanded: #include "protos/perfetto/config/ftrace/ftrace_config.gen.h"
-// gen_amalgamated expanded: #include "protos/perfetto/config/chrome/system_metrics.gen.h"
-// gen_amalgamated expanded: #include "protos/perfetto/config/etw/etw_config.gen.h"
-// gen_amalgamated expanded: #include "protos/perfetto/config/chrome/v8_config.gen.h"
-// gen_amalgamated expanded: #include "protos/perfetto/config/chrome/chrome_config.gen.h"
-// gen_amalgamated expanded: #include "protos/perfetto/config/android/windowmanager_config.gen.h"
-// gen_amalgamated expanded: #include "protos/perfetto/config/android/user_list_config.gen.h"
-// gen_amalgamated expanded: #include "protos/perfetto/config/android/surfaceflinger_transactions_config.gen.h"
-// gen_amalgamated expanded: #include "protos/perfetto/config/android/surfaceflinger_layers_config.gen.h"
-// gen_amalgamated expanded: #include "protos/perfetto/config/android/display_video_config.gen.h"
-// gen_amalgamated expanded: #include "protos/perfetto/config/android/protolog_config.gen.h"
-// gen_amalgamated expanded: #include "protos/perfetto/config/android/pixel_modem_config.gen.h"
-// gen_amalgamated expanded: #include "protos/perfetto/config/android/packages_list_config.gen.h"
-// gen_amalgamated expanded: #include "protos/perfetto/config/android/network_trace_config.gen.h"
-// gen_amalgamated expanded: #include "protos/perfetto/config/android/kernel_wakelocks_config.gen.h"
-// gen_amalgamated expanded: #include "protos/perfetto/config/android/inputmethod_config.gen.h"
-// gen_amalgamated expanded: #include "protos/perfetto/config/android/cpu_per_uid_config.gen.h"
-// gen_amalgamated expanded: #include "protos/perfetto/config/android/app_wakelock_config.gen.h"
-// gen_amalgamated expanded: #include "protos/perfetto/config/android/android_sdk_sysprop_guard_config.gen.h"
-// gen_amalgamated expanded: #include "protos/perfetto/config/android/android_system_property_config.gen.h"
-// gen_amalgamated expanded: #include "protos/perfetto/config/android/android_polled_state_config.gen.h"
-// gen_amalgamated expanded: #include "protos/perfetto/config/android/android_log_config.gen.h"
-// gen_amalgamated expanded: #include "protos/perfetto/common/android_log_constants.gen.h"
-// gen_amalgamated expanded: #include "protos/perfetto/config/android/android_input_event_config.gen.h"
-// gen_amalgamated expanded: #include "protos/perfetto/config/android/android_game_intervention_list_config.gen.h"
-// gen_amalgamated expanded: #include "protos/perfetto/config/android/android_aflags_config.gen.h"
-// gen_amalgamated expanded: #include "protos/perfetto/common/trace_attributes.gen.h"
-// gen_amalgamated expanded: #include "protos/perfetto/common/semantic_type.gen.h"
-// gen_amalgamated expanded: #include "protos/perfetto/common/builtin_clock.gen.h"
namespace perfetto {
namespace protos {
namespace gen {
-StressTestConfig::StressTestConfig() = default;
-StressTestConfig::~StressTestConfig() = default;
-StressTestConfig::StressTestConfig(const StressTestConfig&) = default;
-StressTestConfig& StressTestConfig::operator=(const StressTestConfig&) = default;
-StressTestConfig::StressTestConfig(StressTestConfig&&) noexcept = default;
-StressTestConfig& StressTestConfig::operator=(StressTestConfig&&) = default;
+PerfEventConfig::PerfEventConfig() = default;
+PerfEventConfig::~PerfEventConfig() = default;
+PerfEventConfig::PerfEventConfig(const PerfEventConfig&) = default;
+PerfEventConfig& PerfEventConfig::operator=(const PerfEventConfig&) = default;
+PerfEventConfig::PerfEventConfig(PerfEventConfig&&) noexcept = default;
+PerfEventConfig& PerfEventConfig::operator=(PerfEventConfig&&) = default;
-bool StressTestConfig::operator==(const StressTestConfig& other) const {
+bool PerfEventConfig::operator==(const PerfEventConfig& other) const {
return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
- && ::protozero::internal::gen_helpers::EqualsField(trace_config_, other.trace_config_)
- && ::protozero::internal::gen_helpers::EqualsField(shmem_size_kb_, other.shmem_size_kb_)
- && ::protozero::internal::gen_helpers::EqualsField(shmem_page_size_kb_, other.shmem_page_size_kb_)
- && ::protozero::internal::gen_helpers::EqualsField(num_processes_, other.num_processes_)
- && ::protozero::internal::gen_helpers::EqualsField(num_threads_, other.num_threads_)
- && ::protozero::internal::gen_helpers::EqualsField(max_events_, other.max_events_)
- && ::protozero::internal::gen_helpers::EqualsField(nesting_, other.nesting_)
- && ::protozero::internal::gen_helpers::EqualsField(steady_state_timings_, other.steady_state_timings_)
- && ::protozero::internal::gen_helpers::EqualsField(burst_period_ms_, other.burst_period_ms_)
- && ::protozero::internal::gen_helpers::EqualsField(burst_duration_ms_, other.burst_duration_ms_)
- && ::protozero::internal::gen_helpers::EqualsField(burst_timings_, other.burst_timings_);
+ && ::protozero::internal::gen_helpers::EqualsField(timebase_, other.timebase_)
+ && ::protozero::internal::gen_helpers::EqualsField(followers_, other.followers_)
+ && ::protozero::internal::gen_helpers::EqualsField(callstack_sampling_, other.callstack_sampling_)
+ && ::protozero::internal::gen_helpers::EqualsField(target_cpu_, other.target_cpu_)
+ && ::protozero::internal::gen_helpers::EqualsField(ignore_open_failure_, other.ignore_open_failure_)
+ && ::protozero::internal::gen_helpers::EqualsField(cpuid_, other.cpuid_)
+ && ::protozero::internal::gen_helpers::EqualsField(ring_buffer_read_period_ms_, other.ring_buffer_read_period_ms_)
+ && ::protozero::internal::gen_helpers::EqualsField(ring_buffer_pages_, other.ring_buffer_pages_)
+ && ::protozero::internal::gen_helpers::EqualsField(max_enqueued_footprint_kb_, other.max_enqueued_footprint_kb_)
+ && ::protozero::internal::gen_helpers::EqualsField(max_daemon_memory_kb_, other.max_daemon_memory_kb_)
+ && ::protozero::internal::gen_helpers::EqualsField(remote_descriptor_timeout_ms_, other.remote_descriptor_timeout_ms_)
+ && ::protozero::internal::gen_helpers::EqualsField(unwind_state_clear_period_ms_, other.unwind_state_clear_period_ms_)
+ && ::protozero::internal::gen_helpers::EqualsField(target_installed_by_, other.target_installed_by_)
+ && ::protozero::internal::gen_helpers::EqualsField(all_cpus_, other.all_cpus_)
+ && ::protozero::internal::gen_helpers::EqualsField(sampling_frequency_, other.sampling_frequency_)
+ && ::protozero::internal::gen_helpers::EqualsField(kernel_frames_, other.kernel_frames_)
+ && ::protozero::internal::gen_helpers::EqualsField(target_pid_, other.target_pid_)
+ && ::protozero::internal::gen_helpers::EqualsField(target_cmdline_, other.target_cmdline_)
+ && ::protozero::internal::gen_helpers::EqualsField(exclude_pid_, other.exclude_pid_)
+ && ::protozero::internal::gen_helpers::EqualsField(exclude_cmdline_, other.exclude_cmdline_)
+ && ::protozero::internal::gen_helpers::EqualsField(additional_cmdline_count_, other.additional_cmdline_count_);
}
-bool StressTestConfig::ParseFromArray(const void* raw, size_t size) {
+int PerfEventConfig::followers_size() const { return static_cast<int>(followers_.size()); }
+void PerfEventConfig::clear_followers() { followers_.clear(); }
+FollowerEvent* PerfEventConfig::add_followers() { followers_.emplace_back(); return &followers_.back(); }
+bool PerfEventConfig::ParseFromArray(const void* raw, size_t size) {
+ followers_.clear();
+ target_cpu_.clear();
+ cpuid_.clear();
+ target_installed_by_.clear();
+ target_pid_.clear();
+ target_cmdline_.clear();
+ exclude_pid_.clear();
+ exclude_cmdline_.clear();
unknown_fields_.clear();
bool packed_error = false;
@@ -29560,38 +28822,76 @@ bool StressTestConfig::ParseFromArray(const void* raw, size_t size) {
_has_field_.set(field.id());
}
switch (field.id()) {
- case 1 /* trace_config */:
- (*trace_config_).ParseFromArray(field.data(), field.size());
+ case 15 /* timebase */:
+ (*timebase_).ParseFromArray(field.data(), field.size());
break;
- case 2 /* shmem_size_kb */:
- field.get(&shmem_size_kb_);
+ case 19 /* followers */:
+ followers_.emplace_back();
+ followers_.back().ParseFromArray(field.data(), field.size());
break;
- case 3 /* shmem_page_size_kb */:
- field.get(&shmem_page_size_kb_);
+ case 16 /* callstack_sampling */:
+ (*callstack_sampling_).ParseFromArray(field.data(), field.size());
break;
- case 4 /* num_processes */:
- field.get(&num_processes_);
+ case 20 /* target_cpu */:
+ target_cpu_.emplace_back();
+ field.get(&target_cpu_.back());
break;
- case 5 /* num_threads */:
- field.get(&num_threads_);
+ case 21 /* ignore_open_failure */:
+ field.get(&ignore_open_failure_);
break;
- case 6 /* max_events */:
- field.get(&max_events_);
+ case 22 /* cpuid */:
+ cpuid_.emplace_back();
+ ::protozero::internal::gen_helpers::DeserializeString(field, &cpuid_.back());
break;
- case 7 /* nesting */:
- field.get(&nesting_);
+ case 8 /* ring_buffer_read_period_ms */:
+ field.get(&ring_buffer_read_period_ms_);
break;
- case 8 /* steady_state_timings */:
- (*steady_state_timings_).ParseFromArray(field.data(), field.size());
+ case 3 /* ring_buffer_pages */:
+ field.get(&ring_buffer_pages_);
break;
- case 9 /* burst_period_ms */:
- field.get(&burst_period_ms_);
+ case 17 /* max_enqueued_footprint_kb */:
+ field.get(&max_enqueued_footprint_kb_);
break;
- case 10 /* burst_duration_ms */:
- field.get(&burst_duration_ms_);
+ case 13 /* max_daemon_memory_kb */:
+ field.get(&max_daemon_memory_kb_);
break;
- case 11 /* burst_timings */:
- (*burst_timings_).ParseFromArray(field.data(), field.size());
+ case 9 /* remote_descriptor_timeout_ms */:
+ field.get(&remote_descriptor_timeout_ms_);
+ break;
+ case 10 /* unwind_state_clear_period_ms */:
+ field.get(&unwind_state_clear_period_ms_);
+ break;
+ case 18 /* target_installed_by */:
+ target_installed_by_.emplace_back();
+ ::protozero::internal::gen_helpers::DeserializeString(field, &target_installed_by_.back());
+ break;
+ case 1 /* all_cpus */:
+ field.get(&all_cpus_);
+ break;
+ case 2 /* sampling_frequency */:
+ field.get(&sampling_frequency_);
+ break;
+ case 12 /* kernel_frames */:
+ field.get(&kernel_frames_);
+ break;
+ case 4 /* target_pid */:
+ target_pid_.emplace_back();
+ field.get(&target_pid_.back());
+ break;
+ case 5 /* target_cmdline */:
+ target_cmdline_.emplace_back();
+ ::protozero::internal::gen_helpers::DeserializeString(field, &target_cmdline_.back());
+ break;
+ case 6 /* exclude_pid */:
+ exclude_pid_.emplace_back();
+ field.get(&exclude_pid_.back());
+ break;
+ case 7 /* exclude_cmdline */:
+ exclude_cmdline_.emplace_back();
+ ::protozero::internal::gen_helpers::DeserializeString(field, &exclude_cmdline_.back());
+ break;
+ case 11 /* additional_cmdline_count */:
+ field.get(&additional_cmdline_count_);
break;
default:
field.SerializeAndAppendTo(&unknown_fields_);
@@ -29601,95 +28901,143 @@ bool StressTestConfig::ParseFromArray(const void* raw, size_t size) {
return !packed_error && !dec.bytes_left();
}
-std::string StressTestConfig::SerializeAsString() const {
+std::string PerfEventConfig::SerializeAsString() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsString();
}
-std::vector<uint8_t> StressTestConfig::SerializeAsArray() const {
+std::vector<uint8_t> PerfEventConfig::SerializeAsArray() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsArray();
}
-void StressTestConfig::Serialize(::protozero::Message* msg) const {
- // Field 1: trace_config
- if (_has_field_[1]) {
- (*trace_config_).Serialize(msg->BeginNestedMessage<::protozero::Message>(1));
+void PerfEventConfig::Serialize(::protozero::Message* msg) const {
+ // Field 15: timebase
+ if (_has_field_[15]) {
+ (*timebase_).Serialize(msg->BeginNestedMessage<::protozero::Message>(15));
}
- // Field 2: shmem_size_kb
- if (_has_field_[2]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(2, shmem_size_kb_, msg);
+ // Field 19: followers
+ for (auto& it : followers_) {
+ it.Serialize(msg->BeginNestedMessage<::protozero::Message>(19));
}
- // Field 3: shmem_page_size_kb
- if (_has_field_[3]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(3, shmem_page_size_kb_, msg);
+ // Field 16: callstack_sampling
+ if (_has_field_[16]) {
+ (*callstack_sampling_).Serialize(msg->BeginNestedMessage<::protozero::Message>(16));
}
- // Field 4: num_processes
- if (_has_field_[4]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(4, num_processes_, msg);
+ // Field 20: target_cpu
+ for (auto& it : target_cpu_) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(20, it, msg);
}
- // Field 5: num_threads
- if (_has_field_[5]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(5, num_threads_, msg);
+ // Field 21: ignore_open_failure
+ if (_has_field_[21]) {
+ ::protozero::internal::gen_helpers::SerializeTinyVarInt(21, ignore_open_failure_, msg);
}
- // Field 6: max_events
- if (_has_field_[6]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(6, max_events_, msg);
+ // Field 22: cpuid
+ for (auto& it : cpuid_) {
+ ::protozero::internal::gen_helpers::SerializeString(22, it, msg);
}
- // Field 7: nesting
- if (_has_field_[7]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(7, nesting_, msg);
+ // Field 8: ring_buffer_read_period_ms
+ if (_has_field_[8]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(8, ring_buffer_read_period_ms_, msg);
}
- // Field 8: steady_state_timings
- if (_has_field_[8]) {
- (*steady_state_timings_).Serialize(msg->BeginNestedMessage<::protozero::Message>(8));
+ // Field 3: ring_buffer_pages
+ if (_has_field_[3]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(3, ring_buffer_pages_, msg);
}
- // Field 9: burst_period_ms
+ // Field 17: max_enqueued_footprint_kb
+ if (_has_field_[17]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(17, max_enqueued_footprint_kb_, msg);
+ }
+
+ // Field 13: max_daemon_memory_kb
+ if (_has_field_[13]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(13, max_daemon_memory_kb_, msg);
+ }
+
+ // Field 9: remote_descriptor_timeout_ms
if (_has_field_[9]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(9, burst_period_ms_, msg);
+ ::protozero::internal::gen_helpers::SerializeVarInt(9, remote_descriptor_timeout_ms_, msg);
}
- // Field 10: burst_duration_ms
+ // Field 10: unwind_state_clear_period_ms
if (_has_field_[10]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(10, burst_duration_ms_, msg);
+ ::protozero::internal::gen_helpers::SerializeVarInt(10, unwind_state_clear_period_ms_, msg);
}
- // Field 11: burst_timings
+ // Field 18: target_installed_by
+ for (auto& it : target_installed_by_) {
+ ::protozero::internal::gen_helpers::SerializeString(18, it, msg);
+ }
+
+ // Field 1: all_cpus
+ if (_has_field_[1]) {
+ ::protozero::internal::gen_helpers::SerializeTinyVarInt(1, all_cpus_, msg);
+ }
+
+ // Field 2: sampling_frequency
+ if (_has_field_[2]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(2, sampling_frequency_, msg);
+ }
+
+ // Field 12: kernel_frames
+ if (_has_field_[12]) {
+ ::protozero::internal::gen_helpers::SerializeTinyVarInt(12, kernel_frames_, msg);
+ }
+
+ // Field 4: target_pid
+ for (auto& it : target_pid_) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(4, it, msg);
+ }
+
+ // Field 5: target_cmdline
+ for (auto& it : target_cmdline_) {
+ ::protozero::internal::gen_helpers::SerializeString(5, it, msg);
+ }
+
+ // Field 6: exclude_pid
+ for (auto& it : exclude_pid_) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(6, it, msg);
+ }
+
+ // Field 7: exclude_cmdline
+ for (auto& it : exclude_cmdline_) {
+ ::protozero::internal::gen_helpers::SerializeString(7, it, msg);
+ }
+
+ // Field 11: additional_cmdline_count
if (_has_field_[11]) {
- (*burst_timings_).Serialize(msg->BeginNestedMessage<::protozero::Message>(11));
+ ::protozero::internal::gen_helpers::SerializeVarInt(11, additional_cmdline_count_, msg);
}
protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
}
-StressTestConfig_WriterTiming::StressTestConfig_WriterTiming() = default;
-StressTestConfig_WriterTiming::~StressTestConfig_WriterTiming() = default;
-StressTestConfig_WriterTiming::StressTestConfig_WriterTiming(const StressTestConfig_WriterTiming&) = default;
-StressTestConfig_WriterTiming& StressTestConfig_WriterTiming::operator=(const StressTestConfig_WriterTiming&) = default;
-StressTestConfig_WriterTiming::StressTestConfig_WriterTiming(StressTestConfig_WriterTiming&&) noexcept = default;
-StressTestConfig_WriterTiming& StressTestConfig_WriterTiming::operator=(StressTestConfig_WriterTiming&&) = default;
+PerfEventConfig_CallstackSampling::PerfEventConfig_CallstackSampling() = default;
+PerfEventConfig_CallstackSampling::~PerfEventConfig_CallstackSampling() = default;
+PerfEventConfig_CallstackSampling::PerfEventConfig_CallstackSampling(const PerfEventConfig_CallstackSampling&) = default;
+PerfEventConfig_CallstackSampling& PerfEventConfig_CallstackSampling::operator=(const PerfEventConfig_CallstackSampling&) = default;
+PerfEventConfig_CallstackSampling::PerfEventConfig_CallstackSampling(PerfEventConfig_CallstackSampling&&) noexcept = default;
+PerfEventConfig_CallstackSampling& PerfEventConfig_CallstackSampling::operator=(PerfEventConfig_CallstackSampling&&) = default;
-bool StressTestConfig_WriterTiming::operator==(const StressTestConfig_WriterTiming& other) const {
+bool PerfEventConfig_CallstackSampling::operator==(const PerfEventConfig_CallstackSampling& other) const {
return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
- && ::protozero::internal::gen_helpers::EqualsField(payload_mean_, other.payload_mean_)
- && ::protozero::internal::gen_helpers::EqualsField(payload_stddev_, other.payload_stddev_)
- && ::protozero::internal::gen_helpers::EqualsField(rate_mean_, other.rate_mean_)
- && ::protozero::internal::gen_helpers::EqualsField(rate_stddev_, other.rate_stddev_)
- && ::protozero::internal::gen_helpers::EqualsField(payload_write_time_ms_, other.payload_write_time_ms_);
+ && ::protozero::internal::gen_helpers::EqualsField(scope_, other.scope_)
+ && ::protozero::internal::gen_helpers::EqualsField(kernel_frames_, other.kernel_frames_)
+ && ::protozero::internal::gen_helpers::EqualsField(user_frames_, other.user_frames_);
}
-bool StressTestConfig_WriterTiming::ParseFromArray(const void* raw, size_t size) {
+bool PerfEventConfig_CallstackSampling::ParseFromArray(const void* raw, size_t size) {
unknown_fields_.clear();
bool packed_error = false;
@@ -29699,20 +29047,14 @@ bool StressTestConfig_WriterTiming::ParseFromArray(const void* raw, size_t size)
_has_field_.set(field.id());
}
switch (field.id()) {
- case 1 /* payload_mean */:
- field.get(&payload_mean_);
- break;
- case 2 /* payload_stddev */:
- field.get(&payload_stddev_);
- break;
- case 3 /* rate_mean */:
- field.get(&rate_mean_);
+ case 1 /* scope */:
+ (*scope_).ParseFromArray(field.data(), field.size());
break;
- case 4 /* rate_stddev */:
- field.get(&rate_stddev_);
+ case 2 /* kernel_frames */:
+ field.get(&kernel_frames_);
break;
- case 5 /* payload_write_time_ms */:
- field.get(&payload_write_time_ms_);
+ case 3 /* user_frames */:
+ field.get(&user_frames_);
break;
default:
field.SerializeAndAppendTo(&unknown_fields_);
@@ -29722,42 +29064,140 @@ bool StressTestConfig_WriterTiming::ParseFromArray(const void* raw, size_t size)
return !packed_error && !dec.bytes_left();
}
-std::string StressTestConfig_WriterTiming::SerializeAsString() const {
+std::string PerfEventConfig_CallstackSampling::SerializeAsString() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsString();
}
-std::vector<uint8_t> StressTestConfig_WriterTiming::SerializeAsArray() const {
+std::vector<uint8_t> PerfEventConfig_CallstackSampling::SerializeAsArray() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsArray();
}
-void StressTestConfig_WriterTiming::Serialize(::protozero::Message* msg) const {
- // Field 1: payload_mean
+void PerfEventConfig_CallstackSampling::Serialize(::protozero::Message* msg) const {
+ // Field 1: scope
if (_has_field_[1]) {
- ::protozero::internal::gen_helpers::SerializeFixed(1, payload_mean_, msg);
+ (*scope_).Serialize(msg->BeginNestedMessage<::protozero::Message>(1));
}
- // Field 2: payload_stddev
+ // Field 2: kernel_frames
if (_has_field_[2]) {
- ::protozero::internal::gen_helpers::SerializeFixed(2, payload_stddev_, msg);
+ ::protozero::internal::gen_helpers::SerializeTinyVarInt(2, kernel_frames_, msg);
}
- // Field 3: rate_mean
+ // Field 3: user_frames
if (_has_field_[3]) {
- ::protozero::internal::gen_helpers::SerializeFixed(3, rate_mean_, msg);
+ ::protozero::internal::gen_helpers::SerializeVarInt(3, user_frames_, msg);
}
- // Field 4: rate_stddev
- if (_has_field_[4]) {
- ::protozero::internal::gen_helpers::SerializeFixed(4, rate_stddev_, msg);
+ protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
+}
+
+
+PerfEventConfig_Scope::PerfEventConfig_Scope() = default;
+PerfEventConfig_Scope::~PerfEventConfig_Scope() = default;
+PerfEventConfig_Scope::PerfEventConfig_Scope(const PerfEventConfig_Scope&) = default;
+PerfEventConfig_Scope& PerfEventConfig_Scope::operator=(const PerfEventConfig_Scope&) = default;
+PerfEventConfig_Scope::PerfEventConfig_Scope(PerfEventConfig_Scope&&) noexcept = default;
+PerfEventConfig_Scope& PerfEventConfig_Scope::operator=(PerfEventConfig_Scope&&) = default;
+
+bool PerfEventConfig_Scope::operator==(const PerfEventConfig_Scope& other) const {
+ return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
+ && ::protozero::internal::gen_helpers::EqualsField(target_pid_, other.target_pid_)
+ && ::protozero::internal::gen_helpers::EqualsField(target_cmdline_, other.target_cmdline_)
+ && ::protozero::internal::gen_helpers::EqualsField(exclude_pid_, other.exclude_pid_)
+ && ::protozero::internal::gen_helpers::EqualsField(exclude_cmdline_, other.exclude_cmdline_)
+ && ::protozero::internal::gen_helpers::EqualsField(additional_cmdline_count_, other.additional_cmdline_count_)
+ && ::protozero::internal::gen_helpers::EqualsField(process_shard_count_, other.process_shard_count_);
+}
+
+bool PerfEventConfig_Scope::ParseFromArray(const void* raw, size_t size) {
+ target_pid_.clear();
+ target_cmdline_.clear();
+ exclude_pid_.clear();
+ exclude_cmdline_.clear();
+ unknown_fields_.clear();
+ bool packed_error = false;
+
+ ::protozero::ProtoDecoder dec(raw, size);
+ for (auto field = dec.ReadField(); field.valid(); field = dec.ReadField()) {
+ if (field.id() < _has_field_.size()) {
+ _has_field_.set(field.id());
+ }
+ switch (field.id()) {
+ case 1 /* target_pid */:
+ target_pid_.emplace_back();
+ field.get(&target_pid_.back());
+ break;
+ case 2 /* target_cmdline */:
+ target_cmdline_.emplace_back();
+ ::protozero::internal::gen_helpers::DeserializeString(field, &target_cmdline_.back());
+ break;
+ case 3 /* exclude_pid */:
+ exclude_pid_.emplace_back();
+ field.get(&exclude_pid_.back());
+ break;
+ case 4 /* exclude_cmdline */:
+ exclude_cmdline_.emplace_back();
+ ::protozero::internal::gen_helpers::DeserializeString(field, &exclude_cmdline_.back());
+ break;
+ case 5 /* additional_cmdline_count */:
+ field.get(&additional_cmdline_count_);
+ break;
+ case 6 /* process_shard_count */:
+ field.get(&process_shard_count_);
+ break;
+ default:
+ field.SerializeAndAppendTo(&unknown_fields_);
+ break;
+ }
}
+ return !packed_error && !dec.bytes_left();
+}
- // Field 5: payload_write_time_ms
+std::string PerfEventConfig_Scope::SerializeAsString() const {
+ ::protozero::internal::gen_helpers::MessageSerializer msg;
+ Serialize(msg.get());
+ return msg.SerializeAsString();
+}
+
+std::vector<uint8_t> PerfEventConfig_Scope::SerializeAsArray() const {
+ ::protozero::internal::gen_helpers::MessageSerializer msg;
+ Serialize(msg.get());
+ return msg.SerializeAsArray();
+}
+
+void PerfEventConfig_Scope::Serialize(::protozero::Message* msg) const {
+ // Field 1: target_pid
+ for (auto& it : target_pid_) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(1, it, msg);
+ }
+
+ // Field 2: target_cmdline
+ for (auto& it : target_cmdline_) {
+ ::protozero::internal::gen_helpers::SerializeString(2, it, msg);
+ }
+
+ // Field 3: exclude_pid
+ for (auto& it : exclude_pid_) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(3, it, msg);
+ }
+
+ // Field 4: exclude_cmdline
+ for (auto& it : exclude_cmdline_) {
+ ::protozero::internal::gen_helpers::SerializeString(4, it, msg);
+ }
+
+ // Field 5: additional_cmdline_count
if (_has_field_[5]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(5, payload_write_time_ms_, msg);
+ ::protozero::internal::gen_helpers::SerializeVarInt(5, additional_cmdline_count_, msg);
+ }
+
+ // Field 6: process_shard_count
+ if (_has_field_[6]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(6, process_shard_count_, msg);
}
protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
@@ -29769,7 +29209,7 @@ void StressTestConfig_WriterTiming::Serialize(::protozero::Message* msg) const {
#if defined(__GNUC__) || defined(__clang__)
#pragma GCC diagnostic pop
#endif
-// gen_amalgamated begin source: gen/protos/perfetto/config/test_config.gen.cc
+// gen_amalgamated begin source: gen/protos/perfetto/config/profiling/smaps_config.gen.cc
// gen_amalgamated expanded: #include "perfetto/protozero/gen_field_helpers.h"
// gen_amalgamated expanded: #include "perfetto/protozero/message.h"
// gen_amalgamated expanded: #include "perfetto/protozero/packed_repeated_fields.h"
@@ -29780,30 +29220,30 @@ void StressTestConfig_WriterTiming::Serialize(::protozero::Message* msg) const {
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wfloat-equal"
#endif
-// gen_amalgamated expanded: #include "protos/perfetto/config/test_config.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/config/profiling/smaps_config.gen.h"
namespace perfetto {
namespace protos {
namespace gen {
-TestConfig::TestConfig() = default;
-TestConfig::~TestConfig() = default;
-TestConfig::TestConfig(const TestConfig&) = default;
-TestConfig& TestConfig::operator=(const TestConfig&) = default;
-TestConfig::TestConfig(TestConfig&&) noexcept = default;
-TestConfig& TestConfig::operator=(TestConfig&&) = default;
+RedactionRule::RedactionRule() = default;
+RedactionRule::~RedactionRule() = default;
+RedactionRule::RedactionRule(const RedactionRule&) = default;
+RedactionRule& RedactionRule::operator=(const RedactionRule&) = default;
+RedactionRule::RedactionRule(RedactionRule&&) noexcept = default;
+RedactionRule& RedactionRule::operator=(RedactionRule&&) = default;
-bool TestConfig::operator==(const TestConfig& other) const {
+bool RedactionRule::operator==(const RedactionRule& other) const {
return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
- && ::protozero::internal::gen_helpers::EqualsField(message_count_, other.message_count_)
- && ::protozero::internal::gen_helpers::EqualsField(max_messages_per_second_, other.max_messages_per_second_)
- && ::protozero::internal::gen_helpers::EqualsField(seed_, other.seed_)
- && ::protozero::internal::gen_helpers::EqualsField(message_size_, other.message_size_)
- && ::protozero::internal::gen_helpers::EqualsField(send_batch_on_register_, other.send_batch_on_register_)
- && ::protozero::internal::gen_helpers::EqualsField(dummy_fields_, other.dummy_fields_);
+ && ::protozero::internal::gen_helpers::EqualsField(pattern_, other.pattern_)
+ && ::protozero::internal::gen_helpers::EqualsField(match_mode_, other.match_mode_)
+ && ::protozero::internal::gen_helpers::EqualsField(keep_full_, other.keep_full_)
+ && ::protozero::internal::gen_helpers::EqualsField(replacement_name_, other.replacement_name_)
+ && ::protozero::internal::gen_helpers::EqualsField(keep_file_extension_, other.keep_file_extension_)
+ && ::protozero::internal::gen_helpers::EqualsField(keep_path_elements_, other.keep_path_elements_);
}
-bool TestConfig::ParseFromArray(const void* raw, size_t size) {
+bool RedactionRule::ParseFromArray(const void* raw, size_t size) {
unknown_fields_.clear();
bool packed_error = false;
@@ -29813,23 +29253,23 @@ bool TestConfig::ParseFromArray(const void* raw, size_t size) {
_has_field_.set(field.id());
}
switch (field.id()) {
- case 1 /* message_count */:
- field.get(&message_count_);
+ case 1 /* pattern */:
+ ::protozero::internal::gen_helpers::DeserializeString(field, &pattern_);
break;
- case 2 /* max_messages_per_second */:
- field.get(&max_messages_per_second_);
+ case 2 /* match_mode */:
+ field.get(&match_mode_);
break;
- case 3 /* seed */:
- field.get(&seed_);
+ case 3 /* keep_full */:
+ field.get(&keep_full_);
break;
- case 4 /* message_size */:
- field.get(&message_size_);
+ case 4 /* replacement_name */:
+ ::protozero::internal::gen_helpers::DeserializeString(field, &replacement_name_);
break;
- case 5 /* send_batch_on_register */:
- field.get(&send_batch_on_register_);
+ case 5 /* keep_file_extension */:
+ field.get(&keep_file_extension_);
break;
- case 6 /* dummy_fields */:
- (*dummy_fields_).ParseFromArray(field.data(), field.size());
+ case 6 /* keep_path_elements */:
+ field.get(&keep_path_elements_);
break;
default:
field.SerializeAndAppendTo(&unknown_fields_);
@@ -29839,79 +29279,73 @@ bool TestConfig::ParseFromArray(const void* raw, size_t size) {
return !packed_error && !dec.bytes_left();
}
-std::string TestConfig::SerializeAsString() const {
+std::string RedactionRule::SerializeAsString() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsString();
}
-std::vector<uint8_t> TestConfig::SerializeAsArray() const {
+std::vector<uint8_t> RedactionRule::SerializeAsArray() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsArray();
}
-void TestConfig::Serialize(::protozero::Message* msg) const {
- // Field 1: message_count
+void RedactionRule::Serialize(::protozero::Message* msg) const {
+ // Field 1: pattern
if (_has_field_[1]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(1, message_count_, msg);
+ ::protozero::internal::gen_helpers::SerializeString(1, pattern_, msg);
}
- // Field 2: max_messages_per_second
+ // Field 2: match_mode
if (_has_field_[2]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(2, max_messages_per_second_, msg);
+ ::protozero::internal::gen_helpers::SerializeVarInt(2, match_mode_, msg);
}
- // Field 3: seed
+ // Field 3: keep_full
if (_has_field_[3]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(3, seed_, msg);
+ ::protozero::internal::gen_helpers::SerializeTinyVarInt(3, keep_full_, msg);
}
- // Field 4: message_size
+ // Field 4: replacement_name
if (_has_field_[4]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(4, message_size_, msg);
+ ::protozero::internal::gen_helpers::SerializeString(4, replacement_name_, msg);
}
- // Field 5: send_batch_on_register
+ // Field 5: keep_file_extension
if (_has_field_[5]) {
- ::protozero::internal::gen_helpers::SerializeTinyVarInt(5, send_batch_on_register_, msg);
+ ::protozero::internal::gen_helpers::SerializeTinyVarInt(5, keep_file_extension_, msg);
}
- // Field 6: dummy_fields
+ // Field 6: keep_path_elements
if (_has_field_[6]) {
- (*dummy_fields_).Serialize(msg->BeginNestedMessage<::protozero::Message>(6));
+ ::protozero::internal::gen_helpers::SerializeVarInt(6, keep_path_elements_, msg);
}
protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
}
-TestConfig_DummyFields::TestConfig_DummyFields() = default;
-TestConfig_DummyFields::~TestConfig_DummyFields() = default;
-TestConfig_DummyFields::TestConfig_DummyFields(const TestConfig_DummyFields&) = default;
-TestConfig_DummyFields& TestConfig_DummyFields::operator=(const TestConfig_DummyFields&) = default;
-TestConfig_DummyFields::TestConfig_DummyFields(TestConfig_DummyFields&&) noexcept = default;
-TestConfig_DummyFields& TestConfig_DummyFields::operator=(TestConfig_DummyFields&&) = default;
+SmapsConfig::SmapsConfig() = default;
+SmapsConfig::~SmapsConfig() = default;
+SmapsConfig::SmapsConfig(const SmapsConfig&) = default;
+SmapsConfig& SmapsConfig::operator=(const SmapsConfig&) = default;
+SmapsConfig::SmapsConfig(SmapsConfig&&) noexcept = default;
+SmapsConfig& SmapsConfig::operator=(SmapsConfig&&) = default;
-bool TestConfig_DummyFields::operator==(const TestConfig_DummyFields& other) const {
+bool SmapsConfig::operator==(const SmapsConfig& other) const {
return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
- && ::protozero::internal::gen_helpers::EqualsField(field_uint32_, other.field_uint32_)
- && ::protozero::internal::gen_helpers::EqualsField(field_int32_, other.field_int32_)
- && ::protozero::internal::gen_helpers::EqualsField(field_uint64_, other.field_uint64_)
- && ::protozero::internal::gen_helpers::EqualsField(field_int64_, other.field_int64_)
- && ::protozero::internal::gen_helpers::EqualsField(field_fixed64_, other.field_fixed64_)
- && ::protozero::internal::gen_helpers::EqualsField(field_sfixed64_, other.field_sfixed64_)
- && ::protozero::internal::gen_helpers::EqualsField(field_fixed32_, other.field_fixed32_)
- && ::protozero::internal::gen_helpers::EqualsField(field_sfixed32_, other.field_sfixed32_)
- && ::protozero::internal::gen_helpers::EqualsField(field_double_, other.field_double_)
- && ::protozero::internal::gen_helpers::EqualsField(field_float_, other.field_float_)
- && ::protozero::internal::gen_helpers::EqualsField(field_sint64_, other.field_sint64_)
- && ::protozero::internal::gen_helpers::EqualsField(field_sint32_, other.field_sint32_)
- && ::protozero::internal::gen_helpers::EqualsField(field_string_, other.field_string_)
- && ::protozero::internal::gen_helpers::EqualsField(field_bytes_, other.field_bytes_);
+ && ::protozero::internal::gen_helpers::EqualsField(vma_fields_, other.vma_fields_)
+ && ::protozero::internal::gen_helpers::EqualsField(unaggregated_, other.unaggregated_)
+ && ::protozero::internal::gen_helpers::EqualsField(name_redaction_rules_, other.name_redaction_rules_);
}
-bool TestConfig_DummyFields::ParseFromArray(const void* raw, size_t size) {
+int SmapsConfig::name_redaction_rules_size() const { return static_cast<int>(name_redaction_rules_.size()); }
+void SmapsConfig::clear_name_redaction_rules() { name_redaction_rules_.clear(); }
+RedactionRule* SmapsConfig::add_name_redaction_rules() { name_redaction_rules_.emplace_back(); return &name_redaction_rules_.back(); }
+bool SmapsConfig::ParseFromArray(const void* raw, size_t size) {
+ vma_fields_.clear();
+ name_redaction_rules_.clear();
unknown_fields_.clear();
bool packed_error = false;
@@ -29921,47 +29355,16 @@ bool TestConfig_DummyFields::ParseFromArray(const void* raw, size_t size) {
_has_field_.set(field.id());
}
switch (field.id()) {
- case 1 /* field_uint32 */:
- field.get(&field_uint32_);
- break;
- case 2 /* field_int32 */:
- field.get(&field_int32_);
- break;
- case 3 /* field_uint64 */:
- field.get(&field_uint64_);
- break;
- case 4 /* field_int64 */:
- field.get(&field_int64_);
- break;
- case 5 /* field_fixed64 */:
- field.get(&field_fixed64_);
- break;
- case 6 /* field_sfixed64 */:
- field.get(&field_sfixed64_);
- break;
- case 7 /* field_fixed32 */:
- field.get(&field_fixed32_);
- break;
- case 8 /* field_sfixed32 */:
- field.get(&field_sfixed32_);
- break;
- case 9 /* field_double */:
- field.get(&field_double_);
- break;
- case 10 /* field_float */:
- field.get(&field_float_);
- break;
- case 11 /* field_sint64 */:
- field.get_signed(&field_sint64_);
- break;
- case 12 /* field_sint32 */:
- field.get_signed(&field_sint32_);
+ case 1 /* vma_fields */:
+ vma_fields_.emplace_back();
+ field.get(&vma_fields_.back());
break;
- case 13 /* field_string */:
- ::protozero::internal::gen_helpers::DeserializeString(field, &field_string_);
+ case 2 /* unaggregated */:
+ field.get(&unaggregated_);
break;
- case 14 /* field_bytes */:
- field.get(&field_bytes_);
+ case 3 /* name_redaction_rules */:
+ name_redaction_rules_.emplace_back();
+ name_redaction_rules_.back().ParseFromArray(field.data(), field.size());
break;
default:
field.SerializeAndAppendTo(&unknown_fields_);
@@ -29971,87 +29374,258 @@ bool TestConfig_DummyFields::ParseFromArray(const void* raw, size_t size) {
return !packed_error && !dec.bytes_left();
}
-std::string TestConfig_DummyFields::SerializeAsString() const {
+std::string SmapsConfig::SerializeAsString() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsString();
}
-std::vector<uint8_t> TestConfig_DummyFields::SerializeAsArray() const {
+std::vector<uint8_t> SmapsConfig::SerializeAsArray() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsArray();
}
-void TestConfig_DummyFields::Serialize(::protozero::Message* msg) const {
- // Field 1: field_uint32
- if (_has_field_[1]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(1, field_uint32_, msg);
+void SmapsConfig::Serialize(::protozero::Message* msg) const {
+ // Field 1: vma_fields
+ for (auto& it : vma_fields_) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(1, it, msg);
}
- // Field 2: field_int32
+ // Field 2: unaggregated
if (_has_field_[2]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(2, field_int32_, msg);
+ ::protozero::internal::gen_helpers::SerializeTinyVarInt(2, unaggregated_, msg);
}
- // Field 3: field_uint64
- if (_has_field_[3]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(3, field_uint64_, msg);
+ // Field 3: name_redaction_rules
+ for (auto& it : name_redaction_rules_) {
+ it.Serialize(msg->BeginNestedMessage<::protozero::Message>(3));
}
- // Field 4: field_int64
- if (_has_field_[4]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(4, field_int64_, msg);
+ protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
+}
+
+
+ProcessSmapsConfig::ProcessSmapsConfig() = default;
+ProcessSmapsConfig::~ProcessSmapsConfig() = default;
+ProcessSmapsConfig::ProcessSmapsConfig(const ProcessSmapsConfig&) = default;
+ProcessSmapsConfig& ProcessSmapsConfig::operator=(const ProcessSmapsConfig&) = default;
+ProcessSmapsConfig::ProcessSmapsConfig(ProcessSmapsConfig&&) noexcept = default;
+ProcessSmapsConfig& ProcessSmapsConfig::operator=(ProcessSmapsConfig&&) = default;
+
+bool ProcessSmapsConfig::operator==(const ProcessSmapsConfig& other) const {
+ return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
+ && ::protozero::internal::gen_helpers::EqualsField(smaps_config_, other.smaps_config_)
+ && ::protozero::internal::gen_helpers::EqualsField(scope_, other.scope_)
+ && ::protozero::internal::gen_helpers::EqualsField(read_period_ms_, other.read_period_ms_)
+ && ::protozero::internal::gen_helpers::EqualsField(max_processes_per_period_, other.max_processes_per_period_);
+}
+
+bool ProcessSmapsConfig::ParseFromArray(const void* raw, size_t size) {
+ unknown_fields_.clear();
+ bool packed_error = false;
+
+ ::protozero::ProtoDecoder dec(raw, size);
+ for (auto field = dec.ReadField(); field.valid(); field = dec.ReadField()) {
+ if (field.id() < _has_field_.size()) {
+ _has_field_.set(field.id());
+ }
+ switch (field.id()) {
+ case 1 /* smaps_config */:
+ (*smaps_config_).ParseFromArray(field.data(), field.size());
+ break;
+ case 2 /* scope */:
+ (*scope_).ParseFromArray(field.data(), field.size());
+ break;
+ case 3 /* read_period_ms */:
+ field.get(&read_period_ms_);
+ break;
+ case 4 /* max_processes_per_period */:
+ field.get(&max_processes_per_period_);
+ break;
+ default:
+ field.SerializeAndAppendTo(&unknown_fields_);
+ break;
+ }
}
+ return !packed_error && !dec.bytes_left();
+}
- // Field 5: field_fixed64
- if (_has_field_[5]) {
- ::protozero::internal::gen_helpers::SerializeFixed(5, field_fixed64_, msg);
+std::string ProcessSmapsConfig::SerializeAsString() const {
+ ::protozero::internal::gen_helpers::MessageSerializer msg;
+ Serialize(msg.get());
+ return msg.SerializeAsString();
+}
+
+std::vector<uint8_t> ProcessSmapsConfig::SerializeAsArray() const {
+ ::protozero::internal::gen_helpers::MessageSerializer msg;
+ Serialize(msg.get());
+ return msg.SerializeAsArray();
+}
+
+void ProcessSmapsConfig::Serialize(::protozero::Message* msg) const {
+ // Field 1: smaps_config
+ if (_has_field_[1]) {
+ (*smaps_config_).Serialize(msg->BeginNestedMessage<::protozero::Message>(1));
}
- // Field 6: field_sfixed64
- if (_has_field_[6]) {
- ::protozero::internal::gen_helpers::SerializeFixed(6, field_sfixed64_, msg);
+ // Field 2: scope
+ if (_has_field_[2]) {
+ (*scope_).Serialize(msg->BeginNestedMessage<::protozero::Message>(2));
}
- // Field 7: field_fixed32
- if (_has_field_[7]) {
- ::protozero::internal::gen_helpers::SerializeFixed(7, field_fixed32_, msg);
+ // Field 3: read_period_ms
+ if (_has_field_[3]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(3, read_period_ms_, msg);
}
- // Field 8: field_sfixed32
- if (_has_field_[8]) {
- ::protozero::internal::gen_helpers::SerializeFixed(8, field_sfixed32_, msg);
+ // Field 4: max_processes_per_period
+ if (_has_field_[4]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(4, max_processes_per_period_, msg);
}
- // Field 9: field_double
- if (_has_field_[9]) {
- ::protozero::internal::gen_helpers::SerializeFixed(9, field_double_, msg);
+ protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
+}
+
+
+ProcessSmapsConfig_Scope::ProcessSmapsConfig_Scope() = default;
+ProcessSmapsConfig_Scope::~ProcessSmapsConfig_Scope() = default;
+ProcessSmapsConfig_Scope::ProcessSmapsConfig_Scope(const ProcessSmapsConfig_Scope&) = default;
+ProcessSmapsConfig_Scope& ProcessSmapsConfig_Scope::operator=(const ProcessSmapsConfig_Scope&) = default;
+ProcessSmapsConfig_Scope::ProcessSmapsConfig_Scope(ProcessSmapsConfig_Scope&&) noexcept = default;
+ProcessSmapsConfig_Scope& ProcessSmapsConfig_Scope::operator=(ProcessSmapsConfig_Scope&&) = default;
+
+bool ProcessSmapsConfig_Scope::operator==(const ProcessSmapsConfig_Scope& other) const {
+ return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
+ && ::protozero::internal::gen_helpers::EqualsField(target_cmdline_, other.target_cmdline_)
+ && ::protozero::internal::gen_helpers::EqualsField(target_uid_, other.target_uid_);
+}
+
+int ProcessSmapsConfig_Scope::target_uid_size() const { return static_cast<int>(target_uid_.size()); }
+void ProcessSmapsConfig_Scope::clear_target_uid() { target_uid_.clear(); }
+ProcessSmapsConfig_Scope_UidRange* ProcessSmapsConfig_Scope::add_target_uid() { target_uid_.emplace_back(); return &target_uid_.back(); }
+bool ProcessSmapsConfig_Scope::ParseFromArray(const void* raw, size_t size) {
+ target_cmdline_.clear();
+ target_uid_.clear();
+ unknown_fields_.clear();
+ bool packed_error = false;
+
+ ::protozero::ProtoDecoder dec(raw, size);
+ for (auto field = dec.ReadField(); field.valid(); field = dec.ReadField()) {
+ if (field.id() < _has_field_.size()) {
+ _has_field_.set(field.id());
+ }
+ switch (field.id()) {
+ case 1 /* target_cmdline */:
+ target_cmdline_.emplace_back();
+ ::protozero::internal::gen_helpers::DeserializeString(field, &target_cmdline_.back());
+ break;
+ case 2 /* target_uid */:
+ target_uid_.emplace_back();
+ target_uid_.back().ParseFromArray(field.data(), field.size());
+ break;
+ default:
+ field.SerializeAndAppendTo(&unknown_fields_);
+ break;
+ }
}
+ return !packed_error && !dec.bytes_left();
+}
- // Field 10: field_float
- if (_has_field_[10]) {
- ::protozero::internal::gen_helpers::SerializeFixed(10, field_float_, msg);
+std::string ProcessSmapsConfig_Scope::SerializeAsString() const {
+ ::protozero::internal::gen_helpers::MessageSerializer msg;
+ Serialize(msg.get());
+ return msg.SerializeAsString();
+}
+
+std::vector<uint8_t> ProcessSmapsConfig_Scope::SerializeAsArray() const {
+ ::protozero::internal::gen_helpers::MessageSerializer msg;
+ Serialize(msg.get());
+ return msg.SerializeAsArray();
+}
+
+void ProcessSmapsConfig_Scope::Serialize(::protozero::Message* msg) const {
+ // Field 1: target_cmdline
+ for (auto& it : target_cmdline_) {
+ ::protozero::internal::gen_helpers::SerializeString(1, it, msg);
}
- // Field 11: field_sint64
- if (_has_field_[11]) {
- ::protozero::internal::gen_helpers::SerializeSignedVarInt(11, field_sint64_, msg);
+ // Field 2: target_uid
+ for (auto& it : target_uid_) {
+ it.Serialize(msg->BeginNestedMessage<::protozero::Message>(2));
}
- // Field 12: field_sint32
- if (_has_field_[12]) {
- ::protozero::internal::gen_helpers::SerializeSignedVarInt(12, field_sint32_, msg);
+ protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
+}
+
+
+ProcessSmapsConfig_Scope_UidRange::ProcessSmapsConfig_Scope_UidRange() = default;
+ProcessSmapsConfig_Scope_UidRange::~ProcessSmapsConfig_Scope_UidRange() = default;
+ProcessSmapsConfig_Scope_UidRange::ProcessSmapsConfig_Scope_UidRange(const ProcessSmapsConfig_Scope_UidRange&) = default;
+ProcessSmapsConfig_Scope_UidRange& ProcessSmapsConfig_Scope_UidRange::operator=(const ProcessSmapsConfig_Scope_UidRange&) = default;
+ProcessSmapsConfig_Scope_UidRange::ProcessSmapsConfig_Scope_UidRange(ProcessSmapsConfig_Scope_UidRange&&) noexcept = default;
+ProcessSmapsConfig_Scope_UidRange& ProcessSmapsConfig_Scope_UidRange::operator=(ProcessSmapsConfig_Scope_UidRange&&) = default;
+
+bool ProcessSmapsConfig_Scope_UidRange::operator==(const ProcessSmapsConfig_Scope_UidRange& other) const {
+ return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
+ && ::protozero::internal::gen_helpers::EqualsField(min_uid_, other.min_uid_)
+ && ::protozero::internal::gen_helpers::EqualsField(max_uid_, other.max_uid_)
+ && ::protozero::internal::gen_helpers::EqualsField(android_match_across_profiles_, other.android_match_across_profiles_);
+}
+
+bool ProcessSmapsConfig_Scope_UidRange::ParseFromArray(const void* raw, size_t size) {
+ unknown_fields_.clear();
+ bool packed_error = false;
+
+ ::protozero::ProtoDecoder dec(raw, size);
+ for (auto field = dec.ReadField(); field.valid(); field = dec.ReadField()) {
+ if (field.id() < _has_field_.size()) {
+ _has_field_.set(field.id());
+ }
+ switch (field.id()) {
+ case 1 /* min_uid */:
+ field.get(&min_uid_);
+ break;
+ case 2 /* max_uid */:
+ field.get(&max_uid_);
+ break;
+ case 3 /* android_match_across_profiles */:
+ field.get(&android_match_across_profiles_);
+ break;
+ default:
+ field.SerializeAndAppendTo(&unknown_fields_);
+ break;
+ }
}
+ return !packed_error && !dec.bytes_left();
+}
- // Field 13: field_string
- if (_has_field_[13]) {
- ::protozero::internal::gen_helpers::SerializeString(13, field_string_, msg);
+std::string ProcessSmapsConfig_Scope_UidRange::SerializeAsString() const {
+ ::protozero::internal::gen_helpers::MessageSerializer msg;
+ Serialize(msg.get());
+ return msg.SerializeAsString();
+}
+
+std::vector<uint8_t> ProcessSmapsConfig_Scope_UidRange::SerializeAsArray() const {
+ ::protozero::internal::gen_helpers::MessageSerializer msg;
+ Serialize(msg.get());
+ return msg.SerializeAsArray();
+}
+
+void ProcessSmapsConfig_Scope_UidRange::Serialize(::protozero::Message* msg) const {
+ // Field 1: min_uid
+ if (_has_field_[1]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(1, min_uid_, msg);
}
- // Field 14: field_bytes
- if (_has_field_[14]) {
- ::protozero::internal::gen_helpers::SerializeString(14, field_bytes_, msg);
+ // Field 2: max_uid
+ if (_has_field_[2]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(2, max_uid_, msg);
+ }
+
+ // Field 3: android_match_across_profiles
+ if (_has_field_[3]) {
+ ::protozero::internal::gen_helpers::SerializeTinyVarInt(3, android_match_across_profiles_, msg);
}
protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
@@ -30063,7 +29637,7 @@ void TestConfig_DummyFields::Serialize(::protozero::Message* msg) const {
#if defined(__GNUC__) || defined(__clang__)
#pragma GCC diagnostic pop
#endif
-// gen_amalgamated begin source: gen/protos/perfetto/config/trace_config.gen.cc
+// gen_amalgamated begin source: gen/protos/perfetto/config/protovm/protovm_config.gen.cc
// gen_amalgamated expanded: #include "perfetto/protozero/gen_field_helpers.h"
// gen_amalgamated expanded: #include "perfetto/protozero/message.h"
// gen_amalgamated expanded: #include "perfetto/protozero/packed_repeated_fields.h"
@@ -30074,139 +29648,25 @@ void TestConfig_DummyFields::Serialize(::protozero::Message* msg) const {
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wfloat-equal"
#endif
-// gen_amalgamated expanded: #include "protos/perfetto/config/trace_config.gen.h"
-// gen_amalgamated expanded: #include "protos/perfetto/config/priority_boost/priority_boost_config.gen.h"
-// gen_amalgamated expanded: #include "protos/perfetto/config/data_source_config.gen.h"
-// gen_amalgamated expanded: #include "protos/perfetto/config/qnx/qnx_config.gen.h"
-// gen_amalgamated expanded: #include "protos/perfetto/config/linux/journald_config.gen.h"
-// gen_amalgamated expanded: #include "protos/perfetto/config/chrome/histogram_samples.gen.h"
-// gen_amalgamated expanded: #include "protos/perfetto/config/system_info/system_info_config.gen.h"
-// gen_amalgamated expanded: #include "protos/perfetto/config/track_event/track_event_config.gen.h"
-// gen_amalgamated expanded: #include "protos/perfetto/config/test_config.gen.h"
-// gen_amalgamated expanded: #include "protos/perfetto/config/sys_stats/sys_stats_config.gen.h"
-// gen_amalgamated expanded: #include "protos/perfetto/common/sys_stats_counters.gen.h"
-// gen_amalgamated expanded: #include "protos/perfetto/config/profiling/perf_event_config.gen.h"
-// gen_amalgamated expanded: #include "protos/perfetto/common/perf_events.gen.h"
-// gen_amalgamated expanded: #include "protos/perfetto/config/profiling/java_hprof_config.gen.h"
-// gen_amalgamated expanded: #include "protos/perfetto/config/profiling/smaps_config.gen.h"
-// gen_amalgamated expanded: #include "protos/perfetto/config/profiling/heapprofd_config.gen.h"
-// gen_amalgamated expanded: #include "protos/perfetto/config/process_stats/process_stats_config.gen.h"
-// gen_amalgamated expanded: #include "protos/perfetto/config/statsd/statsd_tracing_config.gen.h"
-// gen_amalgamated expanded: #include "protos/perfetto/config/statsd/atom_ids.gen.h"
// gen_amalgamated expanded: #include "protos/perfetto/config/protovm/protovm_config.gen.h"
-// gen_amalgamated expanded: #include "protos/perfetto/config/power/android_power_config.gen.h"
-// gen_amalgamated expanded: #include "protos/perfetto/config/interceptor_config.gen.h"
-// gen_amalgamated expanded: #include "protos/perfetto/config/interceptors/console_config.gen.h"
-// gen_amalgamated expanded: #include "protos/perfetto/config/inode_file/inode_file_config.gen.h"
-// gen_amalgamated expanded: #include "protos/perfetto/config/gpu/gpu_renderstages_config.gen.h"
-// gen_amalgamated expanded: #include "protos/perfetto/config/gpu/vulkan_memory_config.gen.h"
-// gen_amalgamated expanded: #include "protos/perfetto/config/gpu/gpu_counter_config.gen.h"
-// gen_amalgamated expanded: #include "protos/perfetto/config/ftrace/frozen_ftrace_config.gen.h"
-// gen_amalgamated expanded: #include "protos/perfetto/config/ftrace/ftrace_config.gen.h"
-// gen_amalgamated expanded: #include "protos/perfetto/config/chrome/system_metrics.gen.h"
-// gen_amalgamated expanded: #include "protos/perfetto/config/etw/etw_config.gen.h"
-// gen_amalgamated expanded: #include "protos/perfetto/config/chrome/v8_config.gen.h"
-// gen_amalgamated expanded: #include "protos/perfetto/config/chrome/chrome_config.gen.h"
-// gen_amalgamated expanded: #include "protos/perfetto/config/android/windowmanager_config.gen.h"
-// gen_amalgamated expanded: #include "protos/perfetto/config/android/user_list_config.gen.h"
-// gen_amalgamated expanded: #include "protos/perfetto/config/android/surfaceflinger_transactions_config.gen.h"
-// gen_amalgamated expanded: #include "protos/perfetto/config/android/surfaceflinger_layers_config.gen.h"
-// gen_amalgamated expanded: #include "protos/perfetto/config/android/display_video_config.gen.h"
-// gen_amalgamated expanded: #include "protos/perfetto/config/android/protolog_config.gen.h"
-// gen_amalgamated expanded: #include "protos/perfetto/config/android/pixel_modem_config.gen.h"
-// gen_amalgamated expanded: #include "protos/perfetto/config/android/packages_list_config.gen.h"
-// gen_amalgamated expanded: #include "protos/perfetto/config/android/network_trace_config.gen.h"
-// gen_amalgamated expanded: #include "protos/perfetto/config/android/kernel_wakelocks_config.gen.h"
-// gen_amalgamated expanded: #include "protos/perfetto/config/android/inputmethod_config.gen.h"
-// gen_amalgamated expanded: #include "protos/perfetto/config/android/cpu_per_uid_config.gen.h"
-// gen_amalgamated expanded: #include "protos/perfetto/config/android/app_wakelock_config.gen.h"
-// gen_amalgamated expanded: #include "protos/perfetto/config/android/android_sdk_sysprop_guard_config.gen.h"
-// gen_amalgamated expanded: #include "protos/perfetto/config/android/android_system_property_config.gen.h"
-// gen_amalgamated expanded: #include "protos/perfetto/config/android/android_polled_state_config.gen.h"
-// gen_amalgamated expanded: #include "protos/perfetto/config/android/android_log_config.gen.h"
-// gen_amalgamated expanded: #include "protos/perfetto/common/android_log_constants.gen.h"
-// gen_amalgamated expanded: #include "protos/perfetto/config/android/android_input_event_config.gen.h"
-// gen_amalgamated expanded: #include "protos/perfetto/config/android/android_game_intervention_list_config.gen.h"
-// gen_amalgamated expanded: #include "protos/perfetto/config/android/android_aflags_config.gen.h"
-// gen_amalgamated expanded: #include "protos/perfetto/common/trace_attributes.gen.h"
-// gen_amalgamated expanded: #include "protos/perfetto/common/semantic_type.gen.h"
-// gen_amalgamated expanded: #include "protos/perfetto/common/builtin_clock.gen.h"
namespace perfetto {
namespace protos {
namespace gen {
-TraceConfig::TraceConfig() = default;
-TraceConfig::~TraceConfig() = default;
-TraceConfig::TraceConfig(const TraceConfig&) = default;
-TraceConfig& TraceConfig::operator=(const TraceConfig&) = default;
-TraceConfig::TraceConfig(TraceConfig&&) noexcept = default;
-TraceConfig& TraceConfig::operator=(TraceConfig&&) = default;
+ProtoVmConfig::ProtoVmConfig() = default;
+ProtoVmConfig::~ProtoVmConfig() = default;
+ProtoVmConfig::ProtoVmConfig(const ProtoVmConfig&) = default;
+ProtoVmConfig& ProtoVmConfig::operator=(const ProtoVmConfig&) = default;
+ProtoVmConfig::ProtoVmConfig(ProtoVmConfig&&) noexcept = default;
+ProtoVmConfig& ProtoVmConfig::operator=(ProtoVmConfig&&) = default;
-bool TraceConfig::operator==(const TraceConfig& other) const {
+bool ProtoVmConfig::operator==(const ProtoVmConfig& other) const {
return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
- && ::protozero::internal::gen_helpers::EqualsField(buffers_, other.buffers_)
- && ::protozero::internal::gen_helpers::EqualsField(data_sources_, other.data_sources_)
- && ::protozero::internal::gen_helpers::EqualsField(builtin_data_sources_, other.builtin_data_sources_)
- && ::protozero::internal::gen_helpers::EqualsField(duration_ms_, other.duration_ms_)
- && ::protozero::internal::gen_helpers::EqualsField(prefer_suspend_clock_for_duration_, other.prefer_suspend_clock_for_duration_)
- && ::protozero::internal::gen_helpers::EqualsField(enable_extra_guardrails_, other.enable_extra_guardrails_)
- && ::protozero::internal::gen_helpers::EqualsField(lockdown_mode_, other.lockdown_mode_)
- && ::protozero::internal::gen_helpers::EqualsField(producers_, other.producers_)
- && ::protozero::internal::gen_helpers::EqualsField(statsd_metadata_, other.statsd_metadata_)
- && ::protozero::internal::gen_helpers::EqualsField(write_into_file_, other.write_into_file_)
- && ::protozero::internal::gen_helpers::EqualsField(output_path_, other.output_path_)
- && ::protozero::internal::gen_helpers::EqualsField(file_write_period_ms_, other.file_write_period_ms_)
- && ::protozero::internal::gen_helpers::EqualsField(max_file_size_bytes_, other.max_file_size_bytes_)
- && ::protozero::internal::gen_helpers::EqualsField(guardrail_overrides_, other.guardrail_overrides_)
- && ::protozero::internal::gen_helpers::EqualsField(deferred_start_, other.deferred_start_)
- && ::protozero::internal::gen_helpers::EqualsField(flush_period_ms_, other.flush_period_ms_)
- && ::protozero::internal::gen_helpers::EqualsField(flush_timeout_ms_, other.flush_timeout_ms_)
- && ::protozero::internal::gen_helpers::EqualsField(data_source_stop_timeout_ms_, other.data_source_stop_timeout_ms_)
- && ::protozero::internal::gen_helpers::EqualsField(notify_traceur_, other.notify_traceur_)
- && ::protozero::internal::gen_helpers::EqualsField(bugreport_score_, other.bugreport_score_)
- && ::protozero::internal::gen_helpers::EqualsField(bugreport_filename_, other.bugreport_filename_)
- && ::protozero::internal::gen_helpers::EqualsField(trigger_config_, other.trigger_config_)
- && ::protozero::internal::gen_helpers::EqualsField(activate_triggers_, other.activate_triggers_)
- && ::protozero::internal::gen_helpers::EqualsField(incremental_state_config_, other.incremental_state_config_)
- && ::protozero::internal::gen_helpers::EqualsField(allow_user_build_tracing_, other.allow_user_build_tracing_)
- && ::protozero::internal::gen_helpers::EqualsField(unique_session_name_, other.unique_session_name_)
- && ::protozero::internal::gen_helpers::EqualsField(compression_type_, other.compression_type_)
- && ::protozero::internal::gen_helpers::EqualsField(compression_, other.compression_)
- && ::protozero::internal::gen_helpers::EqualsField(incident_report_config_, other.incident_report_config_)
- && ::protozero::internal::gen_helpers::EqualsField(statsd_logging_, other.statsd_logging_)
- && ::protozero::internal::gen_helpers::EqualsField(trace_uuid_msb_, other.trace_uuid_msb_)
- && ::protozero::internal::gen_helpers::EqualsField(trace_uuid_lsb_, other.trace_uuid_lsb_)
- && ::protozero::internal::gen_helpers::EqualsField(trace_filter_, other.trace_filter_)
- && ::protozero::internal::gen_helpers::EqualsField(android_report_config_, other.android_report_config_)
- && ::protozero::internal::gen_helpers::EqualsField(cmd_trace_start_delay_, other.cmd_trace_start_delay_)
- && ::protozero::internal::gen_helpers::EqualsField(session_semaphores_, other.session_semaphores_)
- && ::protozero::internal::gen_helpers::EqualsField(priority_boost_, other.priority_boost_)
- && ::protozero::internal::gen_helpers::EqualsField(exclusive_prio_, other.exclusive_prio_)
- && ::protozero::internal::gen_helpers::EqualsField(write_flush_mode_, other.write_flush_mode_)
- && ::protozero::internal::gen_helpers::EqualsField(fflush_post_write_, other.fflush_post_write_)
- && ::protozero::internal::gen_helpers::EqualsField(trace_all_machines_, other.trace_all_machines_)
- && ::protozero::internal::gen_helpers::EqualsField(trace_attributes_, other.trace_attributes_);
+ && ::protozero::internal::gen_helpers::EqualsField(memory_limit_kb_, other.memory_limit_kb_);
}
-int TraceConfig::buffers_size() const { return static_cast<int>(buffers_.size()); }
-void TraceConfig::clear_buffers() { buffers_.clear(); }
-TraceConfig_BufferConfig* TraceConfig::add_buffers() { buffers_.emplace_back(); return &buffers_.back(); }
-int TraceConfig::data_sources_size() const { return static_cast<int>(data_sources_.size()); }
-void TraceConfig::clear_data_sources() { data_sources_.clear(); }
-TraceConfig_DataSource* TraceConfig::add_data_sources() { data_sources_.emplace_back(); return &data_sources_.back(); }
-int TraceConfig::producers_size() const { return static_cast<int>(producers_.size()); }
-void TraceConfig::clear_producers() { producers_.clear(); }
-TraceConfig_ProducerConfig* TraceConfig::add_producers() { producers_.emplace_back(); return &producers_.back(); }
-int TraceConfig::session_semaphores_size() const { return static_cast<int>(session_semaphores_.size()); }
-void TraceConfig::clear_session_semaphores() { session_semaphores_.clear(); }
-TraceConfig_SessionSemaphore* TraceConfig::add_session_semaphores() { session_semaphores_.emplace_back(); return &session_semaphores_.back(); }
-bool TraceConfig::ParseFromArray(const void* raw, size_t size) {
- buffers_.clear();
- data_sources_.clear();
- producers_.clear();
- activate_triggers_.clear();
- session_semaphores_.clear();
+bool ProtoVmConfig::ParseFromArray(const void* raw, size_t size) {
unknown_fields_.clear();
bool packed_error = false;
@@ -30216,136 +29676,8 @@ bool TraceConfig::ParseFromArray(const void* raw, size_t size) {
_has_field_.set(field.id());
}
switch (field.id()) {
- case 1 /* buffers */:
- buffers_.emplace_back();
- buffers_.back().ParseFromArray(field.data(), field.size());
- break;
- case 2 /* data_sources */:
- data_sources_.emplace_back();
- data_sources_.back().ParseFromArray(field.data(), field.size());
- break;
- case 20 /* builtin_data_sources */:
- (*builtin_data_sources_).ParseFromArray(field.data(), field.size());
- break;
- case 3 /* duration_ms */:
- field.get(&duration_ms_);
- break;
- case 36 /* prefer_suspend_clock_for_duration */:
- field.get(&prefer_suspend_clock_for_duration_);
- break;
- case 4 /* enable_extra_guardrails */:
- field.get(&enable_extra_guardrails_);
- break;
- case 5 /* lockdown_mode */:
- field.get(&lockdown_mode_);
- break;
- case 6 /* producers */:
- producers_.emplace_back();
- producers_.back().ParseFromArray(field.data(), field.size());
- break;
- case 7 /* statsd_metadata */:
- (*statsd_metadata_).ParseFromArray(field.data(), field.size());
- break;
- case 8 /* write_into_file */:
- field.get(&write_into_file_);
- break;
- case 29 /* output_path */:
- ::protozero::internal::gen_helpers::DeserializeString(field, &output_path_);
- break;
- case 9 /* file_write_period_ms */:
- field.get(&file_write_period_ms_);
- break;
- case 10 /* max_file_size_bytes */:
- field.get(&max_file_size_bytes_);
- break;
- case 11 /* guardrail_overrides */:
- (*guardrail_overrides_).ParseFromArray(field.data(), field.size());
- break;
- case 12 /* deferred_start */:
- field.get(&deferred_start_);
- break;
- case 13 /* flush_period_ms */:
- field.get(&flush_period_ms_);
- break;
- case 14 /* flush_timeout_ms */:
- field.get(&flush_timeout_ms_);
- break;
- case 23 /* data_source_stop_timeout_ms */:
- field.get(&data_source_stop_timeout_ms_);
- break;
- case 16 /* notify_traceur */:
- field.get(¬ify_traceur_);
- break;
- case 30 /* bugreport_score */:
- field.get(&bugreport_score_);
- break;
- case 38 /* bugreport_filename */:
- ::protozero::internal::gen_helpers::DeserializeString(field, &bugreport_filename_);
- break;
- case 17 /* trigger_config */:
- (*trigger_config_).ParseFromArray(field.data(), field.size());
- break;
- case 18 /* activate_triggers */:
- activate_triggers_.emplace_back();
- ::protozero::internal::gen_helpers::DeserializeString(field, &activate_triggers_.back());
- break;
- case 21 /* incremental_state_config */:
- (*incremental_state_config_).ParseFromArray(field.data(), field.size());
- break;
- case 19 /* allow_user_build_tracing */:
- field.get(&allow_user_build_tracing_);
- break;
- case 22 /* unique_session_name */:
- ::protozero::internal::gen_helpers::DeserializeString(field, &unique_session_name_);
- break;
- case 24 /* compression_type */:
- field.get(&compression_type_);
- break;
- case 47 /* compression */:
- (*compression_).ParseFromArray(field.data(), field.size());
- break;
- case 25 /* incident_report_config */:
- (*incident_report_config_).ParseFromArray(field.data(), field.size());
- break;
- case 31 /* statsd_logging */:
- field.get(&statsd_logging_);
- break;
- case 27 /* trace_uuid_msb */:
- field.get(&trace_uuid_msb_);
- break;
- case 28 /* trace_uuid_lsb */:
- field.get(&trace_uuid_lsb_);
- break;
- case 33 /* trace_filter */:
- (*trace_filter_).ParseFromArray(field.data(), field.size());
- break;
- case 34 /* android_report_config */:
- (*android_report_config_).ParseFromArray(field.data(), field.size());
- break;
- case 35 /* cmd_trace_start_delay */:
- (*cmd_trace_start_delay_).ParseFromArray(field.data(), field.size());
- break;
- case 39 /* session_semaphores */:
- session_semaphores_.emplace_back();
- session_semaphores_.back().ParseFromArray(field.data(), field.size());
- break;
- case 40 /* priority_boost */:
- (*priority_boost_).ParseFromArray(field.data(), field.size());
- break;
- case 41 /* exclusive_prio */:
- field.get(&exclusive_prio_);
- break;
- case 44 /* write_flush_mode */:
- field.get(&write_flush_mode_);
- break;
- case 45 /* fflush_post_write */:
- field.get(&fflush_post_write_);
- break;
- case 43 /* trace_all_machines */:
- field.get(&trace_all_machines_);
- break;
- case 48 /* trace_attributes */:
- (*trace_attributes_).ParseFromArray(field.data(), field.size());
+ case 1 /* memory_limit_kb */:
+ field.get(&memory_limit_kb_);
break;
default:
field.SerializeAndAppendTo(&unknown_fields_);
@@ -30355,247 +29687,68 @@ bool TraceConfig::ParseFromArray(const void* raw, size_t size) {
return !packed_error && !dec.bytes_left();
}
-std::string TraceConfig::SerializeAsString() const {
+std::string ProtoVmConfig::SerializeAsString() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsString();
}
-std::vector<uint8_t> TraceConfig::SerializeAsArray() const {
+std::vector<uint8_t> ProtoVmConfig::SerializeAsArray() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsArray();
}
-void TraceConfig::Serialize(::protozero::Message* msg) const {
- // Field 1: buffers
- for (auto& it : buffers_) {
- it.Serialize(msg->BeginNestedMessage<::protozero::Message>(1));
+void ProtoVmConfig::Serialize(::protozero::Message* msg) const {
+ // Field 1: memory_limit_kb
+ if (_has_field_[1]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(1, memory_limit_kb_, msg);
}
- // Field 2: data_sources
- for (auto& it : data_sources_) {
- it.Serialize(msg->BeginNestedMessage<::protozero::Message>(2));
- }
+ protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
+}
- // Field 20: builtin_data_sources
- if (_has_field_[20]) {
- (*builtin_data_sources_).Serialize(msg->BeginNestedMessage<::protozero::Message>(20));
- }
+} // namespace perfetto
+} // namespace protos
+} // namespace gen
+#if defined(__GNUC__) || defined(__clang__)
+#pragma GCC diagnostic pop
+#endif
+// gen_amalgamated begin source: gen/protos/perfetto/config/qnx/qnx_config.gen.cc
+// gen_amalgamated expanded: #include "perfetto/protozero/gen_field_helpers.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/message.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/packed_repeated_fields.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/proto_decoder.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/scattered_heap_buffer.h"
+// DO NOT EDIT. Autogenerated by Perfetto cppgen_plugin
+#if defined(__GNUC__) || defined(__clang__)
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wfloat-equal"
+#endif
+// gen_amalgamated expanded: #include "protos/perfetto/config/qnx/qnx_config.gen.h"
- // Field 3: duration_ms
- if (_has_field_[3]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(3, duration_ms_, msg);
- }
+namespace perfetto {
+namespace protos {
+namespace gen {
- // Field 36: prefer_suspend_clock_for_duration
- if (_has_field_[36]) {
- ::protozero::internal::gen_helpers::SerializeTinyVarInt(36, prefer_suspend_clock_for_duration_, msg);
- }
+QnxConfig::QnxConfig() = default;
+QnxConfig::~QnxConfig() = default;
+QnxConfig::QnxConfig(const QnxConfig&) = default;
+QnxConfig& QnxConfig::operator=(const QnxConfig&) = default;
+QnxConfig::QnxConfig(QnxConfig&&) noexcept = default;
+QnxConfig& QnxConfig::operator=(QnxConfig&&) = default;
- // Field 4: enable_extra_guardrails
- if (_has_field_[4]) {
- ::protozero::internal::gen_helpers::SerializeTinyVarInt(4, enable_extra_guardrails_, msg);
- }
+bool QnxConfig::operator==(const QnxConfig& other) const {
+ return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
+ && ::protozero::internal::gen_helpers::EqualsField(qnx_kernel_buffers_, other.qnx_kernel_buffers_)
+ && ::protozero::internal::gen_helpers::EqualsField(qnx_kernel_kbuffers_, other.qnx_kernel_kbuffers_)
+ && ::protozero::internal::gen_helpers::EqualsField(qnx_kernel_wide_events_, other.qnx_kernel_wide_events_)
+ && ::protozero::internal::gen_helpers::EqualsField(qnx_cache_pages_, other.qnx_cache_pages_)
+ && ::protozero::internal::gen_helpers::EqualsField(qnx_cache_max_pages_, other.qnx_cache_max_pages_)
+ && ::protozero::internal::gen_helpers::EqualsField(qnx_trace_buffer_init_bytes_, other.qnx_trace_buffer_init_bytes_);
+}
- // Field 5: lockdown_mode
- if (_has_field_[5]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(5, lockdown_mode_, msg);
- }
-
- // Field 6: producers
- for (auto& it : producers_) {
- it.Serialize(msg->BeginNestedMessage<::protozero::Message>(6));
- }
-
- // Field 7: statsd_metadata
- if (_has_field_[7]) {
- (*statsd_metadata_).Serialize(msg->BeginNestedMessage<::protozero::Message>(7));
- }
-
- // Field 8: write_into_file
- if (_has_field_[8]) {
- ::protozero::internal::gen_helpers::SerializeTinyVarInt(8, write_into_file_, msg);
- }
-
- // Field 29: output_path
- if (_has_field_[29]) {
- ::protozero::internal::gen_helpers::SerializeString(29, output_path_, msg);
- }
-
- // Field 9: file_write_period_ms
- if (_has_field_[9]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(9, file_write_period_ms_, msg);
- }
-
- // Field 10: max_file_size_bytes
- if (_has_field_[10]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(10, max_file_size_bytes_, msg);
- }
-
- // Field 11: guardrail_overrides
- if (_has_field_[11]) {
- (*guardrail_overrides_).Serialize(msg->BeginNestedMessage<::protozero::Message>(11));
- }
-
- // Field 12: deferred_start
- if (_has_field_[12]) {
- ::protozero::internal::gen_helpers::SerializeTinyVarInt(12, deferred_start_, msg);
- }
-
- // Field 13: flush_period_ms
- if (_has_field_[13]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(13, flush_period_ms_, msg);
- }
-
- // Field 14: flush_timeout_ms
- if (_has_field_[14]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(14, flush_timeout_ms_, msg);
- }
-
- // Field 23: data_source_stop_timeout_ms
- if (_has_field_[23]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(23, data_source_stop_timeout_ms_, msg);
- }
-
- // Field 16: notify_traceur
- if (_has_field_[16]) {
- ::protozero::internal::gen_helpers::SerializeTinyVarInt(16, notify_traceur_, msg);
- }
-
- // Field 30: bugreport_score
- if (_has_field_[30]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(30, bugreport_score_, msg);
- }
-
- // Field 38: bugreport_filename
- if (_has_field_[38]) {
- ::protozero::internal::gen_helpers::SerializeString(38, bugreport_filename_, msg);
- }
-
- // Field 17: trigger_config
- if (_has_field_[17]) {
- (*trigger_config_).Serialize(msg->BeginNestedMessage<::protozero::Message>(17));
- }
-
- // Field 18: activate_triggers
- for (auto& it : activate_triggers_) {
- ::protozero::internal::gen_helpers::SerializeString(18, it, msg);
- }
-
- // Field 21: incremental_state_config
- if (_has_field_[21]) {
- (*incremental_state_config_).Serialize(msg->BeginNestedMessage<::protozero::Message>(21));
- }
-
- // Field 19: allow_user_build_tracing
- if (_has_field_[19]) {
- ::protozero::internal::gen_helpers::SerializeTinyVarInt(19, allow_user_build_tracing_, msg);
- }
-
- // Field 22: unique_session_name
- if (_has_field_[22]) {
- ::protozero::internal::gen_helpers::SerializeString(22, unique_session_name_, msg);
- }
-
- // Field 24: compression_type
- if (_has_field_[24]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(24, compression_type_, msg);
- }
-
- // Field 47: compression
- if (_has_field_[47]) {
- (*compression_).Serialize(msg->BeginNestedMessage<::protozero::Message>(47));
- }
-
- // Field 25: incident_report_config
- if (_has_field_[25]) {
- (*incident_report_config_).Serialize(msg->BeginNestedMessage<::protozero::Message>(25));
- }
-
- // Field 31: statsd_logging
- if (_has_field_[31]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(31, statsd_logging_, msg);
- }
-
- // Field 27: trace_uuid_msb
- if (_has_field_[27]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(27, trace_uuid_msb_, msg);
- }
-
- // Field 28: trace_uuid_lsb
- if (_has_field_[28]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(28, trace_uuid_lsb_, msg);
- }
-
- // Field 33: trace_filter
- if (_has_field_[33]) {
- (*trace_filter_).Serialize(msg->BeginNestedMessage<::protozero::Message>(33));
- }
-
- // Field 34: android_report_config
- if (_has_field_[34]) {
- (*android_report_config_).Serialize(msg->BeginNestedMessage<::protozero::Message>(34));
- }
-
- // Field 35: cmd_trace_start_delay
- if (_has_field_[35]) {
- (*cmd_trace_start_delay_).Serialize(msg->BeginNestedMessage<::protozero::Message>(35));
- }
-
- // Field 39: session_semaphores
- for (auto& it : session_semaphores_) {
- it.Serialize(msg->BeginNestedMessage<::protozero::Message>(39));
- }
-
- // Field 40: priority_boost
- if (_has_field_[40]) {
- (*priority_boost_).Serialize(msg->BeginNestedMessage<::protozero::Message>(40));
- }
-
- // Field 41: exclusive_prio
- if (_has_field_[41]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(41, exclusive_prio_, msg);
- }
-
- // Field 44: write_flush_mode
- if (_has_field_[44]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(44, write_flush_mode_, msg);
- }
-
- // Field 45: fflush_post_write
- if (_has_field_[45]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(45, fflush_post_write_, msg);
- }
-
- // Field 43: trace_all_machines
- if (_has_field_[43]) {
- ::protozero::internal::gen_helpers::SerializeTinyVarInt(43, trace_all_machines_, msg);
- }
-
- // Field 48: trace_attributes
- if (_has_field_[48]) {
- (*trace_attributes_).Serialize(msg->BeginNestedMessage<::protozero::Message>(48));
- }
-
- protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
-}
-
-
-TraceConfig_SessionSemaphore::TraceConfig_SessionSemaphore() = default;
-TraceConfig_SessionSemaphore::~TraceConfig_SessionSemaphore() = default;
-TraceConfig_SessionSemaphore::TraceConfig_SessionSemaphore(const TraceConfig_SessionSemaphore&) = default;
-TraceConfig_SessionSemaphore& TraceConfig_SessionSemaphore::operator=(const TraceConfig_SessionSemaphore&) = default;
-TraceConfig_SessionSemaphore::TraceConfig_SessionSemaphore(TraceConfig_SessionSemaphore&&) noexcept = default;
-TraceConfig_SessionSemaphore& TraceConfig_SessionSemaphore::operator=(TraceConfig_SessionSemaphore&&) = default;
-
-bool TraceConfig_SessionSemaphore::operator==(const TraceConfig_SessionSemaphore& other) const {
- return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
- && ::protozero::internal::gen_helpers::EqualsField(name_, other.name_)
- && ::protozero::internal::gen_helpers::EqualsField(max_other_session_count_, other.max_other_session_count_);
-}
-
-bool TraceConfig_SessionSemaphore::ParseFromArray(const void* raw, size_t size) {
+bool QnxConfig::ParseFromArray(const void* raw, size_t size) {
unknown_fields_.clear();
bool packed_error = false;
@@ -30605,11 +29758,23 @@ bool TraceConfig_SessionSemaphore::ParseFromArray(const void* raw, size_t size)
_has_field_.set(field.id());
}
switch (field.id()) {
- case 1 /* name */:
- ::protozero::internal::gen_helpers::DeserializeString(field, &name_);
+ case 1 /* qnx_kernel_buffers */:
+ field.get(&qnx_kernel_buffers_);
break;
- case 2 /* max_other_session_count */:
- field.get(&max_other_session_count_);
+ case 2 /* qnx_kernel_kbuffers */:
+ field.get(&qnx_kernel_kbuffers_);
+ break;
+ case 3 /* qnx_kernel_wide_events */:
+ field.get(&qnx_kernel_wide_events_);
+ break;
+ case 4 /* qnx_cache_pages */:
+ field.get(&qnx_cache_pages_);
+ break;
+ case 5 /* qnx_cache_max_pages */:
+ field.get(&qnx_cache_max_pages_);
+ break;
+ case 6 /* qnx_trace_buffer_init_bytes */:
+ field.get(&qnx_trace_buffer_init_bytes_);
break;
default:
field.SerializeAndAppendTo(&unknown_fields_);
@@ -30619,47 +29784,117 @@ bool TraceConfig_SessionSemaphore::ParseFromArray(const void* raw, size_t size)
return !packed_error && !dec.bytes_left();
}
-std::string TraceConfig_SessionSemaphore::SerializeAsString() const {
+std::string QnxConfig::SerializeAsString() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsString();
}
-std::vector<uint8_t> TraceConfig_SessionSemaphore::SerializeAsArray() const {
+std::vector<uint8_t> QnxConfig::SerializeAsArray() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsArray();
}
-void TraceConfig_SessionSemaphore::Serialize(::protozero::Message* msg) const {
- // Field 1: name
+void QnxConfig::Serialize(::protozero::Message* msg) const {
+ // Field 1: qnx_kernel_buffers
if (_has_field_[1]) {
- ::protozero::internal::gen_helpers::SerializeString(1, name_, msg);
+ ::protozero::internal::gen_helpers::SerializeVarInt(1, qnx_kernel_buffers_, msg);
}
- // Field 2: max_other_session_count
+ // Field 2: qnx_kernel_kbuffers
if (_has_field_[2]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(2, max_other_session_count_, msg);
+ ::protozero::internal::gen_helpers::SerializeVarInt(2, qnx_kernel_kbuffers_, msg);
+ }
+
+ // Field 3: qnx_kernel_wide_events
+ if (_has_field_[3]) {
+ ::protozero::internal::gen_helpers::SerializeTinyVarInt(3, qnx_kernel_wide_events_, msg);
+ }
+
+ // Field 4: qnx_cache_pages
+ if (_has_field_[4]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(4, qnx_cache_pages_, msg);
+ }
+
+ // Field 5: qnx_cache_max_pages
+ if (_has_field_[5]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(5, qnx_cache_max_pages_, msg);
+ }
+
+ // Field 6: qnx_trace_buffer_init_bytes
+ if (_has_field_[6]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(6, qnx_trace_buffer_init_bytes_, msg);
}
protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
}
+} // namespace perfetto
+} // namespace protos
+} // namespace gen
+#if defined(__GNUC__) || defined(__clang__)
+#pragma GCC diagnostic pop
+#endif
+// gen_amalgamated begin source: gen/protos/perfetto/config/statsd/atom_ids.gen.cc
+// gen_amalgamated expanded: #include "perfetto/protozero/gen_field_helpers.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/message.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/packed_repeated_fields.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/proto_decoder.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/scattered_heap_buffer.h"
+// DO NOT EDIT. Autogenerated by Perfetto cppgen_plugin
+#if defined(__GNUC__) || defined(__clang__)
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wfloat-equal"
+#endif
+// gen_amalgamated expanded: #include "protos/perfetto/config/statsd/atom_ids.gen.h"
+
+namespace perfetto {
+namespace protos {
+namespace gen {
+} // namespace perfetto
+} // namespace protos
+} // namespace gen
+#if defined(__GNUC__) || defined(__clang__)
+#pragma GCC diagnostic pop
+#endif
+// gen_amalgamated begin source: gen/protos/perfetto/config/statsd/statsd_tracing_config.gen.cc
+// gen_amalgamated expanded: #include "perfetto/protozero/gen_field_helpers.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/message.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/packed_repeated_fields.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/proto_decoder.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/scattered_heap_buffer.h"
+// DO NOT EDIT. Autogenerated by Perfetto cppgen_plugin
+#if defined(__GNUC__) || defined(__clang__)
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wfloat-equal"
+#endif
+// gen_amalgamated expanded: #include "protos/perfetto/config/statsd/statsd_tracing_config.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/config/statsd/atom_ids.gen.h"
+
+namespace perfetto {
+namespace protos {
+namespace gen {
-TraceConfig_CmdTraceStartDelay::TraceConfig_CmdTraceStartDelay() = default;
-TraceConfig_CmdTraceStartDelay::~TraceConfig_CmdTraceStartDelay() = default;
-TraceConfig_CmdTraceStartDelay::TraceConfig_CmdTraceStartDelay(const TraceConfig_CmdTraceStartDelay&) = default;
-TraceConfig_CmdTraceStartDelay& TraceConfig_CmdTraceStartDelay::operator=(const TraceConfig_CmdTraceStartDelay&) = default;
-TraceConfig_CmdTraceStartDelay::TraceConfig_CmdTraceStartDelay(TraceConfig_CmdTraceStartDelay&&) noexcept = default;
-TraceConfig_CmdTraceStartDelay& TraceConfig_CmdTraceStartDelay::operator=(TraceConfig_CmdTraceStartDelay&&) = default;
+StatsdPullAtomConfig::StatsdPullAtomConfig() = default;
+StatsdPullAtomConfig::~StatsdPullAtomConfig() = default;
+StatsdPullAtomConfig::StatsdPullAtomConfig(const StatsdPullAtomConfig&) = default;
+StatsdPullAtomConfig& StatsdPullAtomConfig::operator=(const StatsdPullAtomConfig&) = default;
+StatsdPullAtomConfig::StatsdPullAtomConfig(StatsdPullAtomConfig&&) noexcept = default;
+StatsdPullAtomConfig& StatsdPullAtomConfig::operator=(StatsdPullAtomConfig&&) = default;
-bool TraceConfig_CmdTraceStartDelay::operator==(const TraceConfig_CmdTraceStartDelay& other) const {
+bool StatsdPullAtomConfig::operator==(const StatsdPullAtomConfig& other) const {
return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
- && ::protozero::internal::gen_helpers::EqualsField(min_delay_ms_, other.min_delay_ms_)
- && ::protozero::internal::gen_helpers::EqualsField(max_delay_ms_, other.max_delay_ms_);
+ && ::protozero::internal::gen_helpers::EqualsField(pull_atom_id_, other.pull_atom_id_)
+ && ::protozero::internal::gen_helpers::EqualsField(raw_pull_atom_id_, other.raw_pull_atom_id_)
+ && ::protozero::internal::gen_helpers::EqualsField(pull_frequency_ms_, other.pull_frequency_ms_)
+ && ::protozero::internal::gen_helpers::EqualsField(packages_, other.packages_);
}
-bool TraceConfig_CmdTraceStartDelay::ParseFromArray(const void* raw, size_t size) {
+bool StatsdPullAtomConfig::ParseFromArray(const void* raw, size_t size) {
+ pull_atom_id_.clear();
+ raw_pull_atom_id_.clear();
+ packages_.clear();
unknown_fields_.clear();
bool packed_error = false;
@@ -30669,11 +29904,20 @@ bool TraceConfig_CmdTraceStartDelay::ParseFromArray(const void* raw, size_t size
_has_field_.set(field.id());
}
switch (field.id()) {
- case 1 /* min_delay_ms */:
- field.get(&min_delay_ms_);
+ case 1 /* pull_atom_id */:
+ pull_atom_id_.emplace_back();
+ field.get(&pull_atom_id_.back());
break;
- case 2 /* max_delay_ms */:
- field.get(&max_delay_ms_);
+ case 2 /* raw_pull_atom_id */:
+ raw_pull_atom_id_.emplace_back();
+ field.get(&raw_pull_atom_id_.back());
+ break;
+ case 3 /* pull_frequency_ms */:
+ field.get(&pull_frequency_ms_);
+ break;
+ case 4 /* packages */:
+ packages_.emplace_back();
+ ::protozero::internal::gen_helpers::DeserializeString(field, &packages_.back());
break;
default:
field.SerializeAndAppendTo(&unknown_fields_);
@@ -30683,49 +29927,64 @@ bool TraceConfig_CmdTraceStartDelay::ParseFromArray(const void* raw, size_t size
return !packed_error && !dec.bytes_left();
}
-std::string TraceConfig_CmdTraceStartDelay::SerializeAsString() const {
+std::string StatsdPullAtomConfig::SerializeAsString() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsString();
}
-std::vector<uint8_t> TraceConfig_CmdTraceStartDelay::SerializeAsArray() const {
+std::vector<uint8_t> StatsdPullAtomConfig::SerializeAsArray() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsArray();
}
-void TraceConfig_CmdTraceStartDelay::Serialize(::protozero::Message* msg) const {
- // Field 1: min_delay_ms
- if (_has_field_[1]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(1, min_delay_ms_, msg);
+void StatsdPullAtomConfig::Serialize(::protozero::Message* msg) const {
+ // Field 1: pull_atom_id
+ for (auto& it : pull_atom_id_) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(1, it, msg);
}
- // Field 2: max_delay_ms
- if (_has_field_[2]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(2, max_delay_ms_, msg);
+ // Field 2: raw_pull_atom_id
+ for (auto& it : raw_pull_atom_id_) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(2, it, msg);
+ }
+
+ // Field 3: pull_frequency_ms
+ if (_has_field_[3]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(3, pull_frequency_ms_, msg);
+ }
+
+ // Field 4: packages
+ for (auto& it : packages_) {
+ ::protozero::internal::gen_helpers::SerializeString(4, it, msg);
}
protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
}
-TraceConfig_AndroidReportConfig::TraceConfig_AndroidReportConfig() = default;
-TraceConfig_AndroidReportConfig::~TraceConfig_AndroidReportConfig() = default;
-TraceConfig_AndroidReportConfig::TraceConfig_AndroidReportConfig(const TraceConfig_AndroidReportConfig&) = default;
-TraceConfig_AndroidReportConfig& TraceConfig_AndroidReportConfig::operator=(const TraceConfig_AndroidReportConfig&) = default;
-TraceConfig_AndroidReportConfig::TraceConfig_AndroidReportConfig(TraceConfig_AndroidReportConfig&&) noexcept = default;
-TraceConfig_AndroidReportConfig& TraceConfig_AndroidReportConfig::operator=(TraceConfig_AndroidReportConfig&&) = default;
+StatsdTracingConfig::StatsdTracingConfig() = default;
+StatsdTracingConfig::~StatsdTracingConfig() = default;
+StatsdTracingConfig::StatsdTracingConfig(const StatsdTracingConfig&) = default;
+StatsdTracingConfig& StatsdTracingConfig::operator=(const StatsdTracingConfig&) = default;
+StatsdTracingConfig::StatsdTracingConfig(StatsdTracingConfig&&) noexcept = default;
+StatsdTracingConfig& StatsdTracingConfig::operator=(StatsdTracingConfig&&) = default;
-bool TraceConfig_AndroidReportConfig::operator==(const TraceConfig_AndroidReportConfig& other) const {
+bool StatsdTracingConfig::operator==(const StatsdTracingConfig& other) const {
return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
- && ::protozero::internal::gen_helpers::EqualsField(reporter_service_package_, other.reporter_service_package_)
- && ::protozero::internal::gen_helpers::EqualsField(reporter_service_class_, other.reporter_service_class_)
- && ::protozero::internal::gen_helpers::EqualsField(skip_report_, other.skip_report_)
- && ::protozero::internal::gen_helpers::EqualsField(use_pipe_in_framework_for_testing_, other.use_pipe_in_framework_for_testing_);
+ && ::protozero::internal::gen_helpers::EqualsField(push_atom_id_, other.push_atom_id_)
+ && ::protozero::internal::gen_helpers::EqualsField(raw_push_atom_id_, other.raw_push_atom_id_)
+ && ::protozero::internal::gen_helpers::EqualsField(pull_config_, other.pull_config_);
}
-bool TraceConfig_AndroidReportConfig::ParseFromArray(const void* raw, size_t size) {
+int StatsdTracingConfig::pull_config_size() const { return static_cast<int>(pull_config_.size()); }
+void StatsdTracingConfig::clear_pull_config() { pull_config_.clear(); }
+StatsdPullAtomConfig* StatsdTracingConfig::add_pull_config() { pull_config_.emplace_back(); return &pull_config_.back(); }
+bool StatsdTracingConfig::ParseFromArray(const void* raw, size_t size) {
+ push_atom_id_.clear();
+ raw_push_atom_id_.clear();
+ pull_config_.clear();
unknown_fields_.clear();
bool packed_error = false;
@@ -30735,17 +29994,17 @@ bool TraceConfig_AndroidReportConfig::ParseFromArray(const void* raw, size_t siz
_has_field_.set(field.id());
}
switch (field.id()) {
- case 1 /* reporter_service_package */:
- ::protozero::internal::gen_helpers::DeserializeString(field, &reporter_service_package_);
- break;
- case 2 /* reporter_service_class */:
- ::protozero::internal::gen_helpers::DeserializeString(field, &reporter_service_class_);
+ case 1 /* push_atom_id */:
+ push_atom_id_.emplace_back();
+ field.get(&push_atom_id_.back());
break;
- case 3 /* skip_report */:
- field.get(&skip_report_);
+ case 2 /* raw_push_atom_id */:
+ raw_push_atom_id_.emplace_back();
+ field.get(&raw_push_atom_id_.back());
break;
- case 4 /* use_pipe_in_framework_for_testing */:
- field.get(&use_pipe_in_framework_for_testing_);
+ case 3 /* pull_config */:
+ pull_config_.emplace_back();
+ pull_config_.back().ParseFromArray(field.data(), field.size());
break;
default:
field.SerializeAndAppendTo(&unknown_fields_);
@@ -30755,60 +30014,91 @@ bool TraceConfig_AndroidReportConfig::ParseFromArray(const void* raw, size_t siz
return !packed_error && !dec.bytes_left();
}
-std::string TraceConfig_AndroidReportConfig::SerializeAsString() const {
+std::string StatsdTracingConfig::SerializeAsString() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsString();
}
-std::vector<uint8_t> TraceConfig_AndroidReportConfig::SerializeAsArray() const {
+std::vector<uint8_t> StatsdTracingConfig::SerializeAsArray() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsArray();
}
-void TraceConfig_AndroidReportConfig::Serialize(::protozero::Message* msg) const {
- // Field 1: reporter_service_package
- if (_has_field_[1]) {
- ::protozero::internal::gen_helpers::SerializeString(1, reporter_service_package_, msg);
- }
-
- // Field 2: reporter_service_class
- if (_has_field_[2]) {
- ::protozero::internal::gen_helpers::SerializeString(2, reporter_service_class_, msg);
+void StatsdTracingConfig::Serialize(::protozero::Message* msg) const {
+ // Field 1: push_atom_id
+ for (auto& it : push_atom_id_) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(1, it, msg);
}
- // Field 3: skip_report
- if (_has_field_[3]) {
- ::protozero::internal::gen_helpers::SerializeTinyVarInt(3, skip_report_, msg);
+ // Field 2: raw_push_atom_id
+ for (auto& it : raw_push_atom_id_) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(2, it, msg);
}
- // Field 4: use_pipe_in_framework_for_testing
- if (_has_field_[4]) {
- ::protozero::internal::gen_helpers::SerializeTinyVarInt(4, use_pipe_in_framework_for_testing_, msg);
+ // Field 3: pull_config
+ for (auto& it : pull_config_) {
+ it.Serialize(msg->BeginNestedMessage<::protozero::Message>(3));
}
protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
}
+} // namespace perfetto
+} // namespace protos
+} // namespace gen
+#if defined(__GNUC__) || defined(__clang__)
+#pragma GCC diagnostic pop
+#endif
+// gen_amalgamated begin source: gen/protos/perfetto/config/sys_stats/sys_stats_config.gen.cc
+// gen_amalgamated expanded: #include "perfetto/protozero/gen_field_helpers.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/message.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/packed_repeated_fields.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/proto_decoder.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/scattered_heap_buffer.h"
+// DO NOT EDIT. Autogenerated by Perfetto cppgen_plugin
+#if defined(__GNUC__) || defined(__clang__)
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wfloat-equal"
+#endif
+// gen_amalgamated expanded: #include "protos/perfetto/config/sys_stats/sys_stats_config.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/common/sys_stats_counters.gen.h"
+
+namespace perfetto {
+namespace protos {
+namespace gen {
-TraceConfig_TraceFilter::TraceConfig_TraceFilter() = default;
-TraceConfig_TraceFilter::~TraceConfig_TraceFilter() = default;
-TraceConfig_TraceFilter::TraceConfig_TraceFilter(const TraceConfig_TraceFilter&) = default;
-TraceConfig_TraceFilter& TraceConfig_TraceFilter::operator=(const TraceConfig_TraceFilter&) = default;
-TraceConfig_TraceFilter::TraceConfig_TraceFilter(TraceConfig_TraceFilter&&) noexcept = default;
-TraceConfig_TraceFilter& TraceConfig_TraceFilter::operator=(TraceConfig_TraceFilter&&) = default;
+SysStatsConfig::SysStatsConfig() = default;
+SysStatsConfig::~SysStatsConfig() = default;
+SysStatsConfig::SysStatsConfig(const SysStatsConfig&) = default;
+SysStatsConfig& SysStatsConfig::operator=(const SysStatsConfig&) = default;
+SysStatsConfig::SysStatsConfig(SysStatsConfig&&) noexcept = default;
+SysStatsConfig& SysStatsConfig::operator=(SysStatsConfig&&) = default;
-bool TraceConfig_TraceFilter::operator==(const TraceConfig_TraceFilter& other) const {
+bool SysStatsConfig::operator==(const SysStatsConfig& other) const {
return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
- && ::protozero::internal::gen_helpers::EqualsField(bytecode_, other.bytecode_)
- && ::protozero::internal::gen_helpers::EqualsField(bytecode_v2_, other.bytecode_v2_)
- && ::protozero::internal::gen_helpers::EqualsField(string_filter_chain_, other.string_filter_chain_)
- && ::protozero::internal::gen_helpers::EqualsField(bytecode_overlay_v54_, other.bytecode_overlay_v54_)
- && ::protozero::internal::gen_helpers::EqualsField(string_filter_chain_v54_, other.string_filter_chain_v54_);
+ && ::protozero::internal::gen_helpers::EqualsField(meminfo_period_ms_, other.meminfo_period_ms_)
+ && ::protozero::internal::gen_helpers::EqualsField(meminfo_counters_, other.meminfo_counters_)
+ && ::protozero::internal::gen_helpers::EqualsField(vmstat_period_ms_, other.vmstat_period_ms_)
+ && ::protozero::internal::gen_helpers::EqualsField(vmstat_counters_, other.vmstat_counters_)
+ && ::protozero::internal::gen_helpers::EqualsField(stat_period_ms_, other.stat_period_ms_)
+ && ::protozero::internal::gen_helpers::EqualsField(stat_counters_, other.stat_counters_)
+ && ::protozero::internal::gen_helpers::EqualsField(devfreq_period_ms_, other.devfreq_period_ms_)
+ && ::protozero::internal::gen_helpers::EqualsField(cpufreq_period_ms_, other.cpufreq_period_ms_)
+ && ::protozero::internal::gen_helpers::EqualsField(buddyinfo_period_ms_, other.buddyinfo_period_ms_)
+ && ::protozero::internal::gen_helpers::EqualsField(diskstat_period_ms_, other.diskstat_period_ms_)
+ && ::protozero::internal::gen_helpers::EqualsField(psi_period_ms_, other.psi_period_ms_)
+ && ::protozero::internal::gen_helpers::EqualsField(thermal_period_ms_, other.thermal_period_ms_)
+ && ::protozero::internal::gen_helpers::EqualsField(cpuidle_period_ms_, other.cpuidle_period_ms_)
+ && ::protozero::internal::gen_helpers::EqualsField(gpufreq_period_ms_, other.gpufreq_period_ms_)
+ && ::protozero::internal::gen_helpers::EqualsField(slab_period_ms_, other.slab_period_ms_);
}
-bool TraceConfig_TraceFilter::ParseFromArray(const void* raw, size_t size) {
+bool SysStatsConfig::ParseFromArray(const void* raw, size_t size) {
+ meminfo_counters_.clear();
+ vmstat_counters_.clear();
+ stat_counters_.clear();
unknown_fields_.clear();
bool packed_error = false;
@@ -30818,20 +30108,53 @@ bool TraceConfig_TraceFilter::ParseFromArray(const void* raw, size_t size) {
_has_field_.set(field.id());
}
switch (field.id()) {
- case 1 /* bytecode */:
- field.get(&bytecode_);
+ case 1 /* meminfo_period_ms */:
+ field.get(&meminfo_period_ms_);
break;
- case 2 /* bytecode_v2 */:
- field.get(&bytecode_v2_);
+ case 2 /* meminfo_counters */:
+ meminfo_counters_.emplace_back();
+ field.get(&meminfo_counters_.back());
break;
- case 3 /* string_filter_chain */:
- (*string_filter_chain_).ParseFromArray(field.data(), field.size());
+ case 3 /* vmstat_period_ms */:
+ field.get(&vmstat_period_ms_);
break;
- case 4 /* bytecode_overlay_v54 */:
- field.get(&bytecode_overlay_v54_);
+ case 4 /* vmstat_counters */:
+ vmstat_counters_.emplace_back();
+ field.get(&vmstat_counters_.back());
break;
- case 5 /* string_filter_chain_v54 */:
- (*string_filter_chain_v54_).ParseFromArray(field.data(), field.size());
+ case 5 /* stat_period_ms */:
+ field.get(&stat_period_ms_);
+ break;
+ case 6 /* stat_counters */:
+ stat_counters_.emplace_back();
+ field.get(&stat_counters_.back());
+ break;
+ case 7 /* devfreq_period_ms */:
+ field.get(&devfreq_period_ms_);
+ break;
+ case 8 /* cpufreq_period_ms */:
+ field.get(&cpufreq_period_ms_);
+ break;
+ case 9 /* buddyinfo_period_ms */:
+ field.get(&buddyinfo_period_ms_);
+ break;
+ case 10 /* diskstat_period_ms */:
+ field.get(&diskstat_period_ms_);
+ break;
+ case 11 /* psi_period_ms */:
+ field.get(&psi_period_ms_);
+ break;
+ case 12 /* thermal_period_ms */:
+ field.get(&thermal_period_ms_);
+ break;
+ case 13 /* cpuidle_period_ms */:
+ field.get(&cpuidle_period_ms_);
+ break;
+ case 14 /* gpufreq_period_ms */:
+ field.get(&gpufreq_period_ms_);
+ break;
+ case 15 /* slab_period_ms */:
+ field.get(&slab_period_ms_);
break;
default:
field.SerializeAndAppendTo(&unknown_fields_);
@@ -30841,65 +30164,133 @@ bool TraceConfig_TraceFilter::ParseFromArray(const void* raw, size_t size) {
return !packed_error && !dec.bytes_left();
}
-std::string TraceConfig_TraceFilter::SerializeAsString() const {
+std::string SysStatsConfig::SerializeAsString() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsString();
}
-std::vector<uint8_t> TraceConfig_TraceFilter::SerializeAsArray() const {
+std::vector<uint8_t> SysStatsConfig::SerializeAsArray() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsArray();
}
-void TraceConfig_TraceFilter::Serialize(::protozero::Message* msg) const {
- // Field 1: bytecode
+void SysStatsConfig::Serialize(::protozero::Message* msg) const {
+ // Field 1: meminfo_period_ms
if (_has_field_[1]) {
- ::protozero::internal::gen_helpers::SerializeString(1, bytecode_, msg);
+ ::protozero::internal::gen_helpers::SerializeVarInt(1, meminfo_period_ms_, msg);
}
- // Field 2: bytecode_v2
- if (_has_field_[2]) {
- ::protozero::internal::gen_helpers::SerializeString(2, bytecode_v2_, msg);
+ // Field 2: meminfo_counters
+ for (auto& it : meminfo_counters_) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(2, it, msg);
}
- // Field 3: string_filter_chain
+ // Field 3: vmstat_period_ms
if (_has_field_[3]) {
- (*string_filter_chain_).Serialize(msg->BeginNestedMessage<::protozero::Message>(3));
+ ::protozero::internal::gen_helpers::SerializeVarInt(3, vmstat_period_ms_, msg);
}
- // Field 4: bytecode_overlay_v54
- if (_has_field_[4]) {
- ::protozero::internal::gen_helpers::SerializeString(4, bytecode_overlay_v54_, msg);
+ // Field 4: vmstat_counters
+ for (auto& it : vmstat_counters_) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(4, it, msg);
}
- // Field 5: string_filter_chain_v54
+ // Field 5: stat_period_ms
if (_has_field_[5]) {
- (*string_filter_chain_v54_).Serialize(msg->BeginNestedMessage<::protozero::Message>(5));
+ ::protozero::internal::gen_helpers::SerializeVarInt(5, stat_period_ms_, msg);
+ }
+
+ // Field 6: stat_counters
+ for (auto& it : stat_counters_) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(6, it, msg);
+ }
+
+ // Field 7: devfreq_period_ms
+ if (_has_field_[7]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(7, devfreq_period_ms_, msg);
+ }
+
+ // Field 8: cpufreq_period_ms
+ if (_has_field_[8]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(8, cpufreq_period_ms_, msg);
+ }
+
+ // Field 9: buddyinfo_period_ms
+ if (_has_field_[9]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(9, buddyinfo_period_ms_, msg);
+ }
+
+ // Field 10: diskstat_period_ms
+ if (_has_field_[10]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(10, diskstat_period_ms_, msg);
+ }
+
+ // Field 11: psi_period_ms
+ if (_has_field_[11]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(11, psi_period_ms_, msg);
+ }
+
+ // Field 12: thermal_period_ms
+ if (_has_field_[12]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(12, thermal_period_ms_, msg);
+ }
+
+ // Field 13: cpuidle_period_ms
+ if (_has_field_[13]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(13, cpuidle_period_ms_, msg);
+ }
+
+ // Field 14: gpufreq_period_ms
+ if (_has_field_[14]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(14, gpufreq_period_ms_, msg);
+ }
+
+ // Field 15: slab_period_ms
+ if (_has_field_[15]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(15, slab_period_ms_, msg);
}
protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
}
+} // namespace perfetto
+} // namespace protos
+} // namespace gen
+#if defined(__GNUC__) || defined(__clang__)
+#pragma GCC diagnostic pop
+#endif
+// gen_amalgamated begin source: gen/protos/perfetto/config/system_info/system_info_config.gen.cc
+// gen_amalgamated expanded: #include "perfetto/protozero/gen_field_helpers.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/message.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/packed_repeated_fields.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/proto_decoder.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/scattered_heap_buffer.h"
+// DO NOT EDIT. Autogenerated by Perfetto cppgen_plugin
+#if defined(__GNUC__) || defined(__clang__)
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wfloat-equal"
+#endif
+// gen_amalgamated expanded: #include "protos/perfetto/config/system_info/system_info_config.gen.h"
+
+namespace perfetto {
+namespace protos {
+namespace gen {
-TraceConfig_TraceFilter_StringFilterChain::TraceConfig_TraceFilter_StringFilterChain() = default;
-TraceConfig_TraceFilter_StringFilterChain::~TraceConfig_TraceFilter_StringFilterChain() = default;
-TraceConfig_TraceFilter_StringFilterChain::TraceConfig_TraceFilter_StringFilterChain(const TraceConfig_TraceFilter_StringFilterChain&) = default;
-TraceConfig_TraceFilter_StringFilterChain& TraceConfig_TraceFilter_StringFilterChain::operator=(const TraceConfig_TraceFilter_StringFilterChain&) = default;
-TraceConfig_TraceFilter_StringFilterChain::TraceConfig_TraceFilter_StringFilterChain(TraceConfig_TraceFilter_StringFilterChain&&) noexcept = default;
-TraceConfig_TraceFilter_StringFilterChain& TraceConfig_TraceFilter_StringFilterChain::operator=(TraceConfig_TraceFilter_StringFilterChain&&) = default;
+SystemInfoConfig::SystemInfoConfig() = default;
+SystemInfoConfig::~SystemInfoConfig() = default;
+SystemInfoConfig::SystemInfoConfig(const SystemInfoConfig&) = default;
+SystemInfoConfig& SystemInfoConfig::operator=(const SystemInfoConfig&) = default;
+SystemInfoConfig::SystemInfoConfig(SystemInfoConfig&&) noexcept = default;
+SystemInfoConfig& SystemInfoConfig::operator=(SystemInfoConfig&&) = default;
-bool TraceConfig_TraceFilter_StringFilterChain::operator==(const TraceConfig_TraceFilter_StringFilterChain& other) const {
+bool SystemInfoConfig::operator==(const SystemInfoConfig& other) const {
return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
- && ::protozero::internal::gen_helpers::EqualsField(rules_, other.rules_);
+ && ::protozero::internal::gen_helpers::EqualsField(irq_names_, other.irq_names_);
}
-int TraceConfig_TraceFilter_StringFilterChain::rules_size() const { return static_cast<int>(rules_.size()); }
-void TraceConfig_TraceFilter_StringFilterChain::clear_rules() { rules_.clear(); }
-TraceConfig_TraceFilter_StringFilterRule* TraceConfig_TraceFilter_StringFilterChain::add_rules() { rules_.emplace_back(); return &rules_.back(); }
-bool TraceConfig_TraceFilter_StringFilterChain::ParseFromArray(const void* raw, size_t size) {
- rules_.clear();
+bool SystemInfoConfig::ParseFromArray(const void* raw, size_t size) {
unknown_fields_.clear();
bool packed_error = false;
@@ -30909,9 +30300,8 @@ bool TraceConfig_TraceFilter_StringFilterChain::ParseFromArray(const void* raw,
_has_field_.set(field.id());
}
switch (field.id()) {
- case 1 /* rules */:
- rules_.emplace_back();
- rules_.back().ParseFromArray(field.data(), field.size());
+ case 1 /* irq_names */:
+ field.get(&irq_names_);
break;
default:
field.SerializeAndAppendTo(&unknown_fields_);
@@ -30921,46 +30311,76 @@ bool TraceConfig_TraceFilter_StringFilterChain::ParseFromArray(const void* raw,
return !packed_error && !dec.bytes_left();
}
-std::string TraceConfig_TraceFilter_StringFilterChain::SerializeAsString() const {
+std::string SystemInfoConfig::SerializeAsString() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsString();
}
-std::vector<uint8_t> TraceConfig_TraceFilter_StringFilterChain::SerializeAsArray() const {
+std::vector<uint8_t> SystemInfoConfig::SerializeAsArray() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsArray();
}
-void TraceConfig_TraceFilter_StringFilterChain::Serialize(::protozero::Message* msg) const {
- // Field 1: rules
- for (auto& it : rules_) {
- it.Serialize(msg->BeginNestedMessage<::protozero::Message>(1));
+void SystemInfoConfig::Serialize(::protozero::Message* msg) const {
+ // Field 1: irq_names
+ if (_has_field_[1]) {
+ ::protozero::internal::gen_helpers::SerializeTinyVarInt(1, irq_names_, msg);
}
protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
}
+} // namespace perfetto
+} // namespace protos
+} // namespace gen
+#if defined(__GNUC__) || defined(__clang__)
+#pragma GCC diagnostic pop
+#endif
+// gen_amalgamated begin source: gen/protos/perfetto/config/track_event/track_event_config.gen.cc
+// gen_amalgamated expanded: #include "perfetto/protozero/gen_field_helpers.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/message.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/packed_repeated_fields.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/proto_decoder.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/scattered_heap_buffer.h"
+// DO NOT EDIT. Autogenerated by Perfetto cppgen_plugin
+#if defined(__GNUC__) || defined(__clang__)
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wfloat-equal"
+#endif
+// gen_amalgamated expanded: #include "protos/perfetto/config/track_event/track_event_config.gen.h"
+
+namespace perfetto {
+namespace protos {
+namespace gen {
-TraceConfig_TraceFilter_StringFilterRule::TraceConfig_TraceFilter_StringFilterRule() = default;
-TraceConfig_TraceFilter_StringFilterRule::~TraceConfig_TraceFilter_StringFilterRule() = default;
-TraceConfig_TraceFilter_StringFilterRule::TraceConfig_TraceFilter_StringFilterRule(const TraceConfig_TraceFilter_StringFilterRule&) = default;
-TraceConfig_TraceFilter_StringFilterRule& TraceConfig_TraceFilter_StringFilterRule::operator=(const TraceConfig_TraceFilter_StringFilterRule&) = default;
-TraceConfig_TraceFilter_StringFilterRule::TraceConfig_TraceFilter_StringFilterRule(TraceConfig_TraceFilter_StringFilterRule&&) noexcept = default;
-TraceConfig_TraceFilter_StringFilterRule& TraceConfig_TraceFilter_StringFilterRule::operator=(TraceConfig_TraceFilter_StringFilterRule&&) = default;
+TrackEventConfig::TrackEventConfig() = default;
+TrackEventConfig::~TrackEventConfig() = default;
+TrackEventConfig::TrackEventConfig(const TrackEventConfig&) = default;
+TrackEventConfig& TrackEventConfig::operator=(const TrackEventConfig&) = default;
+TrackEventConfig::TrackEventConfig(TrackEventConfig&&) noexcept = default;
+TrackEventConfig& TrackEventConfig::operator=(TrackEventConfig&&) = default;
-bool TraceConfig_TraceFilter_StringFilterRule::operator==(const TraceConfig_TraceFilter_StringFilterRule& other) const {
+bool TrackEventConfig::operator==(const TrackEventConfig& other) const {
return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
- && ::protozero::internal::gen_helpers::EqualsField(policy_, other.policy_)
- && ::protozero::internal::gen_helpers::EqualsField(regex_pattern_, other.regex_pattern_)
- && ::protozero::internal::gen_helpers::EqualsField(atrace_payload_starts_with_, other.atrace_payload_starts_with_)
- && ::protozero::internal::gen_helpers::EqualsField(name_, other.name_)
- && ::protozero::internal::gen_helpers::EqualsField(semantic_type_, other.semantic_type_);
+ && ::protozero::internal::gen_helpers::EqualsField(disabled_categories_, other.disabled_categories_)
+ && ::protozero::internal::gen_helpers::EqualsField(enabled_categories_, other.enabled_categories_)
+ && ::protozero::internal::gen_helpers::EqualsField(disabled_tags_, other.disabled_tags_)
+ && ::protozero::internal::gen_helpers::EqualsField(enabled_tags_, other.enabled_tags_)
+ && ::protozero::internal::gen_helpers::EqualsField(disable_incremental_timestamps_, other.disable_incremental_timestamps_)
+ && ::protozero::internal::gen_helpers::EqualsField(timestamp_unit_multiplier_, other.timestamp_unit_multiplier_)
+ && ::protozero::internal::gen_helpers::EqualsField(filter_debug_annotations_, other.filter_debug_annotations_)
+ && ::protozero::internal::gen_helpers::EqualsField(enable_thread_time_sampling_, other.enable_thread_time_sampling_)
+ && ::protozero::internal::gen_helpers::EqualsField(thread_time_subsampling_ns_, other.thread_time_subsampling_ns_)
+ && ::protozero::internal::gen_helpers::EqualsField(filter_dynamic_event_names_, other.filter_dynamic_event_names_);
}
-bool TraceConfig_TraceFilter_StringFilterRule::ParseFromArray(const void* raw, size_t size) {
- semantic_type_.clear();
+bool TrackEventConfig::ParseFromArray(const void* raw, size_t size) {
+ disabled_categories_.clear();
+ enabled_categories_.clear();
+ disabled_tags_.clear();
+ enabled_tags_.clear();
unknown_fields_.clear();
bool packed_error = false;
@@ -30970,21 +30390,39 @@ bool TraceConfig_TraceFilter_StringFilterRule::ParseFromArray(const void* raw, s
_has_field_.set(field.id());
}
switch (field.id()) {
- case 1 /* policy */:
- field.get(&policy_);
+ case 1 /* disabled_categories */:
+ disabled_categories_.emplace_back();
+ ::protozero::internal::gen_helpers::DeserializeString(field, &disabled_categories_.back());
break;
- case 2 /* regex_pattern */:
- ::protozero::internal::gen_helpers::DeserializeString(field, ®ex_pattern_);
+ case 2 /* enabled_categories */:
+ enabled_categories_.emplace_back();
+ ::protozero::internal::gen_helpers::DeserializeString(field, &enabled_categories_.back());
break;
- case 3 /* atrace_payload_starts_with */:
- ::protozero::internal::gen_helpers::DeserializeString(field, &atrace_payload_starts_with_);
+ case 3 /* disabled_tags */:
+ disabled_tags_.emplace_back();
+ ::protozero::internal::gen_helpers::DeserializeString(field, &disabled_tags_.back());
break;
- case 4 /* name */:
- ::protozero::internal::gen_helpers::DeserializeString(field, &name_);
+ case 4 /* enabled_tags */:
+ enabled_tags_.emplace_back();
+ ::protozero::internal::gen_helpers::DeserializeString(field, &enabled_tags_.back());
break;
- case 5 /* semantic_type */:
- semantic_type_.emplace_back();
- field.get(&semantic_type_.back());
+ case 5 /* disable_incremental_timestamps */:
+ field.get(&disable_incremental_timestamps_);
+ break;
+ case 6 /* timestamp_unit_multiplier */:
+ field.get(×tamp_unit_multiplier_);
+ break;
+ case 7 /* filter_debug_annotations */:
+ field.get(&filter_debug_annotations_);
+ break;
+ case 8 /* enable_thread_time_sampling */:
+ field.get(&enable_thread_time_sampling_);
+ break;
+ case 10 /* thread_time_subsampling_ns */:
+ field.get(&thread_time_subsampling_ns_);
+ break;
+ case 9 /* filter_dynamic_event_names */:
+ field.get(&filter_dynamic_event_names_);
break;
default:
field.SerializeAndAppendTo(&unknown_fields_);
@@ -30994,65 +30432,113 @@ bool TraceConfig_TraceFilter_StringFilterRule::ParseFromArray(const void* raw, s
return !packed_error && !dec.bytes_left();
}
-std::string TraceConfig_TraceFilter_StringFilterRule::SerializeAsString() const {
+std::string TrackEventConfig::SerializeAsString() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsString();
}
-std::vector<uint8_t> TraceConfig_TraceFilter_StringFilterRule::SerializeAsArray() const {
+std::vector<uint8_t> TrackEventConfig::SerializeAsArray() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsArray();
}
-void TraceConfig_TraceFilter_StringFilterRule::Serialize(::protozero::Message* msg) const {
- // Field 1: policy
- if (_has_field_[1]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(1, policy_, msg);
+void TrackEventConfig::Serialize(::protozero::Message* msg) const {
+ // Field 1: disabled_categories
+ for (auto& it : disabled_categories_) {
+ ::protozero::internal::gen_helpers::SerializeString(1, it, msg);
}
- // Field 2: regex_pattern
- if (_has_field_[2]) {
- ::protozero::internal::gen_helpers::SerializeString(2, regex_pattern_, msg);
+ // Field 2: enabled_categories
+ for (auto& it : enabled_categories_) {
+ ::protozero::internal::gen_helpers::SerializeString(2, it, msg);
}
- // Field 3: atrace_payload_starts_with
- if (_has_field_[3]) {
- ::protozero::internal::gen_helpers::SerializeString(3, atrace_payload_starts_with_, msg);
+ // Field 3: disabled_tags
+ for (auto& it : disabled_tags_) {
+ ::protozero::internal::gen_helpers::SerializeString(3, it, msg);
}
- // Field 4: name
- if (_has_field_[4]) {
- ::protozero::internal::gen_helpers::SerializeString(4, name_, msg);
+ // Field 4: enabled_tags
+ for (auto& it : enabled_tags_) {
+ ::protozero::internal::gen_helpers::SerializeString(4, it, msg);
}
- // Field 5: semantic_type
- for (auto& it : semantic_type_) {
- ::protozero::internal::gen_helpers::SerializeVarInt(5, it, msg);
+ // Field 5: disable_incremental_timestamps
+ if (_has_field_[5]) {
+ ::protozero::internal::gen_helpers::SerializeTinyVarInt(5, disable_incremental_timestamps_, msg);
+ }
+
+ // Field 6: timestamp_unit_multiplier
+ if (_has_field_[6]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(6, timestamp_unit_multiplier_, msg);
+ }
+
+ // Field 7: filter_debug_annotations
+ if (_has_field_[7]) {
+ ::protozero::internal::gen_helpers::SerializeTinyVarInt(7, filter_debug_annotations_, msg);
+ }
+
+ // Field 8: enable_thread_time_sampling
+ if (_has_field_[8]) {
+ ::protozero::internal::gen_helpers::SerializeTinyVarInt(8, enable_thread_time_sampling_, msg);
+ }
+
+ // Field 10: thread_time_subsampling_ns
+ if (_has_field_[10]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(10, thread_time_subsampling_ns_, msg);
+ }
+
+ // Field 9: filter_dynamic_event_names
+ if (_has_field_[9]) {
+ ::protozero::internal::gen_helpers::SerializeTinyVarInt(9, filter_dynamic_event_names_, msg);
}
protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
}
+} // namespace perfetto
+} // namespace protos
+} // namespace gen
+#if defined(__GNUC__) || defined(__clang__)
+#pragma GCC diagnostic pop
+#endif
+// gen_amalgamated begin source: gen/protos/perfetto/config/chrome/chrome_config.gen.cc
+// gen_amalgamated expanded: #include "perfetto/protozero/gen_field_helpers.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/message.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/packed_repeated_fields.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/proto_decoder.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/scattered_heap_buffer.h"
+// DO NOT EDIT. Autogenerated by Perfetto cppgen_plugin
+#if defined(__GNUC__) || defined(__clang__)
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wfloat-equal"
+#endif
+// gen_amalgamated expanded: #include "protos/perfetto/config/chrome/chrome_config.gen.h"
+
+namespace perfetto {
+namespace protos {
+namespace gen {
-TraceConfig_IncidentReportConfig::TraceConfig_IncidentReportConfig() = default;
-TraceConfig_IncidentReportConfig::~TraceConfig_IncidentReportConfig() = default;
-TraceConfig_IncidentReportConfig::TraceConfig_IncidentReportConfig(const TraceConfig_IncidentReportConfig&) = default;
-TraceConfig_IncidentReportConfig& TraceConfig_IncidentReportConfig::operator=(const TraceConfig_IncidentReportConfig&) = default;
-TraceConfig_IncidentReportConfig::TraceConfig_IncidentReportConfig(TraceConfig_IncidentReportConfig&&) noexcept = default;
-TraceConfig_IncidentReportConfig& TraceConfig_IncidentReportConfig::operator=(TraceConfig_IncidentReportConfig&&) = default;
+ChromeConfig::ChromeConfig() = default;
+ChromeConfig::~ChromeConfig() = default;
+ChromeConfig::ChromeConfig(const ChromeConfig&) = default;
+ChromeConfig& ChromeConfig::operator=(const ChromeConfig&) = default;
+ChromeConfig::ChromeConfig(ChromeConfig&&) noexcept = default;
+ChromeConfig& ChromeConfig::operator=(ChromeConfig&&) = default;
-bool TraceConfig_IncidentReportConfig::operator==(const TraceConfig_IncidentReportConfig& other) const {
+bool ChromeConfig::operator==(const ChromeConfig& other) const {
return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
- && ::protozero::internal::gen_helpers::EqualsField(destination_package_, other.destination_package_)
- && ::protozero::internal::gen_helpers::EqualsField(destination_class_, other.destination_class_)
- && ::protozero::internal::gen_helpers::EqualsField(privacy_level_, other.privacy_level_)
- && ::protozero::internal::gen_helpers::EqualsField(skip_incidentd_, other.skip_incidentd_)
- && ::protozero::internal::gen_helpers::EqualsField(skip_dropbox_, other.skip_dropbox_);
+ && ::protozero::internal::gen_helpers::EqualsField(trace_config_, other.trace_config_)
+ && ::protozero::internal::gen_helpers::EqualsField(privacy_filtering_enabled_, other.privacy_filtering_enabled_)
+ && ::protozero::internal::gen_helpers::EqualsField(convert_to_legacy_json_, other.convert_to_legacy_json_)
+ && ::protozero::internal::gen_helpers::EqualsField(client_priority_, other.client_priority_)
+ && ::protozero::internal::gen_helpers::EqualsField(json_agent_label_filter_, other.json_agent_label_filter_)
+ && ::protozero::internal::gen_helpers::EqualsField(event_package_name_filter_enabled_, other.event_package_name_filter_enabled_);
}
-bool TraceConfig_IncidentReportConfig::ParseFromArray(const void* raw, size_t size) {
+bool ChromeConfig::ParseFromArray(const void* raw, size_t size) {
unknown_fields_.clear();
bool packed_error = false;
@@ -31062,20 +30548,23 @@ bool TraceConfig_IncidentReportConfig::ParseFromArray(const void* raw, size_t si
_has_field_.set(field.id());
}
switch (field.id()) {
- case 1 /* destination_package */:
- ::protozero::internal::gen_helpers::DeserializeString(field, &destination_package_);
+ case 1 /* trace_config */:
+ ::protozero::internal::gen_helpers::DeserializeString(field, &trace_config_);
break;
- case 2 /* destination_class */:
- ::protozero::internal::gen_helpers::DeserializeString(field, &destination_class_);
+ case 2 /* privacy_filtering_enabled */:
+ field.get(&privacy_filtering_enabled_);
break;
- case 3 /* privacy_level */:
- field.get(&privacy_level_);
+ case 3 /* convert_to_legacy_json */:
+ field.get(&convert_to_legacy_json_);
break;
- case 5 /* skip_incidentd */:
- field.get(&skip_incidentd_);
+ case 4 /* client_priority */:
+ field.get(&client_priority_);
break;
- case 4 /* skip_dropbox */:
- field.get(&skip_dropbox_);
+ case 5 /* json_agent_label_filter */:
+ ::protozero::internal::gen_helpers::DeserializeString(field, &json_agent_label_filter_);
+ break;
+ case 6 /* event_package_name_filter_enabled */:
+ field.get(&event_package_name_filter_enabled_);
break;
default:
field.SerializeAndAppendTo(&unknown_fields_);
@@ -31085,62 +30574,93 @@ bool TraceConfig_IncidentReportConfig::ParseFromArray(const void* raw, size_t si
return !packed_error && !dec.bytes_left();
}
-std::string TraceConfig_IncidentReportConfig::SerializeAsString() const {
+std::string ChromeConfig::SerializeAsString() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsString();
}
-std::vector<uint8_t> TraceConfig_IncidentReportConfig::SerializeAsArray() const {
+std::vector<uint8_t> ChromeConfig::SerializeAsArray() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsArray();
}
-void TraceConfig_IncidentReportConfig::Serialize(::protozero::Message* msg) const {
- // Field 1: destination_package
+void ChromeConfig::Serialize(::protozero::Message* msg) const {
+ // Field 1: trace_config
if (_has_field_[1]) {
- ::protozero::internal::gen_helpers::SerializeString(1, destination_package_, msg);
+ ::protozero::internal::gen_helpers::SerializeString(1, trace_config_, msg);
}
- // Field 2: destination_class
+ // Field 2: privacy_filtering_enabled
if (_has_field_[2]) {
- ::protozero::internal::gen_helpers::SerializeString(2, destination_class_, msg);
+ ::protozero::internal::gen_helpers::SerializeTinyVarInt(2, privacy_filtering_enabled_, msg);
}
- // Field 3: privacy_level
+ // Field 3: convert_to_legacy_json
if (_has_field_[3]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(3, privacy_level_, msg);
+ ::protozero::internal::gen_helpers::SerializeTinyVarInt(3, convert_to_legacy_json_, msg);
}
- // Field 5: skip_incidentd
+ // Field 4: client_priority
+ if (_has_field_[4]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(4, client_priority_, msg);
+ }
+
+ // Field 5: json_agent_label_filter
if (_has_field_[5]) {
- ::protozero::internal::gen_helpers::SerializeTinyVarInt(5, skip_incidentd_, msg);
+ ::protozero::internal::gen_helpers::SerializeString(5, json_agent_label_filter_, msg);
}
- // Field 4: skip_dropbox
- if (_has_field_[4]) {
- ::protozero::internal::gen_helpers::SerializeTinyVarInt(4, skip_dropbox_, msg);
+ // Field 6: event_package_name_filter_enabled
+ if (_has_field_[6]) {
+ ::protozero::internal::gen_helpers::SerializeTinyVarInt(6, event_package_name_filter_enabled_, msg);
}
protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
}
+} // namespace perfetto
+} // namespace protos
+} // namespace gen
+#if defined(__GNUC__) || defined(__clang__)
+#pragma GCC diagnostic pop
+#endif
+// gen_amalgamated begin source: gen/protos/perfetto/config/chrome/histogram_samples.gen.cc
+// gen_amalgamated expanded: #include "perfetto/protozero/gen_field_helpers.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/message.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/packed_repeated_fields.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/proto_decoder.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/scattered_heap_buffer.h"
+// DO NOT EDIT. Autogenerated by Perfetto cppgen_plugin
+#if defined(__GNUC__) || defined(__clang__)
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wfloat-equal"
+#endif
+// gen_amalgamated expanded: #include "protos/perfetto/config/chrome/histogram_samples.gen.h"
-TraceConfig_CompressionConfig::TraceConfig_CompressionConfig() = default;
-TraceConfig_CompressionConfig::~TraceConfig_CompressionConfig() = default;
-TraceConfig_CompressionConfig::TraceConfig_CompressionConfig(const TraceConfig_CompressionConfig&) = default;
-TraceConfig_CompressionConfig& TraceConfig_CompressionConfig::operator=(const TraceConfig_CompressionConfig&) = default;
-TraceConfig_CompressionConfig::TraceConfig_CompressionConfig(TraceConfig_CompressionConfig&&) noexcept = default;
-TraceConfig_CompressionConfig& TraceConfig_CompressionConfig::operator=(TraceConfig_CompressionConfig&&) = default;
+namespace perfetto {
+namespace protos {
+namespace gen {
-bool TraceConfig_CompressionConfig::operator==(const TraceConfig_CompressionConfig& other) const {
+ChromiumHistogramSamplesConfig::ChromiumHistogramSamplesConfig() = default;
+ChromiumHistogramSamplesConfig::~ChromiumHistogramSamplesConfig() = default;
+ChromiumHistogramSamplesConfig::ChromiumHistogramSamplesConfig(const ChromiumHistogramSamplesConfig&) = default;
+ChromiumHistogramSamplesConfig& ChromiumHistogramSamplesConfig::operator=(const ChromiumHistogramSamplesConfig&) = default;
+ChromiumHistogramSamplesConfig::ChromiumHistogramSamplesConfig(ChromiumHistogramSamplesConfig&&) noexcept = default;
+ChromiumHistogramSamplesConfig& ChromiumHistogramSamplesConfig::operator=(ChromiumHistogramSamplesConfig&&) = default;
+
+bool ChromiumHistogramSamplesConfig::operator==(const ChromiumHistogramSamplesConfig& other) const {
return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
- && ::protozero::internal::gen_helpers::EqualsField(deflate_, other.deflate_)
- && ::protozero::internal::gen_helpers::EqualsField(zstd_, other.zstd_);
+ && ::protozero::internal::gen_helpers::EqualsField(histograms_, other.histograms_)
+ && ::protozero::internal::gen_helpers::EqualsField(filter_histogram_names_, other.filter_histogram_names_);
}
-bool TraceConfig_CompressionConfig::ParseFromArray(const void* raw, size_t size) {
+int ChromiumHistogramSamplesConfig::histograms_size() const { return static_cast<int>(histograms_.size()); }
+void ChromiumHistogramSamplesConfig::clear_histograms() { histograms_.clear(); }
+ChromiumHistogramSamplesConfig_HistogramSample* ChromiumHistogramSamplesConfig::add_histograms() { histograms_.emplace_back(); return &histograms_.back(); }
+bool ChromiumHistogramSamplesConfig::ParseFromArray(const void* raw, size_t size) {
+ histograms_.clear();
unknown_fields_.clear();
bool packed_error = false;
@@ -31150,11 +30670,12 @@ bool TraceConfig_CompressionConfig::ParseFromArray(const void* raw, size_t size)
_has_field_.set(field.id());
}
switch (field.id()) {
- case 1 /* deflate */:
- (*deflate_).ParseFromArray(field.data(), field.size());
+ case 1 /* histograms */:
+ histograms_.emplace_back();
+ histograms_.back().ParseFromArray(field.data(), field.size());
break;
- case 2 /* zstd */:
- (*zstd_).ParseFromArray(field.data(), field.size());
+ case 2 /* filter_histogram_names */:
+ field.get(&filter_histogram_names_);
break;
default:
field.SerializeAndAppendTo(&unknown_fields_);
@@ -31164,46 +30685,48 @@ bool TraceConfig_CompressionConfig::ParseFromArray(const void* raw, size_t size)
return !packed_error && !dec.bytes_left();
}
-std::string TraceConfig_CompressionConfig::SerializeAsString() const {
+std::string ChromiumHistogramSamplesConfig::SerializeAsString() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsString();
}
-std::vector<uint8_t> TraceConfig_CompressionConfig::SerializeAsArray() const {
+std::vector<uint8_t> ChromiumHistogramSamplesConfig::SerializeAsArray() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsArray();
}
-void TraceConfig_CompressionConfig::Serialize(::protozero::Message* msg) const {
- // Field 1: deflate
- if (_has_field_[1]) {
- (*deflate_).Serialize(msg->BeginNestedMessage<::protozero::Message>(1));
+void ChromiumHistogramSamplesConfig::Serialize(::protozero::Message* msg) const {
+ // Field 1: histograms
+ for (auto& it : histograms_) {
+ it.Serialize(msg->BeginNestedMessage<::protozero::Message>(1));
}
- // Field 2: zstd
+ // Field 2: filter_histogram_names
if (_has_field_[2]) {
- (*zstd_).Serialize(msg->BeginNestedMessage<::protozero::Message>(2));
+ ::protozero::internal::gen_helpers::SerializeTinyVarInt(2, filter_histogram_names_, msg);
}
protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
}
-TraceConfig_CompressionConfig_Zstd::TraceConfig_CompressionConfig_Zstd() = default;
-TraceConfig_CompressionConfig_Zstd::~TraceConfig_CompressionConfig_Zstd() = default;
-TraceConfig_CompressionConfig_Zstd::TraceConfig_CompressionConfig_Zstd(const TraceConfig_CompressionConfig_Zstd&) = default;
-TraceConfig_CompressionConfig_Zstd& TraceConfig_CompressionConfig_Zstd::operator=(const TraceConfig_CompressionConfig_Zstd&) = default;
-TraceConfig_CompressionConfig_Zstd::TraceConfig_CompressionConfig_Zstd(TraceConfig_CompressionConfig_Zstd&&) noexcept = default;
-TraceConfig_CompressionConfig_Zstd& TraceConfig_CompressionConfig_Zstd::operator=(TraceConfig_CompressionConfig_Zstd&&) = default;
+ChromiumHistogramSamplesConfig_HistogramSample::ChromiumHistogramSamplesConfig_HistogramSample() = default;
+ChromiumHistogramSamplesConfig_HistogramSample::~ChromiumHistogramSamplesConfig_HistogramSample() = default;
+ChromiumHistogramSamplesConfig_HistogramSample::ChromiumHistogramSamplesConfig_HistogramSample(const ChromiumHistogramSamplesConfig_HistogramSample&) = default;
+ChromiumHistogramSamplesConfig_HistogramSample& ChromiumHistogramSamplesConfig_HistogramSample::operator=(const ChromiumHistogramSamplesConfig_HistogramSample&) = default;
+ChromiumHistogramSamplesConfig_HistogramSample::ChromiumHistogramSamplesConfig_HistogramSample(ChromiumHistogramSamplesConfig_HistogramSample&&) noexcept = default;
+ChromiumHistogramSamplesConfig_HistogramSample& ChromiumHistogramSamplesConfig_HistogramSample::operator=(ChromiumHistogramSamplesConfig_HistogramSample&&) = default;
-bool TraceConfig_CompressionConfig_Zstd::operator==(const TraceConfig_CompressionConfig_Zstd& other) const {
+bool ChromiumHistogramSamplesConfig_HistogramSample::operator==(const ChromiumHistogramSamplesConfig_HistogramSample& other) const {
return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
- && ::protozero::internal::gen_helpers::EqualsField(level_, other.level_);
+ && ::protozero::internal::gen_helpers::EqualsField(histogram_name_, other.histogram_name_)
+ && ::protozero::internal::gen_helpers::EqualsField(min_value_, other.min_value_)
+ && ::protozero::internal::gen_helpers::EqualsField(max_value_, other.max_value_);
}
-bool TraceConfig_CompressionConfig_Zstd::ParseFromArray(const void* raw, size_t size) {
+bool ChromiumHistogramSamplesConfig_HistogramSample::ParseFromArray(const void* raw, size_t size) {
unknown_fields_.clear();
bool packed_error = false;
@@ -31213,8 +30736,14 @@ bool TraceConfig_CompressionConfig_Zstd::ParseFromArray(const void* raw, size_t
_has_field_.set(field.id());
}
switch (field.id()) {
- case 1 /* level */:
- field.get(&level_);
+ case 1 /* histogram_name */:
+ ::protozero::internal::gen_helpers::DeserializeString(field, &histogram_name_);
+ break;
+ case 2 /* min_value */:
+ field.get(&min_value_);
+ break;
+ case 3 /* max_value */:
+ field.get(&max_value_);
break;
default:
field.SerializeAndAppendTo(&unknown_fields_);
@@ -31224,87 +30753,74 @@ bool TraceConfig_CompressionConfig_Zstd::ParseFromArray(const void* raw, size_t
return !packed_error && !dec.bytes_left();
}
-std::string TraceConfig_CompressionConfig_Zstd::SerializeAsString() const {
+std::string ChromiumHistogramSamplesConfig_HistogramSample::SerializeAsString() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsString();
}
-std::vector<uint8_t> TraceConfig_CompressionConfig_Zstd::SerializeAsArray() const {
+std::vector<uint8_t> ChromiumHistogramSamplesConfig_HistogramSample::SerializeAsArray() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsArray();
}
-void TraceConfig_CompressionConfig_Zstd::Serialize(::protozero::Message* msg) const {
- // Field 1: level
+void ChromiumHistogramSamplesConfig_HistogramSample::Serialize(::protozero::Message* msg) const {
+ // Field 1: histogram_name
if (_has_field_[1]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(1, level_, msg);
+ ::protozero::internal::gen_helpers::SerializeString(1, histogram_name_, msg);
}
- protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
-}
-
-
-TraceConfig_CompressionConfig_Deflate::TraceConfig_CompressionConfig_Deflate() = default;
-TraceConfig_CompressionConfig_Deflate::~TraceConfig_CompressionConfig_Deflate() = default;
-TraceConfig_CompressionConfig_Deflate::TraceConfig_CompressionConfig_Deflate(const TraceConfig_CompressionConfig_Deflate&) = default;
-TraceConfig_CompressionConfig_Deflate& TraceConfig_CompressionConfig_Deflate::operator=(const TraceConfig_CompressionConfig_Deflate&) = default;
-TraceConfig_CompressionConfig_Deflate::TraceConfig_CompressionConfig_Deflate(TraceConfig_CompressionConfig_Deflate&&) noexcept = default;
-TraceConfig_CompressionConfig_Deflate& TraceConfig_CompressionConfig_Deflate::operator=(TraceConfig_CompressionConfig_Deflate&&) = default;
-
-bool TraceConfig_CompressionConfig_Deflate::operator==(const TraceConfig_CompressionConfig_Deflate& other) const {
- return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_);
-}
-
-bool TraceConfig_CompressionConfig_Deflate::ParseFromArray(const void* raw, size_t size) {
- unknown_fields_.clear();
- bool packed_error = false;
-
- ::protozero::ProtoDecoder dec(raw, size);
- for (auto field = dec.ReadField(); field.valid(); field = dec.ReadField()) {
- if (field.id() < _has_field_.size()) {
- _has_field_.set(field.id());
- }
- switch (field.id()) {
- default:
- field.SerializeAndAppendTo(&unknown_fields_);
- break;
- }
+ // Field 2: min_value
+ if (_has_field_[2]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(2, min_value_, msg);
}
- return !packed_error && !dec.bytes_left();
-}
-
-std::string TraceConfig_CompressionConfig_Deflate::SerializeAsString() const {
- ::protozero::internal::gen_helpers::MessageSerializer msg;
- Serialize(msg.get());
- return msg.SerializeAsString();
-}
-std::vector<uint8_t> TraceConfig_CompressionConfig_Deflate::SerializeAsArray() const {
- ::protozero::internal::gen_helpers::MessageSerializer msg;
- Serialize(msg.get());
- return msg.SerializeAsArray();
-}
+ // Field 3: max_value
+ if (_has_field_[3]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(3, max_value_, msg);
+ }
-void TraceConfig_CompressionConfig_Deflate::Serialize(::protozero::Message* msg) const {
protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
}
+} // namespace perfetto
+} // namespace protos
+} // namespace gen
+#if defined(__GNUC__) || defined(__clang__)
+#pragma GCC diagnostic pop
+#endif
+// gen_amalgamated begin source: gen/protos/perfetto/config/chrome/sampling_heap_profiler.gen.cc
+// gen_amalgamated expanded: #include "perfetto/protozero/gen_field_helpers.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/message.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/packed_repeated_fields.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/proto_decoder.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/scattered_heap_buffer.h"
+// DO NOT EDIT. Autogenerated by Perfetto cppgen_plugin
+#if defined(__GNUC__) || defined(__clang__)
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wfloat-equal"
+#endif
+// gen_amalgamated expanded: #include "protos/perfetto/config/chrome/sampling_heap_profiler.gen.h"
+
+namespace perfetto {
+namespace protos {
+namespace gen {
-TraceConfig_IncrementalStateConfig::TraceConfig_IncrementalStateConfig() = default;
-TraceConfig_IncrementalStateConfig::~TraceConfig_IncrementalStateConfig() = default;
-TraceConfig_IncrementalStateConfig::TraceConfig_IncrementalStateConfig(const TraceConfig_IncrementalStateConfig&) = default;
-TraceConfig_IncrementalStateConfig& TraceConfig_IncrementalStateConfig::operator=(const TraceConfig_IncrementalStateConfig&) = default;
-TraceConfig_IncrementalStateConfig::TraceConfig_IncrementalStateConfig(TraceConfig_IncrementalStateConfig&&) noexcept = default;
-TraceConfig_IncrementalStateConfig& TraceConfig_IncrementalStateConfig::operator=(TraceConfig_IncrementalStateConfig&&) = default;
+ChromiumSamplingHeapProfilerConfig::ChromiumSamplingHeapProfilerConfig() = default;
+ChromiumSamplingHeapProfilerConfig::~ChromiumSamplingHeapProfilerConfig() = default;
+ChromiumSamplingHeapProfilerConfig::ChromiumSamplingHeapProfilerConfig(const ChromiumSamplingHeapProfilerConfig&) = default;
+ChromiumSamplingHeapProfilerConfig& ChromiumSamplingHeapProfilerConfig::operator=(const ChromiumSamplingHeapProfilerConfig&) = default;
+ChromiumSamplingHeapProfilerConfig::ChromiumSamplingHeapProfilerConfig(ChromiumSamplingHeapProfilerConfig&&) noexcept = default;
+ChromiumSamplingHeapProfilerConfig& ChromiumSamplingHeapProfilerConfig::operator=(ChromiumSamplingHeapProfilerConfig&&) = default;
-bool TraceConfig_IncrementalStateConfig::operator==(const TraceConfig_IncrementalStateConfig& other) const {
+bool ChromiumSamplingHeapProfilerConfig::operator==(const ChromiumSamplingHeapProfilerConfig& other) const {
return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
- && ::protozero::internal::gen_helpers::EqualsField(clear_period_ms_, other.clear_period_ms_);
+ && ::protozero::internal::gen_helpers::EqualsField(sampling_interval_bytes_, other.sampling_interval_bytes_)
+ && ::protozero::internal::gen_helpers::EqualsField(sampling_interval_ms_, other.sampling_interval_ms_);
}
-bool TraceConfig_IncrementalStateConfig::ParseFromArray(const void* raw, size_t size) {
+bool ChromiumSamplingHeapProfilerConfig::ParseFromArray(const void* raw, size_t size) {
unknown_fields_.clear();
bool packed_error = false;
@@ -31314,8 +30830,11 @@ bool TraceConfig_IncrementalStateConfig::ParseFromArray(const void* raw, size_t
_has_field_.set(field.id());
}
switch (field.id()) {
- case 1 /* clear_period_ms */:
- field.get(&clear_period_ms_);
+ case 1 /* sampling_interval_bytes */:
+ field.get(&sampling_interval_bytes_);
+ break;
+ case 2 /* sampling_interval_ms */:
+ field.get(&sampling_interval_ms_);
break;
default:
field.SerializeAndAppendTo(&unknown_fields_);
@@ -31325,48 +30844,132 @@ bool TraceConfig_IncrementalStateConfig::ParseFromArray(const void* raw, size_t
return !packed_error && !dec.bytes_left();
}
-std::string TraceConfig_IncrementalStateConfig::SerializeAsString() const {
+std::string ChromiumSamplingHeapProfilerConfig::SerializeAsString() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsString();
}
-std::vector<uint8_t> TraceConfig_IncrementalStateConfig::SerializeAsArray() const {
+std::vector<uint8_t> ChromiumSamplingHeapProfilerConfig::SerializeAsArray() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsArray();
}
-void TraceConfig_IncrementalStateConfig::Serialize(::protozero::Message* msg) const {
- // Field 1: clear_period_ms
+void ChromiumSamplingHeapProfilerConfig::Serialize(::protozero::Message* msg) const {
+ // Field 1: sampling_interval_bytes
if (_has_field_[1]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(1, clear_period_ms_, msg);
+ ::protozero::internal::gen_helpers::SerializeVarInt(1, sampling_interval_bytes_, msg);
+ }
+
+ // Field 2: sampling_interval_ms
+ if (_has_field_[2]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(2, sampling_interval_ms_, msg);
}
protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
}
+} // namespace perfetto
+} // namespace protos
+} // namespace gen
+#if defined(__GNUC__) || defined(__clang__)
+#pragma GCC diagnostic pop
+#endif
+// gen_amalgamated begin source: gen/protos/perfetto/config/chrome/scenario_config.gen.cc
+// gen_amalgamated expanded: #include "perfetto/protozero/gen_field_helpers.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/message.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/packed_repeated_fields.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/proto_decoder.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/scattered_heap_buffer.h"
+// DO NOT EDIT. Autogenerated by Perfetto cppgen_plugin
+#if defined(__GNUC__) || defined(__clang__)
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wfloat-equal"
+#endif
+// gen_amalgamated expanded: #include "protos/perfetto/config/chrome/scenario_config.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/config/trace_config.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/config/priority_boost/priority_boost_config.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/config/data_source_config.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/config/qnx/qnx_config.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/config/linux/journald_config.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/config/chrome/stack_sampling_profiler.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/config/chrome/sampling_heap_profiler.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/config/chrome/histogram_samples.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/config/system_info/system_info_config.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/config/track_event/track_event_config.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/config/test_config.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/config/sys_stats/sys_stats_config.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/common/sys_stats_counters.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/config/profiling/smaps_config.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/config/profiling/perf_event_config.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/common/perf_events.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/config/profiling/java_hprof_config.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/config/profiling/heapprofd_config.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/config/process_stats/process_stats_config.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/config/statsd/statsd_tracing_config.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/config/statsd/atom_ids.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/config/protovm/protovm_config.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/config/power/android_power_config.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/config/interceptor_config.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/config/interceptors/console_config.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/config/inode_file/inode_file_config.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/config/gpu/gpu_renderstages_config.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/config/gpu/vulkan_memory_config.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/config/gpu/gpu_counter_config.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/config/ftrace/frozen_ftrace_config.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/config/ftrace/ftrace_config.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/config/chrome/system_metrics.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/config/etw/etw_config.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/config/chrome/v8_config.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/config/chrome/chrome_config.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/config/android/windowmanager_config.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/config/android/user_list_config.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/config/android/surfaceflinger_transactions_config.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/config/android/surfaceflinger_layers_config.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/config/android/display_video_config.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/config/android/protolog_config.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/config/android/pixel_modem_config.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/config/android/packages_list_config.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/config/android/network_trace_config.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/config/android/kernel_wakelocks_config.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/config/android/inputmethod_config.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/config/android/cpu_per_uid_config.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/config/android/app_wakelock_config.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/config/android/android_sdk_sysprop_guard_config.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/config/android/android_system_property_config.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/config/android/android_process_state_config.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/config/android/android_polled_state_config.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/config/android/android_log_config.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/common/android_log_constants.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/config/android/android_input_event_config.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/config/android/android_game_intervention_list_config.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/config/android/android_aflags_config.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/common/trace_attributes.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/common/semantic_type.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/common/builtin_clock.gen.h"
+
+namespace perfetto {
+namespace protos {
+namespace gen {
-TraceConfig_TriggerConfig::TraceConfig_TriggerConfig() = default;
-TraceConfig_TriggerConfig::~TraceConfig_TriggerConfig() = default;
-TraceConfig_TriggerConfig::TraceConfig_TriggerConfig(const TraceConfig_TriggerConfig&) = default;
-TraceConfig_TriggerConfig& TraceConfig_TriggerConfig::operator=(const TraceConfig_TriggerConfig&) = default;
-TraceConfig_TriggerConfig::TraceConfig_TriggerConfig(TraceConfig_TriggerConfig&&) noexcept = default;
-TraceConfig_TriggerConfig& TraceConfig_TriggerConfig::operator=(TraceConfig_TriggerConfig&&) = default;
+TracingTriggerRulesConfig::TracingTriggerRulesConfig() = default;
+TracingTriggerRulesConfig::~TracingTriggerRulesConfig() = default;
+TracingTriggerRulesConfig::TracingTriggerRulesConfig(const TracingTriggerRulesConfig&) = default;
+TracingTriggerRulesConfig& TracingTriggerRulesConfig::operator=(const TracingTriggerRulesConfig&) = default;
+TracingTriggerRulesConfig::TracingTriggerRulesConfig(TracingTriggerRulesConfig&&) noexcept = default;
+TracingTriggerRulesConfig& TracingTriggerRulesConfig::operator=(TracingTriggerRulesConfig&&) = default;
-bool TraceConfig_TriggerConfig::operator==(const TraceConfig_TriggerConfig& other) const {
+bool TracingTriggerRulesConfig::operator==(const TracingTriggerRulesConfig& other) const {
return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
- && ::protozero::internal::gen_helpers::EqualsField(trigger_mode_, other.trigger_mode_)
- && ::protozero::internal::gen_helpers::EqualsField(use_clone_snapshot_if_available_, other.use_clone_snapshot_if_available_)
- && ::protozero::internal::gen_helpers::EqualsField(triggers_, other.triggers_)
- && ::protozero::internal::gen_helpers::EqualsField(trigger_timeout_ms_, other.trigger_timeout_ms_);
+ && ::protozero::internal::gen_helpers::EqualsField(rules_, other.rules_);
}
-int TraceConfig_TriggerConfig::triggers_size() const { return static_cast<int>(triggers_.size()); }
-void TraceConfig_TriggerConfig::clear_triggers() { triggers_.clear(); }
-TraceConfig_TriggerConfig_Trigger* TraceConfig_TriggerConfig::add_triggers() { triggers_.emplace_back(); return &triggers_.back(); }
-bool TraceConfig_TriggerConfig::ParseFromArray(const void* raw, size_t size) {
- triggers_.clear();
+int TracingTriggerRulesConfig::rules_size() const { return static_cast<int>(rules_.size()); }
+void TracingTriggerRulesConfig::clear_rules() { rules_.clear(); }
+TriggerRule* TracingTriggerRulesConfig::add_rules() { rules_.emplace_back(); return &rules_.back(); }
+bool TracingTriggerRulesConfig::ParseFromArray(const void* raw, size_t size) {
+ rules_.clear();
unknown_fields_.clear();
bool packed_error = false;
@@ -31376,18 +30979,9 @@ bool TraceConfig_TriggerConfig::ParseFromArray(const void* raw, size_t size) {
_has_field_.set(field.id());
}
switch (field.id()) {
- case 1 /* trigger_mode */:
- field.get(&trigger_mode_);
- break;
- case 5 /* use_clone_snapshot_if_available */:
- field.get(&use_clone_snapshot_if_available_);
- break;
- case 2 /* triggers */:
- triggers_.emplace_back();
- triggers_.back().ParseFromArray(field.data(), field.size());
- break;
- case 3 /* trigger_timeout_ms */:
- field.get(&trigger_timeout_ms_);
+ case 1 /* rules */:
+ rules_.emplace_back();
+ rules_.back().ParseFromArray(field.data(), field.size());
break;
default:
field.SerializeAndAppendTo(&unknown_fields_);
@@ -31397,60 +30991,47 @@ bool TraceConfig_TriggerConfig::ParseFromArray(const void* raw, size_t size) {
return !packed_error && !dec.bytes_left();
}
-std::string TraceConfig_TriggerConfig::SerializeAsString() const {
+std::string TracingTriggerRulesConfig::SerializeAsString() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsString();
}
-std::vector<uint8_t> TraceConfig_TriggerConfig::SerializeAsArray() const {
+std::vector<uint8_t> TracingTriggerRulesConfig::SerializeAsArray() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsArray();
}
-void TraceConfig_TriggerConfig::Serialize(::protozero::Message* msg) const {
- // Field 1: trigger_mode
- if (_has_field_[1]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(1, trigger_mode_, msg);
- }
-
- // Field 5: use_clone_snapshot_if_available
- if (_has_field_[5]) {
- ::protozero::internal::gen_helpers::SerializeTinyVarInt(5, use_clone_snapshot_if_available_, msg);
- }
-
- // Field 2: triggers
- for (auto& it : triggers_) {
- it.Serialize(msg->BeginNestedMessage<::protozero::Message>(2));
- }
-
- // Field 3: trigger_timeout_ms
- if (_has_field_[3]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(3, trigger_timeout_ms_, msg);
+void TracingTriggerRulesConfig::Serialize(::protozero::Message* msg) const {
+ // Field 1: rules
+ for (auto& it : rules_) {
+ it.Serialize(msg->BeginNestedMessage<::protozero::Message>(1));
}
protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
}
-TraceConfig_TriggerConfig_Trigger::TraceConfig_TriggerConfig_Trigger() = default;
-TraceConfig_TriggerConfig_Trigger::~TraceConfig_TriggerConfig_Trigger() = default;
-TraceConfig_TriggerConfig_Trigger::TraceConfig_TriggerConfig_Trigger(const TraceConfig_TriggerConfig_Trigger&) = default;
-TraceConfig_TriggerConfig_Trigger& TraceConfig_TriggerConfig_Trigger::operator=(const TraceConfig_TriggerConfig_Trigger&) = default;
-TraceConfig_TriggerConfig_Trigger::TraceConfig_TriggerConfig_Trigger(TraceConfig_TriggerConfig_Trigger&&) noexcept = default;
-TraceConfig_TriggerConfig_Trigger& TraceConfig_TriggerConfig_Trigger::operator=(TraceConfig_TriggerConfig_Trigger&&) = default;
+TriggerRule::TriggerRule() = default;
+TriggerRule::~TriggerRule() = default;
+TriggerRule::TriggerRule(const TriggerRule&) = default;
+TriggerRule& TriggerRule::operator=(const TriggerRule&) = default;
+TriggerRule::TriggerRule(TriggerRule&&) noexcept = default;
+TriggerRule& TriggerRule::operator=(TriggerRule&&) = default;
-bool TraceConfig_TriggerConfig_Trigger::operator==(const TraceConfig_TriggerConfig_Trigger& other) const {
+bool TriggerRule::operator==(const TriggerRule& other) const {
return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
&& ::protozero::internal::gen_helpers::EqualsField(name_, other.name_)
- && ::protozero::internal::gen_helpers::EqualsField(producer_name_regex_, other.producer_name_regex_)
- && ::protozero::internal::gen_helpers::EqualsField(stop_delay_ms_, other.stop_delay_ms_)
- && ::protozero::internal::gen_helpers::EqualsField(max_per_24_h_, other.max_per_24_h_)
- && ::protozero::internal::gen_helpers::EqualsField(skip_probability_, other.skip_probability_);
+ && ::protozero::internal::gen_helpers::EqualsField(trigger_chance_, other.trigger_chance_)
+ && ::protozero::internal::gen_helpers::EqualsField(delay_ms_, other.delay_ms_)
+ && ::protozero::internal::gen_helpers::EqualsField(activation_delay_ms_, other.activation_delay_ms_)
+ && ::protozero::internal::gen_helpers::EqualsField(manual_trigger_name_, other.manual_trigger_name_)
+ && ::protozero::internal::gen_helpers::EqualsField(histogram_, other.histogram_)
+ && ::protozero::internal::gen_helpers::EqualsField(repeating_interval_, other.repeating_interval_);
}
-bool TraceConfig_TriggerConfig_Trigger::ParseFromArray(const void* raw, size_t size) {
+bool TriggerRule::ParseFromArray(const void* raw, size_t size) {
unknown_fields_.clear();
bool packed_error = false;
@@ -31463,17 +31044,23 @@ bool TraceConfig_TriggerConfig_Trigger::ParseFromArray(const void* raw, size_t s
case 1 /* name */:
::protozero::internal::gen_helpers::DeserializeString(field, &name_);
break;
- case 2 /* producer_name_regex */:
- ::protozero::internal::gen_helpers::DeserializeString(field, &producer_name_regex_);
+ case 2 /* trigger_chance */:
+ field.get(&trigger_chance_);
break;
- case 3 /* stop_delay_ms */:
- field.get(&stop_delay_ms_);
+ case 3 /* delay_ms */:
+ field.get(&delay_ms_);
break;
- case 4 /* max_per_24_h */:
- field.get(&max_per_24_h_);
+ case 8 /* activation_delay_ms */:
+ field.get(&activation_delay_ms_);
break;
- case 5 /* skip_probability */:
- field.get(&skip_probability_);
+ case 4 /* manual_trigger_name */:
+ ::protozero::internal::gen_helpers::DeserializeString(field, &manual_trigger_name_);
+ break;
+ case 5 /* histogram */:
+ (*histogram_).ParseFromArray(field.data(), field.size());
+ break;
+ case 6 /* repeating_interval */:
+ (*repeating_interval_).ParseFromArray(field.data(), field.size());
break;
default:
field.SerializeAndAppendTo(&unknown_fields_);
@@ -31483,62 +31070,72 @@ bool TraceConfig_TriggerConfig_Trigger::ParseFromArray(const void* raw, size_t s
return !packed_error && !dec.bytes_left();
}
-std::string TraceConfig_TriggerConfig_Trigger::SerializeAsString() const {
+std::string TriggerRule::SerializeAsString() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsString();
}
-std::vector<uint8_t> TraceConfig_TriggerConfig_Trigger::SerializeAsArray() const {
+std::vector<uint8_t> TriggerRule::SerializeAsArray() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsArray();
}
-void TraceConfig_TriggerConfig_Trigger::Serialize(::protozero::Message* msg) const {
+void TriggerRule::Serialize(::protozero::Message* msg) const {
// Field 1: name
if (_has_field_[1]) {
::protozero::internal::gen_helpers::SerializeString(1, name_, msg);
}
- // Field 2: producer_name_regex
+ // Field 2: trigger_chance
if (_has_field_[2]) {
- ::protozero::internal::gen_helpers::SerializeString(2, producer_name_regex_, msg);
+ ::protozero::internal::gen_helpers::SerializeFixed(2, trigger_chance_, msg);
}
- // Field 3: stop_delay_ms
+ // Field 3: delay_ms
if (_has_field_[3]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(3, stop_delay_ms_, msg);
+ ::protozero::internal::gen_helpers::SerializeVarInt(3, delay_ms_, msg);
}
- // Field 4: max_per_24_h
+ // Field 8: activation_delay_ms
+ if (_has_field_[8]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(8, activation_delay_ms_, msg);
+ }
+
+ // Field 4: manual_trigger_name
if (_has_field_[4]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(4, max_per_24_h_, msg);
+ ::protozero::internal::gen_helpers::SerializeString(4, manual_trigger_name_, msg);
}
- // Field 5: skip_probability
+ // Field 5: histogram
if (_has_field_[5]) {
- ::protozero::internal::gen_helpers::SerializeFixed(5, skip_probability_, msg);
+ (*histogram_).Serialize(msg->BeginNestedMessage<::protozero::Message>(5));
+ }
+
+ // Field 6: repeating_interval
+ if (_has_field_[6]) {
+ (*repeating_interval_).Serialize(msg->BeginNestedMessage<::protozero::Message>(6));
}
protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
}
-TraceConfig_GuardrailOverrides::TraceConfig_GuardrailOverrides() = default;
-TraceConfig_GuardrailOverrides::~TraceConfig_GuardrailOverrides() = default;
-TraceConfig_GuardrailOverrides::TraceConfig_GuardrailOverrides(const TraceConfig_GuardrailOverrides&) = default;
-TraceConfig_GuardrailOverrides& TraceConfig_GuardrailOverrides::operator=(const TraceConfig_GuardrailOverrides&) = default;
-TraceConfig_GuardrailOverrides::TraceConfig_GuardrailOverrides(TraceConfig_GuardrailOverrides&&) noexcept = default;
-TraceConfig_GuardrailOverrides& TraceConfig_GuardrailOverrides::operator=(TraceConfig_GuardrailOverrides&&) = default;
+TriggerRule_RepeatingInterval::TriggerRule_RepeatingInterval() = default;
+TriggerRule_RepeatingInterval::~TriggerRule_RepeatingInterval() = default;
+TriggerRule_RepeatingInterval::TriggerRule_RepeatingInterval(const TriggerRule_RepeatingInterval&) = default;
+TriggerRule_RepeatingInterval& TriggerRule_RepeatingInterval::operator=(const TriggerRule_RepeatingInterval&) = default;
+TriggerRule_RepeatingInterval::TriggerRule_RepeatingInterval(TriggerRule_RepeatingInterval&&) noexcept = default;
+TriggerRule_RepeatingInterval& TriggerRule_RepeatingInterval::operator=(TriggerRule_RepeatingInterval&&) = default;
-bool TraceConfig_GuardrailOverrides::operator==(const TraceConfig_GuardrailOverrides& other) const {
+bool TriggerRule_RepeatingInterval::operator==(const TriggerRule_RepeatingInterval& other) const {
return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
- && ::protozero::internal::gen_helpers::EqualsField(max_upload_per_day_bytes_, other.max_upload_per_day_bytes_)
- && ::protozero::internal::gen_helpers::EqualsField(max_tracing_buffer_size_kb_, other.max_tracing_buffer_size_kb_);
+ && ::protozero::internal::gen_helpers::EqualsField(period_ms_, other.period_ms_)
+ && ::protozero::internal::gen_helpers::EqualsField(randomized_, other.randomized_);
}
-bool TraceConfig_GuardrailOverrides::ParseFromArray(const void* raw, size_t size) {
+bool TriggerRule_RepeatingInterval::ParseFromArray(const void* raw, size_t size) {
unknown_fields_.clear();
bool packed_error = false;
@@ -31548,11 +31145,11 @@ bool TraceConfig_GuardrailOverrides::ParseFromArray(const void* raw, size_t size
_has_field_.set(field.id());
}
switch (field.id()) {
- case 1 /* max_upload_per_day_bytes */:
- field.get(&max_upload_per_day_bytes_);
+ case 1 /* period_ms */:
+ field.get(&period_ms_);
break;
- case 2 /* max_tracing_buffer_size_kb */:
- field.get(&max_tracing_buffer_size_kb_);
+ case 2 /* randomized */:
+ field.get(&randomized_);
break;
default:
field.SerializeAndAppendTo(&unknown_fields_);
@@ -31562,49 +31159,48 @@ bool TraceConfig_GuardrailOverrides::ParseFromArray(const void* raw, size_t size
return !packed_error && !dec.bytes_left();
}
-std::string TraceConfig_GuardrailOverrides::SerializeAsString() const {
+std::string TriggerRule_RepeatingInterval::SerializeAsString() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsString();
}
-std::vector<uint8_t> TraceConfig_GuardrailOverrides::SerializeAsArray() const {
+std::vector<uint8_t> TriggerRule_RepeatingInterval::SerializeAsArray() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsArray();
}
-void TraceConfig_GuardrailOverrides::Serialize(::protozero::Message* msg) const {
- // Field 1: max_upload_per_day_bytes
+void TriggerRule_RepeatingInterval::Serialize(::protozero::Message* msg) const {
+ // Field 1: period_ms
if (_has_field_[1]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(1, max_upload_per_day_bytes_, msg);
+ ::protozero::internal::gen_helpers::SerializeVarInt(1, period_ms_, msg);
}
- // Field 2: max_tracing_buffer_size_kb
+ // Field 2: randomized
if (_has_field_[2]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(2, max_tracing_buffer_size_kb_, msg);
+ ::protozero::internal::gen_helpers::SerializeTinyVarInt(2, randomized_, msg);
}
protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
}
-TraceConfig_StatsdMetadata::TraceConfig_StatsdMetadata() = default;
-TraceConfig_StatsdMetadata::~TraceConfig_StatsdMetadata() = default;
-TraceConfig_StatsdMetadata::TraceConfig_StatsdMetadata(const TraceConfig_StatsdMetadata&) = default;
-TraceConfig_StatsdMetadata& TraceConfig_StatsdMetadata::operator=(const TraceConfig_StatsdMetadata&) = default;
-TraceConfig_StatsdMetadata::TraceConfig_StatsdMetadata(TraceConfig_StatsdMetadata&&) noexcept = default;
-TraceConfig_StatsdMetadata& TraceConfig_StatsdMetadata::operator=(TraceConfig_StatsdMetadata&&) = default;
+TriggerRule_HistogramTrigger::TriggerRule_HistogramTrigger() = default;
+TriggerRule_HistogramTrigger::~TriggerRule_HistogramTrigger() = default;
+TriggerRule_HistogramTrigger::TriggerRule_HistogramTrigger(const TriggerRule_HistogramTrigger&) = default;
+TriggerRule_HistogramTrigger& TriggerRule_HistogramTrigger::operator=(const TriggerRule_HistogramTrigger&) = default;
+TriggerRule_HistogramTrigger::TriggerRule_HistogramTrigger(TriggerRule_HistogramTrigger&&) noexcept = default;
+TriggerRule_HistogramTrigger& TriggerRule_HistogramTrigger::operator=(TriggerRule_HistogramTrigger&&) = default;
-bool TraceConfig_StatsdMetadata::operator==(const TraceConfig_StatsdMetadata& other) const {
+bool TriggerRule_HistogramTrigger::operator==(const TriggerRule_HistogramTrigger& other) const {
return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
- && ::protozero::internal::gen_helpers::EqualsField(triggering_alert_id_, other.triggering_alert_id_)
- && ::protozero::internal::gen_helpers::EqualsField(triggering_config_uid_, other.triggering_config_uid_)
- && ::protozero::internal::gen_helpers::EqualsField(triggering_config_id_, other.triggering_config_id_)
- && ::protozero::internal::gen_helpers::EqualsField(triggering_subscription_id_, other.triggering_subscription_id_);
+ && ::protozero::internal::gen_helpers::EqualsField(histogram_name_, other.histogram_name_)
+ && ::protozero::internal::gen_helpers::EqualsField(min_value_, other.min_value_)
+ && ::protozero::internal::gen_helpers::EqualsField(max_value_, other.max_value_);
}
-bool TraceConfig_StatsdMetadata::ParseFromArray(const void* raw, size_t size) {
+bool TriggerRule_HistogramTrigger::ParseFromArray(const void* raw, size_t size) {
unknown_fields_.clear();
bool packed_error = false;
@@ -31614,17 +31210,14 @@ bool TraceConfig_StatsdMetadata::ParseFromArray(const void* raw, size_t size) {
_has_field_.set(field.id());
}
switch (field.id()) {
- case 1 /* triggering_alert_id */:
- field.get(&triggering_alert_id_);
- break;
- case 2 /* triggering_config_uid */:
- field.get(&triggering_config_uid_);
+ case 1 /* histogram_name */:
+ ::protozero::internal::gen_helpers::DeserializeString(field, &histogram_name_);
break;
- case 3 /* triggering_config_id */:
- field.get(&triggering_config_id_);
+ case 2 /* min_value */:
+ field.get(&min_value_);
break;
- case 4 /* triggering_subscription_id */:
- field.get(&triggering_subscription_id_);
+ case 3 /* max_value */:
+ field.get(&max_value_);
break;
default:
field.SerializeAndAppendTo(&unknown_fields_);
@@ -31634,58 +31227,55 @@ bool TraceConfig_StatsdMetadata::ParseFromArray(const void* raw, size_t size) {
return !packed_error && !dec.bytes_left();
}
-std::string TraceConfig_StatsdMetadata::SerializeAsString() const {
+std::string TriggerRule_HistogramTrigger::SerializeAsString() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsString();
}
-std::vector<uint8_t> TraceConfig_StatsdMetadata::SerializeAsArray() const {
+std::vector<uint8_t> TriggerRule_HistogramTrigger::SerializeAsArray() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsArray();
}
-void TraceConfig_StatsdMetadata::Serialize(::protozero::Message* msg) const {
- // Field 1: triggering_alert_id
+void TriggerRule_HistogramTrigger::Serialize(::protozero::Message* msg) const {
+ // Field 1: histogram_name
if (_has_field_[1]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(1, triggering_alert_id_, msg);
+ ::protozero::internal::gen_helpers::SerializeString(1, histogram_name_, msg);
}
- // Field 2: triggering_config_uid
+ // Field 2: min_value
if (_has_field_[2]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(2, triggering_config_uid_, msg);
+ ::protozero::internal::gen_helpers::SerializeVarInt(2, min_value_, msg);
}
- // Field 3: triggering_config_id
+ // Field 3: max_value
if (_has_field_[3]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(3, triggering_config_id_, msg);
- }
-
- // Field 4: triggering_subscription_id
- if (_has_field_[4]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(4, triggering_subscription_id_, msg);
+ ::protozero::internal::gen_helpers::SerializeVarInt(3, max_value_, msg);
}
protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
}
-TraceConfig_ProducerConfig::TraceConfig_ProducerConfig() = default;
-TraceConfig_ProducerConfig::~TraceConfig_ProducerConfig() = default;
-TraceConfig_ProducerConfig::TraceConfig_ProducerConfig(const TraceConfig_ProducerConfig&) = default;
-TraceConfig_ProducerConfig& TraceConfig_ProducerConfig::operator=(const TraceConfig_ProducerConfig&) = default;
-TraceConfig_ProducerConfig::TraceConfig_ProducerConfig(TraceConfig_ProducerConfig&&) noexcept = default;
-TraceConfig_ProducerConfig& TraceConfig_ProducerConfig::operator=(TraceConfig_ProducerConfig&&) = default;
+ChromeFieldTracingConfig::ChromeFieldTracingConfig() = default;
+ChromeFieldTracingConfig::~ChromeFieldTracingConfig() = default;
+ChromeFieldTracingConfig::ChromeFieldTracingConfig(const ChromeFieldTracingConfig&) = default;
+ChromeFieldTracingConfig& ChromeFieldTracingConfig::operator=(const ChromeFieldTracingConfig&) = default;
+ChromeFieldTracingConfig::ChromeFieldTracingConfig(ChromeFieldTracingConfig&&) noexcept = default;
+ChromeFieldTracingConfig& ChromeFieldTracingConfig::operator=(ChromeFieldTracingConfig&&) = default;
-bool TraceConfig_ProducerConfig::operator==(const TraceConfig_ProducerConfig& other) const {
+bool ChromeFieldTracingConfig::operator==(const ChromeFieldTracingConfig& other) const {
return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
- && ::protozero::internal::gen_helpers::EqualsField(producer_name_, other.producer_name_)
- && ::protozero::internal::gen_helpers::EqualsField(shm_size_kb_, other.shm_size_kb_)
- && ::protozero::internal::gen_helpers::EqualsField(page_size_kb_, other.page_size_kb_);
+ && ::protozero::internal::gen_helpers::EqualsField(scenarios_, other.scenarios_);
}
-bool TraceConfig_ProducerConfig::ParseFromArray(const void* raw, size_t size) {
+int ChromeFieldTracingConfig::scenarios_size() const { return static_cast<int>(scenarios_.size()); }
+void ChromeFieldTracingConfig::clear_scenarios() { scenarios_.clear(); }
+ScenarioConfig* ChromeFieldTracingConfig::add_scenarios() { scenarios_.emplace_back(); return &scenarios_.back(); }
+bool ChromeFieldTracingConfig::ParseFromArray(const void* raw, size_t size) {
+ scenarios_.clear();
unknown_fields_.clear();
bool packed_error = false;
@@ -31695,14 +31285,9 @@ bool TraceConfig_ProducerConfig::ParseFromArray(const void* raw, size_t size) {
_has_field_.set(field.id());
}
switch (field.id()) {
- case 1 /* producer_name */:
- ::protozero::internal::gen_helpers::DeserializeString(field, &producer_name_);
- break;
- case 2 /* shm_size_kb */:
- field.get(&shm_size_kb_);
- break;
- case 3 /* page_size_kb */:
- field.get(&page_size_kb_);
+ case 1 /* scenarios */:
+ scenarios_.emplace_back();
+ scenarios_.back().ParseFromArray(field.data(), field.size());
break;
default:
field.SerializeAndAppendTo(&unknown_fields_);
@@ -31712,60 +31297,69 @@ bool TraceConfig_ProducerConfig::ParseFromArray(const void* raw, size_t size) {
return !packed_error && !dec.bytes_left();
}
-std::string TraceConfig_ProducerConfig::SerializeAsString() const {
+std::string ChromeFieldTracingConfig::SerializeAsString() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsString();
}
-std::vector<uint8_t> TraceConfig_ProducerConfig::SerializeAsArray() const {
+std::vector<uint8_t> ChromeFieldTracingConfig::SerializeAsArray() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsArray();
}
-void TraceConfig_ProducerConfig::Serialize(::protozero::Message* msg) const {
- // Field 1: producer_name
- if (_has_field_[1]) {
- ::protozero::internal::gen_helpers::SerializeString(1, producer_name_, msg);
- }
-
- // Field 2: shm_size_kb
- if (_has_field_[2]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(2, shm_size_kb_, msg);
- }
-
- // Field 3: page_size_kb
- if (_has_field_[3]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(3, page_size_kb_, msg);
+void ChromeFieldTracingConfig::Serialize(::protozero::Message* msg) const {
+ // Field 1: scenarios
+ for (auto& it : scenarios_) {
+ it.Serialize(msg->BeginNestedMessage<::protozero::Message>(1));
}
protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
}
-TraceConfig_BuiltinDataSource::TraceConfig_BuiltinDataSource() = default;
-TraceConfig_BuiltinDataSource::~TraceConfig_BuiltinDataSource() = default;
-TraceConfig_BuiltinDataSource::TraceConfig_BuiltinDataSource(const TraceConfig_BuiltinDataSource&) = default;
-TraceConfig_BuiltinDataSource& TraceConfig_BuiltinDataSource::operator=(const TraceConfig_BuiltinDataSource&) = default;
-TraceConfig_BuiltinDataSource::TraceConfig_BuiltinDataSource(TraceConfig_BuiltinDataSource&&) noexcept = default;
-TraceConfig_BuiltinDataSource& TraceConfig_BuiltinDataSource::operator=(TraceConfig_BuiltinDataSource&&) = default;
+ScenarioConfig::ScenarioConfig() = default;
+ScenarioConfig::~ScenarioConfig() = default;
+ScenarioConfig::ScenarioConfig(const ScenarioConfig&) = default;
+ScenarioConfig& ScenarioConfig::operator=(const ScenarioConfig&) = default;
+ScenarioConfig::ScenarioConfig(ScenarioConfig&&) noexcept = default;
+ScenarioConfig& ScenarioConfig::operator=(ScenarioConfig&&) = default;
-bool TraceConfig_BuiltinDataSource::operator==(const TraceConfig_BuiltinDataSource& other) const {
+bool ScenarioConfig::operator==(const ScenarioConfig& other) const {
return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
- && ::protozero::internal::gen_helpers::EqualsField(disable_clock_snapshotting_, other.disable_clock_snapshotting_)
- && ::protozero::internal::gen_helpers::EqualsField(disable_trace_config_, other.disable_trace_config_)
- && ::protozero::internal::gen_helpers::EqualsField(disable_system_info_, other.disable_system_info_)
- && ::protozero::internal::gen_helpers::EqualsField(disable_service_events_, other.disable_service_events_)
- && ::protozero::internal::gen_helpers::EqualsField(primary_trace_clock_, other.primary_trace_clock_)
- && ::protozero::internal::gen_helpers::EqualsField(snapshot_interval_ms_, other.snapshot_interval_ms_)
- && ::protozero::internal::gen_helpers::EqualsField(prefer_suspend_clock_for_snapshot_, other.prefer_suspend_clock_for_snapshot_)
- && ::protozero::internal::gen_helpers::EqualsField(disable_chunk_usage_histograms_, other.disable_chunk_usage_histograms_)
- && ::protozero::internal::gen_helpers::EqualsField(disable_extension_descriptors_, other.disable_extension_descriptors_)
- && ::protozero::internal::gen_helpers::EqualsField(enable_concurrent_session_events_, other.enable_concurrent_session_events_);
+ && ::protozero::internal::gen_helpers::EqualsField(scenario_name_, other.scenario_name_)
+ && ::protozero::internal::gen_helpers::EqualsField(scenario_description_, other.scenario_description_)
+ && ::protozero::internal::gen_helpers::EqualsField(start_rules_, other.start_rules_)
+ && ::protozero::internal::gen_helpers::EqualsField(stop_rules_, other.stop_rules_)
+ && ::protozero::internal::gen_helpers::EqualsField(upload_rules_, other.upload_rules_)
+ && ::protozero::internal::gen_helpers::EqualsField(setup_rules_, other.setup_rules_)
+ && ::protozero::internal::gen_helpers::EqualsField(trace_config_, other.trace_config_)
+ && ::protozero::internal::gen_helpers::EqualsField(nested_scenarios_, other.nested_scenarios_)
+ && ::protozero::internal::gen_helpers::EqualsField(use_system_backend_, other.use_system_backend_);
}
-bool TraceConfig_BuiltinDataSource::ParseFromArray(const void* raw, size_t size) {
+int ScenarioConfig::start_rules_size() const { return static_cast<int>(start_rules_.size()); }
+void ScenarioConfig::clear_start_rules() { start_rules_.clear(); }
+TriggerRule* ScenarioConfig::add_start_rules() { start_rules_.emplace_back(); return &start_rules_.back(); }
+int ScenarioConfig::stop_rules_size() const { return static_cast<int>(stop_rules_.size()); }
+void ScenarioConfig::clear_stop_rules() { stop_rules_.clear(); }
+TriggerRule* ScenarioConfig::add_stop_rules() { stop_rules_.emplace_back(); return &stop_rules_.back(); }
+int ScenarioConfig::upload_rules_size() const { return static_cast<int>(upload_rules_.size()); }
+void ScenarioConfig::clear_upload_rules() { upload_rules_.clear(); }
+TriggerRule* ScenarioConfig::add_upload_rules() { upload_rules_.emplace_back(); return &upload_rules_.back(); }
+int ScenarioConfig::setup_rules_size() const { return static_cast<int>(setup_rules_.size()); }
+void ScenarioConfig::clear_setup_rules() { setup_rules_.clear(); }
+TriggerRule* ScenarioConfig::add_setup_rules() { setup_rules_.emplace_back(); return &setup_rules_.back(); }
+int ScenarioConfig::nested_scenarios_size() const { return static_cast<int>(nested_scenarios_.size()); }
+void ScenarioConfig::clear_nested_scenarios() { nested_scenarios_.clear(); }
+NestedScenarioConfig* ScenarioConfig::add_nested_scenarios() { nested_scenarios_.emplace_back(); return &nested_scenarios_.back(); }
+bool ScenarioConfig::ParseFromArray(const void* raw, size_t size) {
+ start_rules_.clear();
+ stop_rules_.clear();
+ upload_rules_.clear();
+ setup_rules_.clear();
+ nested_scenarios_.clear();
unknown_fields_.clear();
bool packed_error = false;
@@ -31775,35 +31369,37 @@ bool TraceConfig_BuiltinDataSource::ParseFromArray(const void* raw, size_t size)
_has_field_.set(field.id());
}
switch (field.id()) {
- case 1 /* disable_clock_snapshotting */:
- field.get(&disable_clock_snapshotting_);
- break;
- case 2 /* disable_trace_config */:
- field.get(&disable_trace_config_);
+ case 1 /* scenario_name */:
+ ::protozero::internal::gen_helpers::DeserializeString(field, &scenario_name_);
break;
- case 3 /* disable_system_info */:
- field.get(&disable_system_info_);
+ case 9 /* scenario_description */:
+ ::protozero::internal::gen_helpers::DeserializeString(field, &scenario_description_);
break;
- case 4 /* disable_service_events */:
- field.get(&disable_service_events_);
+ case 2 /* start_rules */:
+ start_rules_.emplace_back();
+ start_rules_.back().ParseFromArray(field.data(), field.size());
break;
- case 5 /* primary_trace_clock */:
- field.get(&primary_trace_clock_);
+ case 3 /* stop_rules */:
+ stop_rules_.emplace_back();
+ stop_rules_.back().ParseFromArray(field.data(), field.size());
break;
- case 6 /* snapshot_interval_ms */:
- field.get(&snapshot_interval_ms_);
+ case 4 /* upload_rules */:
+ upload_rules_.emplace_back();
+ upload_rules_.back().ParseFromArray(field.data(), field.size());
break;
- case 7 /* prefer_suspend_clock_for_snapshot */:
- field.get(&prefer_suspend_clock_for_snapshot_);
+ case 5 /* setup_rules */:
+ setup_rules_.emplace_back();
+ setup_rules_.back().ParseFromArray(field.data(), field.size());
break;
- case 8 /* disable_chunk_usage_histograms */:
- field.get(&disable_chunk_usage_histograms_);
+ case 6 /* trace_config */:
+ (*trace_config_).ParseFromArray(field.data(), field.size());
break;
- case 9 /* disable_extension_descriptors */:
- field.get(&disable_extension_descriptors_);
+ case 7 /* nested_scenarios */:
+ nested_scenarios_.emplace_back();
+ nested_scenarios_.back().ParseFromArray(field.data(), field.size());
break;
- case 10 /* enable_concurrent_session_events */:
- field.get(&enable_concurrent_session_events_);
+ case 8 /* use_system_backend */:
+ field.get(&use_system_backend_);
break;
default:
field.SerializeAndAppendTo(&unknown_fields_);
@@ -31813,92 +31409,96 @@ bool TraceConfig_BuiltinDataSource::ParseFromArray(const void* raw, size_t size)
return !packed_error && !dec.bytes_left();
}
-std::string TraceConfig_BuiltinDataSource::SerializeAsString() const {
+std::string ScenarioConfig::SerializeAsString() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsString();
}
-std::vector<uint8_t> TraceConfig_BuiltinDataSource::SerializeAsArray() const {
+std::vector<uint8_t> ScenarioConfig::SerializeAsArray() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsArray();
}
-void TraceConfig_BuiltinDataSource::Serialize(::protozero::Message* msg) const {
- // Field 1: disable_clock_snapshotting
+void ScenarioConfig::Serialize(::protozero::Message* msg) const {
+ // Field 1: scenario_name
if (_has_field_[1]) {
- ::protozero::internal::gen_helpers::SerializeTinyVarInt(1, disable_clock_snapshotting_, msg);
- }
-
- // Field 2: disable_trace_config
- if (_has_field_[2]) {
- ::protozero::internal::gen_helpers::SerializeTinyVarInt(2, disable_trace_config_, msg);
+ ::protozero::internal::gen_helpers::SerializeString(1, scenario_name_, msg);
}
- // Field 3: disable_system_info
- if (_has_field_[3]) {
- ::protozero::internal::gen_helpers::SerializeTinyVarInt(3, disable_system_info_, msg);
+ // Field 9: scenario_description
+ if (_has_field_[9]) {
+ ::protozero::internal::gen_helpers::SerializeString(9, scenario_description_, msg);
}
- // Field 4: disable_service_events
- if (_has_field_[4]) {
- ::protozero::internal::gen_helpers::SerializeTinyVarInt(4, disable_service_events_, msg);
+ // Field 2: start_rules
+ for (auto& it : start_rules_) {
+ it.Serialize(msg->BeginNestedMessage<::protozero::Message>(2));
}
- // Field 5: primary_trace_clock
- if (_has_field_[5]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(5, primary_trace_clock_, msg);
+ // Field 3: stop_rules
+ for (auto& it : stop_rules_) {
+ it.Serialize(msg->BeginNestedMessage<::protozero::Message>(3));
}
- // Field 6: snapshot_interval_ms
- if (_has_field_[6]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(6, snapshot_interval_ms_, msg);
+ // Field 4: upload_rules
+ for (auto& it : upload_rules_) {
+ it.Serialize(msg->BeginNestedMessage<::protozero::Message>(4));
}
- // Field 7: prefer_suspend_clock_for_snapshot
- if (_has_field_[7]) {
- ::protozero::internal::gen_helpers::SerializeTinyVarInt(7, prefer_suspend_clock_for_snapshot_, msg);
+ // Field 5: setup_rules
+ for (auto& it : setup_rules_) {
+ it.Serialize(msg->BeginNestedMessage<::protozero::Message>(5));
}
- // Field 8: disable_chunk_usage_histograms
- if (_has_field_[8]) {
- ::protozero::internal::gen_helpers::SerializeTinyVarInt(8, disable_chunk_usage_histograms_, msg);
+ // Field 6: trace_config
+ if (_has_field_[6]) {
+ (*trace_config_).Serialize(msg->BeginNestedMessage<::protozero::Message>(6));
}
- // Field 9: disable_extension_descriptors
- if (_has_field_[9]) {
- ::protozero::internal::gen_helpers::SerializeTinyVarInt(9, disable_extension_descriptors_, msg);
+ // Field 7: nested_scenarios
+ for (auto& it : nested_scenarios_) {
+ it.Serialize(msg->BeginNestedMessage<::protozero::Message>(7));
}
- // Field 10: enable_concurrent_session_events
- if (_has_field_[10]) {
- ::protozero::internal::gen_helpers::SerializeTinyVarInt(10, enable_concurrent_session_events_, msg);
+ // Field 8: use_system_backend
+ if (_has_field_[8]) {
+ ::protozero::internal::gen_helpers::SerializeTinyVarInt(8, use_system_backend_, msg);
}
protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
}
-TraceConfig_DataSource::TraceConfig_DataSource() = default;
-TraceConfig_DataSource::~TraceConfig_DataSource() = default;
-TraceConfig_DataSource::TraceConfig_DataSource(const TraceConfig_DataSource&) = default;
-TraceConfig_DataSource& TraceConfig_DataSource::operator=(const TraceConfig_DataSource&) = default;
-TraceConfig_DataSource::TraceConfig_DataSource(TraceConfig_DataSource&&) noexcept = default;
-TraceConfig_DataSource& TraceConfig_DataSource::operator=(TraceConfig_DataSource&&) = default;
+NestedScenarioConfig::NestedScenarioConfig() = default;
+NestedScenarioConfig::~NestedScenarioConfig() = default;
+NestedScenarioConfig::NestedScenarioConfig(const NestedScenarioConfig&) = default;
+NestedScenarioConfig& NestedScenarioConfig::operator=(const NestedScenarioConfig&) = default;
+NestedScenarioConfig::NestedScenarioConfig(NestedScenarioConfig&&) noexcept = default;
+NestedScenarioConfig& NestedScenarioConfig::operator=(NestedScenarioConfig&&) = default;
-bool TraceConfig_DataSource::operator==(const TraceConfig_DataSource& other) const {
+bool NestedScenarioConfig::operator==(const NestedScenarioConfig& other) const {
return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
- && ::protozero::internal::gen_helpers::EqualsField(config_, other.config_)
- && ::protozero::internal::gen_helpers::EqualsField(producer_name_filter_, other.producer_name_filter_)
- && ::protozero::internal::gen_helpers::EqualsField(producer_name_regex_filter_, other.producer_name_regex_filter_)
- && ::protozero::internal::gen_helpers::EqualsField(machine_name_filter_, other.machine_name_filter_);
+ && ::protozero::internal::gen_helpers::EqualsField(scenario_name_, other.scenario_name_)
+ && ::protozero::internal::gen_helpers::EqualsField(start_rules_, other.start_rules_)
+ && ::protozero::internal::gen_helpers::EqualsField(stop_rules_, other.stop_rules_)
+ && ::protozero::internal::gen_helpers::EqualsField(upload_rules_, other.upload_rules_);
}
-bool TraceConfig_DataSource::ParseFromArray(const void* raw, size_t size) {
- producer_name_filter_.clear();
- producer_name_regex_filter_.clear();
- machine_name_filter_.clear();
+int NestedScenarioConfig::start_rules_size() const { return static_cast<int>(start_rules_.size()); }
+void NestedScenarioConfig::clear_start_rules() { start_rules_.clear(); }
+TriggerRule* NestedScenarioConfig::add_start_rules() { start_rules_.emplace_back(); return &start_rules_.back(); }
+int NestedScenarioConfig::stop_rules_size() const { return static_cast<int>(stop_rules_.size()); }
+void NestedScenarioConfig::clear_stop_rules() { stop_rules_.clear(); }
+TriggerRule* NestedScenarioConfig::add_stop_rules() { stop_rules_.emplace_back(); return &stop_rules_.back(); }
+int NestedScenarioConfig::upload_rules_size() const { return static_cast<int>(upload_rules_.size()); }
+void NestedScenarioConfig::clear_upload_rules() { upload_rules_.clear(); }
+TriggerRule* NestedScenarioConfig::add_upload_rules() { upload_rules_.emplace_back(); return &upload_rules_.back(); }
+bool NestedScenarioConfig::ParseFromArray(const void* raw, size_t size) {
+ start_rules_.clear();
+ stop_rules_.clear();
+ upload_rules_.clear();
unknown_fields_.clear();
bool packed_error = false;
@@ -31908,20 +31508,20 @@ bool TraceConfig_DataSource::ParseFromArray(const void* raw, size_t size) {
_has_field_.set(field.id());
}
switch (field.id()) {
- case 1 /* config */:
- (*config_).ParseFromArray(field.data(), field.size());
+ case 1 /* scenario_name */:
+ ::protozero::internal::gen_helpers::DeserializeString(field, &scenario_name_);
break;
- case 2 /* producer_name_filter */:
- producer_name_filter_.emplace_back();
- ::protozero::internal::gen_helpers::DeserializeString(field, &producer_name_filter_.back());
+ case 2 /* start_rules */:
+ start_rules_.emplace_back();
+ start_rules_.back().ParseFromArray(field.data(), field.size());
break;
- case 3 /* producer_name_regex_filter */:
- producer_name_regex_filter_.emplace_back();
- ::protozero::internal::gen_helpers::DeserializeString(field, &producer_name_regex_filter_.back());
+ case 3 /* stop_rules */:
+ stop_rules_.emplace_back();
+ stop_rules_.back().ParseFromArray(field.data(), field.size());
break;
- case 4 /* machine_name_filter */:
- machine_name_filter_.emplace_back();
- ::protozero::internal::gen_helpers::DeserializeString(field, &machine_name_filter_.back());
+ case 4 /* upload_rules */:
+ upload_rules_.emplace_back();
+ upload_rules_.back().ParseFromArray(field.data(), field.size());
break;
default:
field.SerializeAndAppendTo(&unknown_fields_);
@@ -31931,61 +31531,78 @@ bool TraceConfig_DataSource::ParseFromArray(const void* raw, size_t size) {
return !packed_error && !dec.bytes_left();
}
-std::string TraceConfig_DataSource::SerializeAsString() const {
+std::string NestedScenarioConfig::SerializeAsString() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsString();
}
-std::vector<uint8_t> TraceConfig_DataSource::SerializeAsArray() const {
+std::vector<uint8_t> NestedScenarioConfig::SerializeAsArray() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsArray();
}
-void TraceConfig_DataSource::Serialize(::protozero::Message* msg) const {
- // Field 1: config
+void NestedScenarioConfig::Serialize(::protozero::Message* msg) const {
+ // Field 1: scenario_name
if (_has_field_[1]) {
- (*config_).Serialize(msg->BeginNestedMessage<::protozero::Message>(1));
+ ::protozero::internal::gen_helpers::SerializeString(1, scenario_name_, msg);
}
- // Field 2: producer_name_filter
- for (auto& it : producer_name_filter_) {
- ::protozero::internal::gen_helpers::SerializeString(2, it, msg);
+ // Field 2: start_rules
+ for (auto& it : start_rules_) {
+ it.Serialize(msg->BeginNestedMessage<::protozero::Message>(2));
}
- // Field 3: producer_name_regex_filter
- for (auto& it : producer_name_regex_filter_) {
- ::protozero::internal::gen_helpers::SerializeString(3, it, msg);
+ // Field 3: stop_rules
+ for (auto& it : stop_rules_) {
+ it.Serialize(msg->BeginNestedMessage<::protozero::Message>(3));
}
- // Field 4: machine_name_filter
- for (auto& it : machine_name_filter_) {
- ::protozero::internal::gen_helpers::SerializeString(4, it, msg);
+ // Field 4: upload_rules
+ for (auto& it : upload_rules_) {
+ it.Serialize(msg->BeginNestedMessage<::protozero::Message>(4));
}
protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
}
+} // namespace perfetto
+} // namespace protos
+} // namespace gen
+#if defined(__GNUC__) || defined(__clang__)
+#pragma GCC diagnostic pop
+#endif
+// gen_amalgamated begin source: gen/protos/perfetto/config/chrome/stack_sampling_profiler.gen.cc
+// gen_amalgamated expanded: #include "perfetto/protozero/gen_field_helpers.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/message.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/packed_repeated_fields.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/proto_decoder.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/scattered_heap_buffer.h"
+// DO NOT EDIT. Autogenerated by Perfetto cppgen_plugin
+#if defined(__GNUC__) || defined(__clang__)
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wfloat-equal"
+#endif
+// gen_amalgamated expanded: #include "protos/perfetto/config/chrome/stack_sampling_profiler.gen.h"
+
+namespace perfetto {
+namespace protos {
+namespace gen {
-TraceConfig_BufferConfig::TraceConfig_BufferConfig() = default;
-TraceConfig_BufferConfig::~TraceConfig_BufferConfig() = default;
-TraceConfig_BufferConfig::TraceConfig_BufferConfig(const TraceConfig_BufferConfig&) = default;
-TraceConfig_BufferConfig& TraceConfig_BufferConfig::operator=(const TraceConfig_BufferConfig&) = default;
-TraceConfig_BufferConfig::TraceConfig_BufferConfig(TraceConfig_BufferConfig&&) noexcept = default;
-TraceConfig_BufferConfig& TraceConfig_BufferConfig::operator=(TraceConfig_BufferConfig&&) = default;
+ChromiumStackSamplingProfilerConfig::ChromiumStackSamplingProfilerConfig() = default;
+ChromiumStackSamplingProfilerConfig::~ChromiumStackSamplingProfilerConfig() = default;
+ChromiumStackSamplingProfilerConfig::ChromiumStackSamplingProfilerConfig(const ChromiumStackSamplingProfilerConfig&) = default;
+ChromiumStackSamplingProfilerConfig& ChromiumStackSamplingProfilerConfig::operator=(const ChromiumStackSamplingProfilerConfig&) = default;
+ChromiumStackSamplingProfilerConfig::ChromiumStackSamplingProfilerConfig(ChromiumStackSamplingProfilerConfig&&) noexcept = default;
+ChromiumStackSamplingProfilerConfig& ChromiumStackSamplingProfilerConfig::operator=(ChromiumStackSamplingProfilerConfig&&) = default;
-bool TraceConfig_BufferConfig::operator==(const TraceConfig_BufferConfig& other) const {
+bool ChromiumStackSamplingProfilerConfig::operator==(const ChromiumStackSamplingProfilerConfig& other) const {
return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
- && ::protozero::internal::gen_helpers::EqualsField(size_kb_, other.size_kb_)
- && ::protozero::internal::gen_helpers::EqualsField(fill_policy_, other.fill_policy_)
- && ::protozero::internal::gen_helpers::EqualsField(transfer_on_clone_, other.transfer_on_clone_)
- && ::protozero::internal::gen_helpers::EqualsField(clear_before_clone_, other.clear_before_clone_)
- && ::protozero::internal::gen_helpers::EqualsField(name_, other.name_)
- && ::protozero::internal::gen_helpers::EqualsField(experimental_mode_, other.experimental_mode_);
+ && ::protozero::internal::gen_helpers::EqualsField(sampling_interval_ms_, other.sampling_interval_ms_);
}
-bool TraceConfig_BufferConfig::ParseFromArray(const void* raw, size_t size) {
+bool ChromiumStackSamplingProfilerConfig::ParseFromArray(const void* raw, size_t size) {
unknown_fields_.clear();
bool packed_error = false;
@@ -31995,23 +31612,8 @@ bool TraceConfig_BufferConfig::ParseFromArray(const void* raw, size_t size) {
_has_field_.set(field.id());
}
switch (field.id()) {
- case 1 /* size_kb */:
- field.get(&size_kb_);
- break;
- case 4 /* fill_policy */:
- field.get(&fill_policy_);
- break;
- case 5 /* transfer_on_clone */:
- field.get(&transfer_on_clone_);
- break;
- case 6 /* clear_before_clone */:
- field.get(&clear_before_clone_);
- break;
- case 7 /* name */:
- ::protozero::internal::gen_helpers::DeserializeString(field, &name_);
- break;
- case 8 /* experimental_mode */:
- field.get(&experimental_mode_);
+ case 1 /* sampling_interval_ms */:
+ field.get(&sampling_interval_ms_);
break;
default:
field.SerializeAndAppendTo(&unknown_fields_);
@@ -32021,47 +31623,185 @@ bool TraceConfig_BufferConfig::ParseFromArray(const void* raw, size_t size) {
return !packed_error && !dec.bytes_left();
}
-std::string TraceConfig_BufferConfig::SerializeAsString() const {
+std::string ChromiumStackSamplingProfilerConfig::SerializeAsString() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsString();
}
-std::vector<uint8_t> TraceConfig_BufferConfig::SerializeAsArray() const {
+std::vector<uint8_t> ChromiumStackSamplingProfilerConfig::SerializeAsArray() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsArray();
}
-void TraceConfig_BufferConfig::Serialize(::protozero::Message* msg) const {
- // Field 1: size_kb
+void ChromiumStackSamplingProfilerConfig::Serialize(::protozero::Message* msg) const {
+ // Field 1: sampling_interval_ms
if (_has_field_[1]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(1, size_kb_, msg);
+ ::protozero::internal::gen_helpers::SerializeVarInt(1, sampling_interval_ms_, msg);
}
- // Field 4: fill_policy
- if (_has_field_[4]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(4, fill_policy_, msg);
+ protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
+}
+
+} // namespace perfetto
+} // namespace protos
+} // namespace gen
+#if defined(__GNUC__) || defined(__clang__)
+#pragma GCC diagnostic pop
+#endif
+// gen_amalgamated begin source: gen/protos/perfetto/config/chrome/system_metrics.gen.cc
+// gen_amalgamated expanded: #include "perfetto/protozero/gen_field_helpers.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/message.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/packed_repeated_fields.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/proto_decoder.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/scattered_heap_buffer.h"
+// DO NOT EDIT. Autogenerated by Perfetto cppgen_plugin
+#if defined(__GNUC__) || defined(__clang__)
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wfloat-equal"
+#endif
+// gen_amalgamated expanded: #include "protos/perfetto/config/chrome/system_metrics.gen.h"
+
+namespace perfetto {
+namespace protos {
+namespace gen {
+
+ChromiumSystemMetricsConfig::ChromiumSystemMetricsConfig() = default;
+ChromiumSystemMetricsConfig::~ChromiumSystemMetricsConfig() = default;
+ChromiumSystemMetricsConfig::ChromiumSystemMetricsConfig(const ChromiumSystemMetricsConfig&) = default;
+ChromiumSystemMetricsConfig& ChromiumSystemMetricsConfig::operator=(const ChromiumSystemMetricsConfig&) = default;
+ChromiumSystemMetricsConfig::ChromiumSystemMetricsConfig(ChromiumSystemMetricsConfig&&) noexcept = default;
+ChromiumSystemMetricsConfig& ChromiumSystemMetricsConfig::operator=(ChromiumSystemMetricsConfig&&) = default;
+
+bool ChromiumSystemMetricsConfig::operator==(const ChromiumSystemMetricsConfig& other) const {
+ return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
+ && ::protozero::internal::gen_helpers::EqualsField(sampling_interval_ms_, other.sampling_interval_ms_);
+}
+
+bool ChromiumSystemMetricsConfig::ParseFromArray(const void* raw, size_t size) {
+ unknown_fields_.clear();
+ bool packed_error = false;
+
+ ::protozero::ProtoDecoder dec(raw, size);
+ for (auto field = dec.ReadField(); field.valid(); field = dec.ReadField()) {
+ if (field.id() < _has_field_.size()) {
+ _has_field_.set(field.id());
+ }
+ switch (field.id()) {
+ case 1 /* sampling_interval_ms */:
+ field.get(&sampling_interval_ms_);
+ break;
+ default:
+ field.SerializeAndAppendTo(&unknown_fields_);
+ break;
+ }
}
+ return !packed_error && !dec.bytes_left();
+}
- // Field 5: transfer_on_clone
- if (_has_field_[5]) {
- ::protozero::internal::gen_helpers::SerializeTinyVarInt(5, transfer_on_clone_, msg);
+std::string ChromiumSystemMetricsConfig::SerializeAsString() const {
+ ::protozero::internal::gen_helpers::MessageSerializer msg;
+ Serialize(msg.get());
+ return msg.SerializeAsString();
+}
+
+std::vector<uint8_t> ChromiumSystemMetricsConfig::SerializeAsArray() const {
+ ::protozero::internal::gen_helpers::MessageSerializer msg;
+ Serialize(msg.get());
+ return msg.SerializeAsArray();
+}
+
+void ChromiumSystemMetricsConfig::Serialize(::protozero::Message* msg) const {
+ // Field 1: sampling_interval_ms
+ if (_has_field_[1]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(1, sampling_interval_ms_, msg);
}
- // Field 6: clear_before_clone
- if (_has_field_[6]) {
- ::protozero::internal::gen_helpers::SerializeTinyVarInt(6, clear_before_clone_, msg);
+ protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
+}
+
+} // namespace perfetto
+} // namespace protos
+} // namespace gen
+#if defined(__GNUC__) || defined(__clang__)
+#pragma GCC diagnostic pop
+#endif
+// gen_amalgamated begin source: gen/protos/perfetto/config/chrome/v8_config.gen.cc
+// gen_amalgamated expanded: #include "perfetto/protozero/gen_field_helpers.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/message.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/packed_repeated_fields.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/proto_decoder.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/scattered_heap_buffer.h"
+// DO NOT EDIT. Autogenerated by Perfetto cppgen_plugin
+#if defined(__GNUC__) || defined(__clang__)
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wfloat-equal"
+#endif
+// gen_amalgamated expanded: #include "protos/perfetto/config/chrome/v8_config.gen.h"
+
+namespace perfetto {
+namespace protos {
+namespace gen {
+
+V8Config::V8Config() = default;
+V8Config::~V8Config() = default;
+V8Config::V8Config(const V8Config&) = default;
+V8Config& V8Config::operator=(const V8Config&) = default;
+V8Config::V8Config(V8Config&&) noexcept = default;
+V8Config& V8Config::operator=(V8Config&&) = default;
+
+bool V8Config::operator==(const V8Config& other) const {
+ return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
+ && ::protozero::internal::gen_helpers::EqualsField(log_script_sources_, other.log_script_sources_)
+ && ::protozero::internal::gen_helpers::EqualsField(log_instructions_, other.log_instructions_);
+}
+
+bool V8Config::ParseFromArray(const void* raw, size_t size) {
+ unknown_fields_.clear();
+ bool packed_error = false;
+
+ ::protozero::ProtoDecoder dec(raw, size);
+ for (auto field = dec.ReadField(); field.valid(); field = dec.ReadField()) {
+ if (field.id() < _has_field_.size()) {
+ _has_field_.set(field.id());
+ }
+ switch (field.id()) {
+ case 1 /* log_script_sources */:
+ field.get(&log_script_sources_);
+ break;
+ case 2 /* log_instructions */:
+ field.get(&log_instructions_);
+ break;
+ default:
+ field.SerializeAndAppendTo(&unknown_fields_);
+ break;
+ }
}
+ return !packed_error && !dec.bytes_left();
+}
- // Field 7: name
- if (_has_field_[7]) {
- ::protozero::internal::gen_helpers::SerializeString(7, name_, msg);
+std::string V8Config::SerializeAsString() const {
+ ::protozero::internal::gen_helpers::MessageSerializer msg;
+ Serialize(msg.get());
+ return msg.SerializeAsString();
+}
+
+std::vector<uint8_t> V8Config::SerializeAsArray() const {
+ ::protozero::internal::gen_helpers::MessageSerializer msg;
+ Serialize(msg.get());
+ return msg.SerializeAsArray();
+}
+
+void V8Config::Serialize(::protozero::Message* msg) const {
+ // Field 1: log_script_sources
+ if (_has_field_[1]) {
+ ::protozero::internal::gen_helpers::SerializeTinyVarInt(1, log_script_sources_, msg);
}
- // Field 8: experimental_mode
- if (_has_field_[8]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(8, experimental_mode_, msg);
+ // Field 2: log_instructions
+ if (_has_field_[2]) {
+ ::protozero::internal::gen_helpers::SerializeTinyVarInt(2, log_instructions_, msg);
}
protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
@@ -32073,161 +31813,7 @@ void TraceConfig_BufferConfig::Serialize(::protozero::Message* msg) const {
#if defined(__GNUC__) || defined(__clang__)
#pragma GCC diagnostic pop
#endif
-// gen_amalgamated begin source: gen/protos/perfetto/protovm/vm_program.pbzero.cc
-// Intentionally empty (crbug.com/998165)
-// gen_amalgamated begin source: gen/protos/perfetto/common/android_energy_consumer_descriptor.pbzero.cc
-// Intentionally empty (crbug.com/998165)
-// gen_amalgamated begin source: gen/protos/perfetto/common/android_log_constants.pbzero.cc
-// Intentionally empty (crbug.com/998165)
-// gen_amalgamated begin source: gen/protos/perfetto/common/builtin_clock.pbzero.cc
-// Intentionally empty (crbug.com/998165)
-// gen_amalgamated begin source: gen/protos/perfetto/common/commit_data_request.pbzero.cc
-// Intentionally empty (crbug.com/998165)
-// gen_amalgamated begin source: gen/protos/perfetto/common/data_source_descriptor.pbzero.cc
-// Intentionally empty (crbug.com/998165)
-// gen_amalgamated begin source: gen/protos/perfetto/common/descriptor.pbzero.cc
-// Intentionally empty (crbug.com/998165)
-// gen_amalgamated begin source: gen/protos/perfetto/common/ftrace_descriptor.pbzero.cc
-// Intentionally empty (crbug.com/998165)
-// gen_amalgamated begin source: gen/protos/perfetto/common/gpu_counter_descriptor.pbzero.cc
-// Intentionally empty (crbug.com/998165)
-// gen_amalgamated begin source: gen/protos/perfetto/common/interceptor_descriptor.pbzero.cc
-// Intentionally empty (crbug.com/998165)
-// gen_amalgamated begin source: gen/protos/perfetto/common/observable_events.pbzero.cc
-// Intentionally empty (crbug.com/998165)
-// gen_amalgamated begin source: gen/protos/perfetto/common/perf_events.pbzero.cc
-// Intentionally empty (crbug.com/998165)
-// gen_amalgamated begin source: gen/protos/perfetto/common/sys_stats_counters.pbzero.cc
-// Intentionally empty (crbug.com/998165)
-// gen_amalgamated begin source: gen/protos/perfetto/common/system_info.pbzero.cc
-// Intentionally empty (crbug.com/998165)
-// gen_amalgamated begin source: gen/protos/perfetto/common/trace_attributes.pbzero.cc
-// Intentionally empty (crbug.com/998165)
-// gen_amalgamated begin source: gen/protos/perfetto/common/trace_stats.pbzero.cc
-// Intentionally empty (crbug.com/998165)
-// gen_amalgamated begin source: gen/protos/perfetto/common/tracing_service_capabilities.pbzero.cc
-// Intentionally empty (crbug.com/998165)
-// gen_amalgamated begin source: gen/protos/perfetto/common/tracing_service_state.pbzero.cc
-// Intentionally empty (crbug.com/998165)
-// gen_amalgamated begin source: gen/protos/perfetto/common/track_event_descriptor.pbzero.cc
-// Intentionally empty (crbug.com/998165)
-// gen_amalgamated begin source: gen/protos/perfetto/trace/android/android_aflags.pbzero.cc
-// Intentionally empty (crbug.com/998165)
-// gen_amalgamated begin source: gen/protos/perfetto/trace/android/android_game_intervention_list.pbzero.cc
-// Intentionally empty (crbug.com/998165)
-// gen_amalgamated begin source: gen/protos/perfetto/trace/android/android_log.pbzero.cc
-// Intentionally empty (crbug.com/998165)
-// gen_amalgamated begin source: gen/protos/perfetto/trace/android/android_system_property.pbzero.cc
-// Intentionally empty (crbug.com/998165)
-// gen_amalgamated begin source: gen/protos/perfetto/trace/android/cpu_per_uid_data.pbzero.cc
-// Intentionally empty (crbug.com/998165)
-// gen_amalgamated begin source: gen/protos/perfetto/trace/android/graphics_frame_event.pbzero.cc
-// Intentionally empty (crbug.com/998165)
-// gen_amalgamated begin source: gen/protos/perfetto/trace/android/initial_display_state.pbzero.cc
-// Intentionally empty (crbug.com/998165)
-// gen_amalgamated begin source: gen/protos/perfetto/trace/android/kernel_wakelock_data.pbzero.cc
-// Intentionally empty (crbug.com/998165)
-// gen_amalgamated begin source: gen/protos/perfetto/trace/android/packages_list.pbzero.cc
-// Intentionally empty (crbug.com/998165)
-// gen_amalgamated begin source: gen/protos/perfetto/trace/android/pixel_modem_events.pbzero.cc
-// Intentionally empty (crbug.com/998165)
-// gen_amalgamated begin source: gen/protos/perfetto/trace/android/user_list.pbzero.cc
-// Intentionally empty (crbug.com/998165)
-// gen_amalgamated begin source: gen/protos/perfetto/trace/chrome/chrome_benchmark_metadata.pbzero.cc
-// Intentionally empty (crbug.com/998165)
-// gen_amalgamated begin source: gen/protos/perfetto/trace/chrome/chrome_metadata.pbzero.cc
-// Intentionally empty (crbug.com/998165)
-// gen_amalgamated begin source: gen/protos/perfetto/trace/chrome/chrome_trace_event.pbzero.cc
-// Intentionally empty (crbug.com/998165)
-// gen_amalgamated begin source: gen/protos/perfetto/trace/chrome/chrome_trigger.pbzero.cc
-// Intentionally empty (crbug.com/998165)
-// gen_amalgamated begin source: gen/protos/perfetto/trace/chrome/v8.pbzero.cc
-// Intentionally empty (crbug.com/998165)
-// gen_amalgamated begin source: gen/protos/perfetto/trace/gpu/gpu_counter_event.pbzero.cc
-// Intentionally empty (crbug.com/998165)
-// gen_amalgamated begin source: gen/protos/perfetto/trace/gpu/gpu_log.pbzero.cc
-// Intentionally empty (crbug.com/998165)
-// gen_amalgamated begin source: gen/protos/perfetto/trace/gpu/gpu_mem_event.pbzero.cc
-// Intentionally empty (crbug.com/998165)
-// gen_amalgamated begin source: gen/protos/perfetto/trace/gpu/gpu_render_stage_event.pbzero.cc
-// Intentionally empty (crbug.com/998165)
-// gen_amalgamated begin source: gen/protos/perfetto/trace/gpu/vulkan_api_event.pbzero.cc
-// Intentionally empty (crbug.com/998165)
-// gen_amalgamated begin source: gen/protos/perfetto/trace/gpu/vulkan_memory_event.pbzero.cc
-// Intentionally empty (crbug.com/998165)
-// gen_amalgamated begin source: gen/protos/perfetto/trace/profiling/inline_callstack.pbzero.cc
-// Intentionally empty (crbug.com/998165)
-// gen_amalgamated begin source: gen/protos/perfetto/trace/profiling/art_process_metadata.pbzero.cc
-// Intentionally empty (crbug.com/998165)
-// gen_amalgamated begin source: gen/protos/perfetto/trace/profiling/deobfuscation.pbzero.cc
-// Intentionally empty (crbug.com/998165)
-// gen_amalgamated begin source: gen/protos/perfetto/trace/profiling/profile_common.pbzero.cc
-// Intentionally empty (crbug.com/998165)
-// gen_amalgamated begin source: gen/protos/perfetto/trace/profiling/profile_packet.pbzero.cc
-// Intentionally empty (crbug.com/998165)
-// gen_amalgamated begin source: gen/protos/perfetto/trace/profiling/smaps.pbzero.cc
-// Intentionally empty (crbug.com/998165)
-// gen_amalgamated begin source: gen/protos/perfetto/trace/profiling/stack_sample.pbzero.cc
-// Intentionally empty (crbug.com/998165)
-// gen_amalgamated begin source: gen/protos/perfetto/trace/track_event/chrome_active_processes.pbzero.cc
-// Intentionally empty (crbug.com/998165)
-// gen_amalgamated begin source: gen/protos/perfetto/trace/track_event/chrome_application_state_info.pbzero.cc
-// Intentionally empty (crbug.com/998165)
-// gen_amalgamated begin source: gen/protos/perfetto/trace/track_event/chrome_compositor_scheduler_state.pbzero.cc
-// Intentionally empty (crbug.com/998165)
-// gen_amalgamated begin source: gen/protos/perfetto/trace/track_event/chrome_content_settings_event_info.pbzero.cc
-// Intentionally empty (crbug.com/998165)
-// gen_amalgamated begin source: gen/protos/perfetto/trace/track_event/chrome_frame_reporter.pbzero.cc
-// Intentionally empty (crbug.com/998165)
-// gen_amalgamated begin source: gen/protos/perfetto/trace/track_event/chrome_histogram_sample.pbzero.cc
-// Intentionally empty (crbug.com/998165)
-// gen_amalgamated begin source: gen/protos/perfetto/trace/track_event/chrome_keyed_service.pbzero.cc
-// Intentionally empty (crbug.com/998165)
-// gen_amalgamated begin source: gen/protos/perfetto/trace/track_event/chrome_latency_info.pbzero.cc
-// Intentionally empty (crbug.com/998165)
-// gen_amalgamated begin source: gen/protos/perfetto/trace/track_event/chrome_legacy_ipc.pbzero.cc
-// Intentionally empty (crbug.com/998165)
-// gen_amalgamated begin source: gen/protos/perfetto/trace/track_event/chrome_message_pump.pbzero.cc
-// Intentionally empty (crbug.com/998165)
-// gen_amalgamated begin source: gen/protos/perfetto/trace/track_event/chrome_mojo_event_info.pbzero.cc
-// Intentionally empty (crbug.com/998165)
-// gen_amalgamated begin source: gen/protos/perfetto/trace/track_event/chrome_process_descriptor.pbzero.cc
-// Intentionally empty (crbug.com/998165)
-// gen_amalgamated begin source: gen/protos/perfetto/trace/track_event/chrome_renderer_scheduler_state.pbzero.cc
-// Intentionally empty (crbug.com/998165)
-// gen_amalgamated begin source: gen/protos/perfetto/trace/track_event/chrome_thread_descriptor.pbzero.cc
-// Intentionally empty (crbug.com/998165)
-// gen_amalgamated begin source: gen/protos/perfetto/trace/track_event/chrome_user_event.pbzero.cc
-// Intentionally empty (crbug.com/998165)
-// gen_amalgamated begin source: gen/protos/perfetto/trace/track_event/chrome_window_handle_event_info.pbzero.cc
-// Intentionally empty (crbug.com/998165)
-// gen_amalgamated begin source: gen/protos/perfetto/trace/track_event/counter_descriptor.pbzero.cc
-// Intentionally empty (crbug.com/998165)
-// gen_amalgamated begin source: gen/protos/perfetto/trace/track_event/debug_annotation.pbzero.cc
-// Intentionally empty (crbug.com/998165)
-// gen_amalgamated begin source: gen/protos/perfetto/trace/track_event/log_message.pbzero.cc
-// Intentionally empty (crbug.com/998165)
-// gen_amalgamated begin source: gen/protos/perfetto/trace/track_event/process_descriptor.pbzero.cc
-// Intentionally empty (crbug.com/998165)
-// gen_amalgamated begin source: gen/protos/perfetto/trace/track_event/range_of_interest.pbzero.cc
-// Intentionally empty (crbug.com/998165)
-// gen_amalgamated begin source: gen/protos/perfetto/trace/track_event/screenshot.pbzero.cc
-// Intentionally empty (crbug.com/998165)
-// gen_amalgamated begin source: gen/protos/perfetto/trace/track_event/source_location.pbzero.cc
-// Intentionally empty (crbug.com/998165)
-// gen_amalgamated begin source: gen/protos/perfetto/trace/track_event/state_descriptor.pbzero.cc
-// Intentionally empty (crbug.com/998165)
-// gen_amalgamated begin source: gen/protos/perfetto/trace/track_event/task_execution.pbzero.cc
-// Intentionally empty (crbug.com/998165)
-// gen_amalgamated begin source: gen/protos/perfetto/trace/track_event/thread_descriptor.pbzero.cc
-// Intentionally empty (crbug.com/998165)
-// gen_amalgamated begin source: gen/protos/perfetto/trace/track_event/track_descriptor.pbzero.cc
-// Intentionally empty (crbug.com/998165)
-// gen_amalgamated begin source: gen/protos/perfetto/trace/track_event/track_event.pbzero.cc
-// Intentionally empty (crbug.com/998165)
-// gen_amalgamated begin source: gen/protos/perfetto/trace/interned_data/interned_data.pbzero.cc
-// Intentionally empty (crbug.com/998165)
-// gen_amalgamated begin source: gen/protos/perfetto/trace/track_event/chrome_active_processes.gen.cc
+// gen_amalgamated begin source: gen/protos/perfetto/config/data_source_config.gen.cc
// gen_amalgamated expanded: #include "perfetto/protozero/gen_field_helpers.h"
// gen_amalgamated expanded: #include "perfetto/protozero/message.h"
// gen_amalgamated expanded: #include "perfetto/protozero/packed_repeated_fields.h"
@@ -32238,26 +31824,94 @@ void TraceConfig_BufferConfig::Serialize(::protozero::Message* msg) const {
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wfloat-equal"
#endif
-// gen_amalgamated expanded: #include "protos/perfetto/trace/track_event/chrome_active_processes.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/config/data_source_config.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/config/system_info/system_info_config.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/config/test_config.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/config/priority_boost/priority_boost_config.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/config/protovm/protovm_config.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/config/interceptor_config.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/config/interceptors/console_config.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/config/chrome/chrome_config.gen.h"
namespace perfetto {
namespace protos {
namespace gen {
-ChromeActiveProcesses::ChromeActiveProcesses() = default;
-ChromeActiveProcesses::~ChromeActiveProcesses() = default;
-ChromeActiveProcesses::ChromeActiveProcesses(const ChromeActiveProcesses&) = default;
-ChromeActiveProcesses& ChromeActiveProcesses::operator=(const ChromeActiveProcesses&) = default;
-ChromeActiveProcesses::ChromeActiveProcesses(ChromeActiveProcesses&&) noexcept = default;
-ChromeActiveProcesses& ChromeActiveProcesses::operator=(ChromeActiveProcesses&&) = default;
+DataSourceConfig::DataSourceConfig() = default;
+DataSourceConfig::~DataSourceConfig() = default;
+DataSourceConfig::DataSourceConfig(const DataSourceConfig&) = default;
+DataSourceConfig& DataSourceConfig::operator=(const DataSourceConfig&) = default;
+DataSourceConfig::DataSourceConfig(DataSourceConfig&&) noexcept = default;
+DataSourceConfig& DataSourceConfig::operator=(DataSourceConfig&&) = default;
-bool ChromeActiveProcesses::operator==(const ChromeActiveProcesses& other) const {
+bool DataSourceConfig::operator==(const DataSourceConfig& other) const {
return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
- && ::protozero::internal::gen_helpers::EqualsField(pid_, other.pid_);
+ && ::protozero::internal::gen_helpers::EqualsField(name_, other.name_)
+ && ::protozero::internal::gen_helpers::EqualsField(target_buffer_, other.target_buffer_)
+ && ::protozero::internal::gen_helpers::EqualsField(target_buffer_name_, other.target_buffer_name_)
+ && ::protozero::internal::gen_helpers::EqualsField(trace_duration_ms_, other.trace_duration_ms_)
+ && ::protozero::internal::gen_helpers::EqualsField(prefer_suspend_clock_for_duration_, other.prefer_suspend_clock_for_duration_)
+ && ::protozero::internal::gen_helpers::EqualsField(stop_timeout_ms_, other.stop_timeout_ms_)
+ && ::protozero::internal::gen_helpers::EqualsField(enable_extra_guardrails_, other.enable_extra_guardrails_)
+ && ::protozero::internal::gen_helpers::EqualsField(session_initiator_, other.session_initiator_)
+ && ::protozero::internal::gen_helpers::EqualsField(tracing_session_id_, other.tracing_session_id_)
+ && ::protozero::internal::gen_helpers::EqualsField(buffer_exhausted_policy_, other.buffer_exhausted_policy_)
+ && ::protozero::internal::gen_helpers::EqualsField(priority_boost_, other.priority_boost_)
+ && ::protozero::internal::gen_helpers::EqualsField(protovm_config_, other.protovm_config_)
+ && ::protozero::internal::gen_helpers::EqualsField(supports_tracing_v2_, other.supports_tracing_v2_)
+ && ::protozero::internal::gen_helpers::EqualsField(experimental_tracing_v2_, other.experimental_tracing_v2_)
+ && ::protozero::internal::gen_helpers::EqualsField(ftrace_config_, other.ftrace_config_)
+ && ::protozero::internal::gen_helpers::EqualsField(inode_file_config_, other.inode_file_config_)
+ && ::protozero::internal::gen_helpers::EqualsField(process_stats_config_, other.process_stats_config_)
+ && ::protozero::internal::gen_helpers::EqualsField(sys_stats_config_, other.sys_stats_config_)
+ && ::protozero::internal::gen_helpers::EqualsField(heapprofd_config_, other.heapprofd_config_)
+ && ::protozero::internal::gen_helpers::EqualsField(java_hprof_config_, other.java_hprof_config_)
+ && ::protozero::internal::gen_helpers::EqualsField(android_power_config_, other.android_power_config_)
+ && ::protozero::internal::gen_helpers::EqualsField(android_log_config_, other.android_log_config_)
+ && ::protozero::internal::gen_helpers::EqualsField(gpu_counter_config_, other.gpu_counter_config_)
+ && ::protozero::internal::gen_helpers::EqualsField(android_game_intervention_list_config_, other.android_game_intervention_list_config_)
+ && ::protozero::internal::gen_helpers::EqualsField(packages_list_config_, other.packages_list_config_)
+ && ::protozero::internal::gen_helpers::EqualsField(perf_event_config_, other.perf_event_config_)
+ && ::protozero::internal::gen_helpers::EqualsField(vulkan_memory_config_, other.vulkan_memory_config_)
+ && ::protozero::internal::gen_helpers::EqualsField(track_event_config_, other.track_event_config_)
+ && ::protozero::internal::gen_helpers::EqualsField(android_polled_state_config_, other.android_polled_state_config_)
+ && ::protozero::internal::gen_helpers::EqualsField(android_system_property_config_, other.android_system_property_config_)
+ && ::protozero::internal::gen_helpers::EqualsField(statsd_tracing_config_, other.statsd_tracing_config_)
+ && ::protozero::internal::gen_helpers::EqualsField(system_info_config_, other.system_info_config_)
+ && ::protozero::internal::gen_helpers::EqualsField(frozen_ftrace_config_, other.frozen_ftrace_config_)
+ && ::protozero::internal::gen_helpers::EqualsField(chrome_config_, other.chrome_config_)
+ && ::protozero::internal::gen_helpers::EqualsField(v8_config_, other.v8_config_)
+ && ::protozero::internal::gen_helpers::EqualsField(interceptor_config_, other.interceptor_config_)
+ && ::protozero::internal::gen_helpers::EqualsField(network_packet_trace_config_, other.network_packet_trace_config_)
+ && ::protozero::internal::gen_helpers::EqualsField(surfaceflinger_layers_config_, other.surfaceflinger_layers_config_)
+ && ::protozero::internal::gen_helpers::EqualsField(surfaceflinger_transactions_config_, other.surfaceflinger_transactions_config_)
+ && ::protozero::internal::gen_helpers::EqualsField(android_sdk_sysprop_guard_config_, other.android_sdk_sysprop_guard_config_)
+ && ::protozero::internal::gen_helpers::EqualsField(etw_config_, other.etw_config_)
+ && ::protozero::internal::gen_helpers::EqualsField(protolog_config_, other.protolog_config_)
+ && ::protozero::internal::gen_helpers::EqualsField(android_input_event_config_, other.android_input_event_config_)
+ && ::protozero::internal::gen_helpers::EqualsField(pixel_modem_config_, other.pixel_modem_config_)
+ && ::protozero::internal::gen_helpers::EqualsField(windowmanager_config_, other.windowmanager_config_)
+ && ::protozero::internal::gen_helpers::EqualsField(chromium_system_metrics_, other.chromium_system_metrics_)
+ && ::protozero::internal::gen_helpers::EqualsField(kernel_wakelocks_config_, other.kernel_wakelocks_config_)
+ && ::protozero::internal::gen_helpers::EqualsField(gpu_renderstages_config_, other.gpu_renderstages_config_)
+ && ::protozero::internal::gen_helpers::EqualsField(chromium_histogram_samples_, other.chromium_histogram_samples_)
+ && ::protozero::internal::gen_helpers::EqualsField(app_wakelocks_config_, other.app_wakelocks_config_)
+ && ::protozero::internal::gen_helpers::EqualsField(cpu_per_uid_config_, other.cpu_per_uid_config_)
+ && ::protozero::internal::gen_helpers::EqualsField(user_list_config_, other.user_list_config_)
+ && ::protozero::internal::gen_helpers::EqualsField(inputmethod_config_, other.inputmethod_config_)
+ && ::protozero::internal::gen_helpers::EqualsField(android_aflags_config_, other.android_aflags_config_)
+ && ::protozero::internal::gen_helpers::EqualsField(journald_config_, other.journald_config_)
+ && ::protozero::internal::gen_helpers::EqualsField(display_video_config_, other.display_video_config_)
+ && ::protozero::internal::gen_helpers::EqualsField(chromium_stack_sampling_profiler_, other.chromium_stack_sampling_profiler_)
+ && ::protozero::internal::gen_helpers::EqualsField(chromium_sampling_heap_profiler_, other.chromium_sampling_heap_profiler_)
+ && ::protozero::internal::gen_helpers::EqualsField(android_process_state_config_, other.android_process_state_config_)
+ && ::protozero::internal::gen_helpers::EqualsField(process_smaps_config_, other.process_smaps_config_)
+ && ::protozero::internal::gen_helpers::EqualsField(qnx_config_, other.qnx_config_)
+ && ::protozero::internal::gen_helpers::EqualsField(legacy_config_, other.legacy_config_)
+ && ::protozero::internal::gen_helpers::EqualsField(for_testing_, other.for_testing_);
}
-bool ChromeActiveProcesses::ParseFromArray(const void* raw, size_t size) {
- pid_.clear();
+bool DataSourceConfig::ParseFromArray(const void* raw, size_t size) {
unknown_fields_.clear();
bool packed_error = false;
@@ -32267,9 +31921,194 @@ bool ChromeActiveProcesses::ParseFromArray(const void* raw, size_t size) {
_has_field_.set(field.id());
}
switch (field.id()) {
- case 1 /* pid */:
- pid_.emplace_back();
- field.get(&pid_.back());
+ case 1 /* name */:
+ ::protozero::internal::gen_helpers::DeserializeString(field, &name_);
+ break;
+ case 2 /* target_buffer */:
+ field.get(&target_buffer_);
+ break;
+ case 11 /* target_buffer_name */:
+ ::protozero::internal::gen_helpers::DeserializeString(field, &target_buffer_name_);
+ break;
+ case 3 /* trace_duration_ms */:
+ field.get(&trace_duration_ms_);
+ break;
+ case 122 /* prefer_suspend_clock_for_duration */:
+ field.get(&prefer_suspend_clock_for_duration_);
+ break;
+ case 7 /* stop_timeout_ms */:
+ field.get(&stop_timeout_ms_);
+ break;
+ case 6 /* enable_extra_guardrails */:
+ field.get(&enable_extra_guardrails_);
+ break;
+ case 8 /* session_initiator */:
+ field.get(&session_initiator_);
+ break;
+ case 4 /* tracing_session_id */:
+ field.get(&tracing_session_id_);
+ break;
+ case 9 /* buffer_exhausted_policy */:
+ field.get(&buffer_exhausted_policy_);
+ break;
+ case 10 /* priority_boost */:
+ (*priority_boost_).ParseFromArray(field.data(), field.size());
+ break;
+ case 12 /* protovm_config */:
+ (*protovm_config_).ParseFromArray(field.data(), field.size());
+ break;
+ case 147 /* supports_tracing_v2 */:
+ field.get(&supports_tracing_v2_);
+ break;
+ case 148 /* experimental_tracing_v2 */:
+ (*experimental_tracing_v2_).ParseFromArray(field.data(), field.size());
+ break;
+ case 100 /* ftrace_config */:
+ ::protozero::internal::gen_helpers::DeserializeString(field, &ftrace_config_);
+ break;
+ case 102 /* inode_file_config */:
+ ::protozero::internal::gen_helpers::DeserializeString(field, &inode_file_config_);
+ break;
+ case 103 /* process_stats_config */:
+ ::protozero::internal::gen_helpers::DeserializeString(field, &process_stats_config_);
+ break;
+ case 104 /* sys_stats_config */:
+ ::protozero::internal::gen_helpers::DeserializeString(field, &sys_stats_config_);
+ break;
+ case 105 /* heapprofd_config */:
+ ::protozero::internal::gen_helpers::DeserializeString(field, &heapprofd_config_);
+ break;
+ case 110 /* java_hprof_config */:
+ ::protozero::internal::gen_helpers::DeserializeString(field, &java_hprof_config_);
+ break;
+ case 106 /* android_power_config */:
+ ::protozero::internal::gen_helpers::DeserializeString(field, &android_power_config_);
+ break;
+ case 107 /* android_log_config */:
+ ::protozero::internal::gen_helpers::DeserializeString(field, &android_log_config_);
+ break;
+ case 108 /* gpu_counter_config */:
+ ::protozero::internal::gen_helpers::DeserializeString(field, &gpu_counter_config_);
+ break;
+ case 116 /* android_game_intervention_list_config */:
+ ::protozero::internal::gen_helpers::DeserializeString(field, &android_game_intervention_list_config_);
+ break;
+ case 109 /* packages_list_config */:
+ ::protozero::internal::gen_helpers::DeserializeString(field, &packages_list_config_);
+ break;
+ case 111 /* perf_event_config */:
+ ::protozero::internal::gen_helpers::DeserializeString(field, &perf_event_config_);
+ break;
+ case 112 /* vulkan_memory_config */:
+ ::protozero::internal::gen_helpers::DeserializeString(field, &vulkan_memory_config_);
+ break;
+ case 113 /* track_event_config */:
+ ::protozero::internal::gen_helpers::DeserializeString(field, &track_event_config_);
+ break;
+ case 114 /* android_polled_state_config */:
+ ::protozero::internal::gen_helpers::DeserializeString(field, &android_polled_state_config_);
+ break;
+ case 118 /* android_system_property_config */:
+ ::protozero::internal::gen_helpers::DeserializeString(field, &android_system_property_config_);
+ break;
+ case 117 /* statsd_tracing_config */:
+ ::protozero::internal::gen_helpers::DeserializeString(field, &statsd_tracing_config_);
+ break;
+ case 119 /* system_info_config */:
+ (*system_info_config_).ParseFromArray(field.data(), field.size());
+ break;
+ case 136 /* frozen_ftrace_config */:
+ ::protozero::internal::gen_helpers::DeserializeString(field, &frozen_ftrace_config_);
+ break;
+ case 101 /* chrome_config */:
+ (*chrome_config_).ParseFromArray(field.data(), field.size());
+ break;
+ case 127 /* v8_config */:
+ ::protozero::internal::gen_helpers::DeserializeString(field, &v8_config_);
+ break;
+ case 115 /* interceptor_config */:
+ (*interceptor_config_).ParseFromArray(field.data(), field.size());
+ break;
+ case 120 /* network_packet_trace_config */:
+ ::protozero::internal::gen_helpers::DeserializeString(field, &network_packet_trace_config_);
+ break;
+ case 121 /* surfaceflinger_layers_config */:
+ ::protozero::internal::gen_helpers::DeserializeString(field, &surfaceflinger_layers_config_);
+ break;
+ case 123 /* surfaceflinger_transactions_config */:
+ ::protozero::internal::gen_helpers::DeserializeString(field, &surfaceflinger_transactions_config_);
+ break;
+ case 124 /* android_sdk_sysprop_guard_config */:
+ ::protozero::internal::gen_helpers::DeserializeString(field, &android_sdk_sysprop_guard_config_);
+ break;
+ case 125 /* etw_config */:
+ ::protozero::internal::gen_helpers::DeserializeString(field, &etw_config_);
+ break;
+ case 126 /* protolog_config */:
+ ::protozero::internal::gen_helpers::DeserializeString(field, &protolog_config_);
+ break;
+ case 128 /* android_input_event_config */:
+ ::protozero::internal::gen_helpers::DeserializeString(field, &android_input_event_config_);
+ break;
+ case 129 /* pixel_modem_config */:
+ ::protozero::internal::gen_helpers::DeserializeString(field, &pixel_modem_config_);
+ break;
+ case 130 /* windowmanager_config */:
+ ::protozero::internal::gen_helpers::DeserializeString(field, &windowmanager_config_);
+ break;
+ case 131 /* chromium_system_metrics */:
+ ::protozero::internal::gen_helpers::DeserializeString(field, &chromium_system_metrics_);
+ break;
+ case 132 /* kernel_wakelocks_config */:
+ ::protozero::internal::gen_helpers::DeserializeString(field, &kernel_wakelocks_config_);
+ break;
+ case 133 /* gpu_renderstages_config */:
+ ::protozero::internal::gen_helpers::DeserializeString(field, &gpu_renderstages_config_);
+ break;
+ case 134 /* chromium_histogram_samples */:
+ ::protozero::internal::gen_helpers::DeserializeString(field, &chromium_histogram_samples_);
+ break;
+ case 135 /* app_wakelocks_config */:
+ ::protozero::internal::gen_helpers::DeserializeString(field, &app_wakelocks_config_);
+ break;
+ case 137 /* cpu_per_uid_config */:
+ ::protozero::internal::gen_helpers::DeserializeString(field, &cpu_per_uid_config_);
+ break;
+ case 138 /* user_list_config */:
+ ::protozero::internal::gen_helpers::DeserializeString(field, &user_list_config_);
+ break;
+ case 139 /* inputmethod_config */:
+ ::protozero::internal::gen_helpers::DeserializeString(field, &inputmethod_config_);
+ break;
+ case 140 /* android_aflags_config */:
+ ::protozero::internal::gen_helpers::DeserializeString(field, &android_aflags_config_);
+ break;
+ case 141 /* journald_config */:
+ ::protozero::internal::gen_helpers::DeserializeString(field, &journald_config_);
+ break;
+ case 142 /* display_video_config */:
+ ::protozero::internal::gen_helpers::DeserializeString(field, &display_video_config_);
+ break;
+ case 143 /* chromium_stack_sampling_profiler */:
+ ::protozero::internal::gen_helpers::DeserializeString(field, &chromium_stack_sampling_profiler_);
+ break;
+ case 144 /* chromium_sampling_heap_profiler */:
+ ::protozero::internal::gen_helpers::DeserializeString(field, &chromium_sampling_heap_profiler_);
+ break;
+ case 145 /* android_process_state_config */:
+ ::protozero::internal::gen_helpers::DeserializeString(field, &android_process_state_config_);
+ break;
+ case 146 /* process_smaps_config */:
+ ::protozero::internal::gen_helpers::DeserializeString(field, &process_smaps_config_);
+ break;
+ case 150 /* qnx_config */:
+ ::protozero::internal::gen_helpers::DeserializeString(field, &qnx_config_);
+ break;
+ case 1000 /* legacy_config */:
+ ::protozero::internal::gen_helpers::DeserializeString(field, &legacy_config_);
+ break;
+ case 1001 /* for_testing */:
+ (*for_testing_).ParseFromArray(field.data(), field.size());
break;
default:
field.SerializeAndAppendTo(&unknown_fields_);
@@ -32279,147 +32118,357 @@ bool ChromeActiveProcesses::ParseFromArray(const void* raw, size_t size) {
return !packed_error && !dec.bytes_left();
}
-std::string ChromeActiveProcesses::SerializeAsString() const {
+std::string DataSourceConfig::SerializeAsString() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsString();
}
-std::vector<uint8_t> ChromeActiveProcesses::SerializeAsArray() const {
+std::vector<uint8_t> DataSourceConfig::SerializeAsArray() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsArray();
}
-void ChromeActiveProcesses::Serialize(::protozero::Message* msg) const {
- // Field 1: pid
- for (auto& it : pid_) {
- ::protozero::internal::gen_helpers::SerializeVarInt(1, it, msg);
+void DataSourceConfig::Serialize(::protozero::Message* msg) const {
+ // Field 1: name
+ if (_has_field_[1]) {
+ ::protozero::internal::gen_helpers::SerializeString(1, name_, msg);
}
- protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
-}
+ // Field 2: target_buffer
+ if (_has_field_[2]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(2, target_buffer_, msg);
+ }
-} // namespace perfetto
-} // namespace protos
-} // namespace gen
-#if defined(__GNUC__) || defined(__clang__)
-#pragma GCC diagnostic pop
-#endif
-// gen_amalgamated begin source: gen/protos/perfetto/trace/track_event/chrome_application_state_info.gen.cc
-// gen_amalgamated expanded: #include "perfetto/protozero/gen_field_helpers.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/message.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/packed_repeated_fields.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/proto_decoder.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/scattered_heap_buffer.h"
-// DO NOT EDIT. Autogenerated by Perfetto cppgen_plugin
-#if defined(__GNUC__) || defined(__clang__)
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wfloat-equal"
-#endif
-// gen_amalgamated expanded: #include "protos/perfetto/trace/track_event/chrome_application_state_info.gen.h"
+ // Field 11: target_buffer_name
+ if (_has_field_[11]) {
+ ::protozero::internal::gen_helpers::SerializeString(11, target_buffer_name_, msg);
+ }
-namespace perfetto {
-namespace protos {
-namespace gen {
+ // Field 3: trace_duration_ms
+ if (_has_field_[3]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(3, trace_duration_ms_, msg);
+ }
-ChromeApplicationStateInfo::ChromeApplicationStateInfo() = default;
-ChromeApplicationStateInfo::~ChromeApplicationStateInfo() = default;
-ChromeApplicationStateInfo::ChromeApplicationStateInfo(const ChromeApplicationStateInfo&) = default;
-ChromeApplicationStateInfo& ChromeApplicationStateInfo::operator=(const ChromeApplicationStateInfo&) = default;
-ChromeApplicationStateInfo::ChromeApplicationStateInfo(ChromeApplicationStateInfo&&) noexcept = default;
-ChromeApplicationStateInfo& ChromeApplicationStateInfo::operator=(ChromeApplicationStateInfo&&) = default;
+ // Field 122: prefer_suspend_clock_for_duration
+ if (_has_field_[122]) {
+ ::protozero::internal::gen_helpers::SerializeTinyVarInt(122, prefer_suspend_clock_for_duration_, msg);
+ }
-bool ChromeApplicationStateInfo::operator==(const ChromeApplicationStateInfo& other) const {
- return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
- && ::protozero::internal::gen_helpers::EqualsField(application_state_, other.application_state_);
-}
+ // Field 7: stop_timeout_ms
+ if (_has_field_[7]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(7, stop_timeout_ms_, msg);
+ }
-bool ChromeApplicationStateInfo::ParseFromArray(const void* raw, size_t size) {
- unknown_fields_.clear();
- bool packed_error = false;
+ // Field 6: enable_extra_guardrails
+ if (_has_field_[6]) {
+ ::protozero::internal::gen_helpers::SerializeTinyVarInt(6, enable_extra_guardrails_, msg);
+ }
- ::protozero::ProtoDecoder dec(raw, size);
- for (auto field = dec.ReadField(); field.valid(); field = dec.ReadField()) {
- if (field.id() < _has_field_.size()) {
- _has_field_.set(field.id());
- }
- switch (field.id()) {
- case 1 /* application_state */:
- field.get(&application_state_);
- break;
- default:
- field.SerializeAndAppendTo(&unknown_fields_);
- break;
- }
+ // Field 8: session_initiator
+ if (_has_field_[8]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(8, session_initiator_, msg);
}
- return !packed_error && !dec.bytes_left();
-}
-std::string ChromeApplicationStateInfo::SerializeAsString() const {
- ::protozero::internal::gen_helpers::MessageSerializer msg;
- Serialize(msg.get());
- return msg.SerializeAsString();
-}
+ // Field 4: tracing_session_id
+ if (_has_field_[4]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(4, tracing_session_id_, msg);
+ }
-std::vector<uint8_t> ChromeApplicationStateInfo::SerializeAsArray() const {
- ::protozero::internal::gen_helpers::MessageSerializer msg;
- Serialize(msg.get());
- return msg.SerializeAsArray();
-}
+ // Field 9: buffer_exhausted_policy
+ if (_has_field_[9]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(9, buffer_exhausted_policy_, msg);
+ }
-void ChromeApplicationStateInfo::Serialize(::protozero::Message* msg) const {
- // Field 1: application_state
- if (_has_field_[1]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(1, application_state_, msg);
+ // Field 10: priority_boost
+ if (_has_field_[10]) {
+ (*priority_boost_).Serialize(msg->BeginNestedMessage<::protozero::Message>(10));
+ }
+
+ // Field 12: protovm_config
+ if (_has_field_[12]) {
+ (*protovm_config_).Serialize(msg->BeginNestedMessage<::protozero::Message>(12));
+ }
+
+ // Field 147: supports_tracing_v2
+ if (_has_field_[147]) {
+ ::protozero::internal::gen_helpers::SerializeTinyVarInt(147, supports_tracing_v2_, msg);
+ }
+
+ // Field 148: experimental_tracing_v2
+ if (_has_field_[148]) {
+ (*experimental_tracing_v2_).Serialize(msg->BeginNestedMessage<::protozero::Message>(148));
+ }
+
+ // Field 100: ftrace_config
+ if (_has_field_[100]) {
+ msg->AppendString(100, ftrace_config_);
+ }
+
+ // Field 102: inode_file_config
+ if (_has_field_[102]) {
+ msg->AppendString(102, inode_file_config_);
+ }
+
+ // Field 103: process_stats_config
+ if (_has_field_[103]) {
+ msg->AppendString(103, process_stats_config_);
+ }
+
+ // Field 104: sys_stats_config
+ if (_has_field_[104]) {
+ msg->AppendString(104, sys_stats_config_);
+ }
+
+ // Field 105: heapprofd_config
+ if (_has_field_[105]) {
+ msg->AppendString(105, heapprofd_config_);
+ }
+
+ // Field 110: java_hprof_config
+ if (_has_field_[110]) {
+ msg->AppendString(110, java_hprof_config_);
+ }
+
+ // Field 106: android_power_config
+ if (_has_field_[106]) {
+ msg->AppendString(106, android_power_config_);
+ }
+
+ // Field 107: android_log_config
+ if (_has_field_[107]) {
+ msg->AppendString(107, android_log_config_);
+ }
+
+ // Field 108: gpu_counter_config
+ if (_has_field_[108]) {
+ msg->AppendString(108, gpu_counter_config_);
+ }
+
+ // Field 116: android_game_intervention_list_config
+ if (_has_field_[116]) {
+ msg->AppendString(116, android_game_intervention_list_config_);
+ }
+
+ // Field 109: packages_list_config
+ if (_has_field_[109]) {
+ msg->AppendString(109, packages_list_config_);
+ }
+
+ // Field 111: perf_event_config
+ if (_has_field_[111]) {
+ msg->AppendString(111, perf_event_config_);
+ }
+
+ // Field 112: vulkan_memory_config
+ if (_has_field_[112]) {
+ msg->AppendString(112, vulkan_memory_config_);
+ }
+
+ // Field 113: track_event_config
+ if (_has_field_[113]) {
+ msg->AppendString(113, track_event_config_);
+ }
+
+ // Field 114: android_polled_state_config
+ if (_has_field_[114]) {
+ msg->AppendString(114, android_polled_state_config_);
+ }
+
+ // Field 118: android_system_property_config
+ if (_has_field_[118]) {
+ msg->AppendString(118, android_system_property_config_);
+ }
+
+ // Field 117: statsd_tracing_config
+ if (_has_field_[117]) {
+ msg->AppendString(117, statsd_tracing_config_);
+ }
+
+ // Field 119: system_info_config
+ if (_has_field_[119]) {
+ (*system_info_config_).Serialize(msg->BeginNestedMessage<::protozero::Message>(119));
+ }
+
+ // Field 136: frozen_ftrace_config
+ if (_has_field_[136]) {
+ msg->AppendString(136, frozen_ftrace_config_);
+ }
+
+ // Field 101: chrome_config
+ if (_has_field_[101]) {
+ (*chrome_config_).Serialize(msg->BeginNestedMessage<::protozero::Message>(101));
+ }
+
+ // Field 127: v8_config
+ if (_has_field_[127]) {
+ msg->AppendString(127, v8_config_);
+ }
+
+ // Field 115: interceptor_config
+ if (_has_field_[115]) {
+ (*interceptor_config_).Serialize(msg->BeginNestedMessage<::protozero::Message>(115));
+ }
+
+ // Field 120: network_packet_trace_config
+ if (_has_field_[120]) {
+ msg->AppendString(120, network_packet_trace_config_);
+ }
+
+ // Field 121: surfaceflinger_layers_config
+ if (_has_field_[121]) {
+ msg->AppendString(121, surfaceflinger_layers_config_);
+ }
+
+ // Field 123: surfaceflinger_transactions_config
+ if (_has_field_[123]) {
+ msg->AppendString(123, surfaceflinger_transactions_config_);
+ }
+
+ // Field 124: android_sdk_sysprop_guard_config
+ if (_has_field_[124]) {
+ msg->AppendString(124, android_sdk_sysprop_guard_config_);
+ }
+
+ // Field 125: etw_config
+ if (_has_field_[125]) {
+ msg->AppendString(125, etw_config_);
+ }
+
+ // Field 126: protolog_config
+ if (_has_field_[126]) {
+ msg->AppendString(126, protolog_config_);
+ }
+
+ // Field 128: android_input_event_config
+ if (_has_field_[128]) {
+ msg->AppendString(128, android_input_event_config_);
+ }
+
+ // Field 129: pixel_modem_config
+ if (_has_field_[129]) {
+ msg->AppendString(129, pixel_modem_config_);
+ }
+
+ // Field 130: windowmanager_config
+ if (_has_field_[130]) {
+ msg->AppendString(130, windowmanager_config_);
+ }
+
+ // Field 131: chromium_system_metrics
+ if (_has_field_[131]) {
+ msg->AppendString(131, chromium_system_metrics_);
+ }
+
+ // Field 132: kernel_wakelocks_config
+ if (_has_field_[132]) {
+ msg->AppendString(132, kernel_wakelocks_config_);
+ }
+
+ // Field 133: gpu_renderstages_config
+ if (_has_field_[133]) {
+ msg->AppendString(133, gpu_renderstages_config_);
+ }
+
+ // Field 134: chromium_histogram_samples
+ if (_has_field_[134]) {
+ msg->AppendString(134, chromium_histogram_samples_);
+ }
+
+ // Field 135: app_wakelocks_config
+ if (_has_field_[135]) {
+ msg->AppendString(135, app_wakelocks_config_);
+ }
+
+ // Field 137: cpu_per_uid_config
+ if (_has_field_[137]) {
+ msg->AppendString(137, cpu_per_uid_config_);
+ }
+
+ // Field 138: user_list_config
+ if (_has_field_[138]) {
+ msg->AppendString(138, user_list_config_);
+ }
+
+ // Field 139: inputmethod_config
+ if (_has_field_[139]) {
+ msg->AppendString(139, inputmethod_config_);
+ }
+
+ // Field 140: android_aflags_config
+ if (_has_field_[140]) {
+ msg->AppendString(140, android_aflags_config_);
+ }
+
+ // Field 141: journald_config
+ if (_has_field_[141]) {
+ msg->AppendString(141, journald_config_);
+ }
+
+ // Field 142: display_video_config
+ if (_has_field_[142]) {
+ msg->AppendString(142, display_video_config_);
+ }
+
+ // Field 143: chromium_stack_sampling_profiler
+ if (_has_field_[143]) {
+ msg->AppendString(143, chromium_stack_sampling_profiler_);
+ }
+
+ // Field 144: chromium_sampling_heap_profiler
+ if (_has_field_[144]) {
+ msg->AppendString(144, chromium_sampling_heap_profiler_);
+ }
+
+ // Field 145: android_process_state_config
+ if (_has_field_[145]) {
+ msg->AppendString(145, android_process_state_config_);
+ }
+
+ // Field 146: process_smaps_config
+ if (_has_field_[146]) {
+ msg->AppendString(146, process_smaps_config_);
+ }
+
+ // Field 150: qnx_config
+ if (_has_field_[150]) {
+ msg->AppendString(150, qnx_config_);
+ }
+
+ // Field 1000: legacy_config
+ if (_has_field_[1000]) {
+ ::protozero::internal::gen_helpers::SerializeString(1000, legacy_config_, msg);
+ }
+
+ // Field 1001: for_testing
+ if (_has_field_[1001]) {
+ (*for_testing_).Serialize(msg->BeginNestedMessage<::protozero::Message>(1001));
}
protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
}
-} // namespace perfetto
-} // namespace protos
-} // namespace gen
-#if defined(__GNUC__) || defined(__clang__)
-#pragma GCC diagnostic pop
-#endif
-// gen_amalgamated begin source: gen/protos/perfetto/trace/track_event/chrome_compositor_scheduler_state.gen.cc
-// gen_amalgamated expanded: #include "perfetto/protozero/gen_field_helpers.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/message.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/packed_repeated_fields.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/proto_decoder.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/scattered_heap_buffer.h"
-// DO NOT EDIT. Autogenerated by Perfetto cppgen_plugin
-#if defined(__GNUC__) || defined(__clang__)
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wfloat-equal"
-#endif
-// gen_amalgamated expanded: #include "protos/perfetto/trace/track_event/chrome_compositor_scheduler_state.gen.h"
-// gen_amalgamated expanded: #include "protos/perfetto/trace/track_event/source_location.gen.h"
-
-namespace perfetto {
-namespace protos {
-namespace gen {
-CompositorTimingHistory::CompositorTimingHistory() = default;
-CompositorTimingHistory::~CompositorTimingHistory() = default;
-CompositorTimingHistory::CompositorTimingHistory(const CompositorTimingHistory&) = default;
-CompositorTimingHistory& CompositorTimingHistory::operator=(const CompositorTimingHistory&) = default;
-CompositorTimingHistory::CompositorTimingHistory(CompositorTimingHistory&&) noexcept = default;
-CompositorTimingHistory& CompositorTimingHistory::operator=(CompositorTimingHistory&&) = default;
+DataSourceConfig_ExperimentalTracingV2Config::DataSourceConfig_ExperimentalTracingV2Config() = default;
+DataSourceConfig_ExperimentalTracingV2Config::~DataSourceConfig_ExperimentalTracingV2Config() = default;
+DataSourceConfig_ExperimentalTracingV2Config::DataSourceConfig_ExperimentalTracingV2Config(const DataSourceConfig_ExperimentalTracingV2Config&) = default;
+DataSourceConfig_ExperimentalTracingV2Config& DataSourceConfig_ExperimentalTracingV2Config::operator=(const DataSourceConfig_ExperimentalTracingV2Config&) = default;
+DataSourceConfig_ExperimentalTracingV2Config::DataSourceConfig_ExperimentalTracingV2Config(DataSourceConfig_ExperimentalTracingV2Config&&) noexcept = default;
+DataSourceConfig_ExperimentalTracingV2Config& DataSourceConfig_ExperimentalTracingV2Config::operator=(DataSourceConfig_ExperimentalTracingV2Config&&) = default;
-bool CompositorTimingHistory::operator==(const CompositorTimingHistory& other) const {
+bool DataSourceConfig_ExperimentalTracingV2Config::operator==(const DataSourceConfig_ExperimentalTracingV2Config& other) const {
return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
- && ::protozero::internal::gen_helpers::EqualsField(begin_main_frame_queue_critical_estimate_delta_us_, other.begin_main_frame_queue_critical_estimate_delta_us_)
- && ::protozero::internal::gen_helpers::EqualsField(begin_main_frame_queue_not_critical_estimate_delta_us_, other.begin_main_frame_queue_not_critical_estimate_delta_us_)
- && ::protozero::internal::gen_helpers::EqualsField(begin_main_frame_start_to_ready_to_commit_estimate_delta_us_, other.begin_main_frame_start_to_ready_to_commit_estimate_delta_us_)
- && ::protozero::internal::gen_helpers::EqualsField(commit_to_ready_to_activate_estimate_delta_us_, other.commit_to_ready_to_activate_estimate_delta_us_)
- && ::protozero::internal::gen_helpers::EqualsField(prepare_tiles_estimate_delta_us_, other.prepare_tiles_estimate_delta_us_)
- && ::protozero::internal::gen_helpers::EqualsField(activate_estimate_delta_us_, other.activate_estimate_delta_us_)
- && ::protozero::internal::gen_helpers::EqualsField(draw_estimate_delta_us_, other.draw_estimate_delta_us_);
+ && ::protozero::internal::gen_helpers::EqualsField(use_v2_probability_percent_, other.use_v2_probability_percent_)
+ && ::protozero::internal::gen_helpers::EqualsField(chunk_size_options_, other.chunk_size_options_)
+ && ::protozero::internal::gen_helpers::EqualsField(drain_occupancy_percent_, other.drain_occupancy_percent_);
}
-bool CompositorTimingHistory::ParseFromArray(const void* raw, size_t size) {
+int DataSourceConfig_ExperimentalTracingV2Config::chunk_size_options_size() const { return static_cast<int>(chunk_size_options_.size()); }
+void DataSourceConfig_ExperimentalTracingV2Config::clear_chunk_size_options() { chunk_size_options_.clear(); }
+DataSourceConfig_ExperimentalTracingV2Config_ChunkSizeOption* DataSourceConfig_ExperimentalTracingV2Config::add_chunk_size_options() { chunk_size_options_.emplace_back(); return &chunk_size_options_.back(); }
+bool DataSourceConfig_ExperimentalTracingV2Config::ParseFromArray(const void* raw, size_t size) {
+ chunk_size_options_.clear();
unknown_fields_.clear();
bool packed_error = false;
@@ -32429,26 +32478,15 @@ bool CompositorTimingHistory::ParseFromArray(const void* raw, size_t size) {
_has_field_.set(field.id());
}
switch (field.id()) {
- case 1 /* begin_main_frame_queue_critical_estimate_delta_us */:
- field.get(&begin_main_frame_queue_critical_estimate_delta_us_);
- break;
- case 2 /* begin_main_frame_queue_not_critical_estimate_delta_us */:
- field.get(&begin_main_frame_queue_not_critical_estimate_delta_us_);
- break;
- case 3 /* begin_main_frame_start_to_ready_to_commit_estimate_delta_us */:
- field.get(&begin_main_frame_start_to_ready_to_commit_estimate_delta_us_);
+ case 1 /* use_v2_probability_percent */:
+ field.get(&use_v2_probability_percent_);
break;
- case 4 /* commit_to_ready_to_activate_estimate_delta_us */:
- field.get(&commit_to_ready_to_activate_estimate_delta_us_);
- break;
- case 5 /* prepare_tiles_estimate_delta_us */:
- field.get(&prepare_tiles_estimate_delta_us_);
- break;
- case 6 /* activate_estimate_delta_us */:
- field.get(&activate_estimate_delta_us_);
+ case 2 /* chunk_size_options */:
+ chunk_size_options_.emplace_back();
+ chunk_size_options_.back().ParseFromArray(field.data(), field.size());
break;
- case 7 /* draw_estimate_delta_us */:
- field.get(&draw_estimate_delta_us_);
+ case 3 /* drain_occupancy_percent */:
+ field.get(&drain_occupancy_percent_);
break;
default:
field.SerializeAndAppendTo(&unknown_fields_);
@@ -32458,74 +32496,52 @@ bool CompositorTimingHistory::ParseFromArray(const void* raw, size_t size) {
return !packed_error && !dec.bytes_left();
}
-std::string CompositorTimingHistory::SerializeAsString() const {
+std::string DataSourceConfig_ExperimentalTracingV2Config::SerializeAsString() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsString();
}
-std::vector<uint8_t> CompositorTimingHistory::SerializeAsArray() const {
+std::vector<uint8_t> DataSourceConfig_ExperimentalTracingV2Config::SerializeAsArray() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsArray();
}
-void CompositorTimingHistory::Serialize(::protozero::Message* msg) const {
- // Field 1: begin_main_frame_queue_critical_estimate_delta_us
+void DataSourceConfig_ExperimentalTracingV2Config::Serialize(::protozero::Message* msg) const {
+ // Field 1: use_v2_probability_percent
if (_has_field_[1]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(1, begin_main_frame_queue_critical_estimate_delta_us_, msg);
+ ::protozero::internal::gen_helpers::SerializeVarInt(1, use_v2_probability_percent_, msg);
}
- // Field 2: begin_main_frame_queue_not_critical_estimate_delta_us
- if (_has_field_[2]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(2, begin_main_frame_queue_not_critical_estimate_delta_us_, msg);
+ // Field 2: chunk_size_options
+ for (auto& it : chunk_size_options_) {
+ it.Serialize(msg->BeginNestedMessage<::protozero::Message>(2));
}
- // Field 3: begin_main_frame_start_to_ready_to_commit_estimate_delta_us
+ // Field 3: drain_occupancy_percent
if (_has_field_[3]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(3, begin_main_frame_start_to_ready_to_commit_estimate_delta_us_, msg);
- }
-
- // Field 4: commit_to_ready_to_activate_estimate_delta_us
- if (_has_field_[4]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(4, commit_to_ready_to_activate_estimate_delta_us_, msg);
- }
-
- // Field 5: prepare_tiles_estimate_delta_us
- if (_has_field_[5]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(5, prepare_tiles_estimate_delta_us_, msg);
- }
-
- // Field 6: activate_estimate_delta_us
- if (_has_field_[6]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(6, activate_estimate_delta_us_, msg);
- }
-
- // Field 7: draw_estimate_delta_us
- if (_has_field_[7]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(7, draw_estimate_delta_us_, msg);
+ ::protozero::internal::gen_helpers::SerializeVarInt(3, drain_occupancy_percent_, msg);
}
protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
}
-BeginFrameSourceState::BeginFrameSourceState() = default;
-BeginFrameSourceState::~BeginFrameSourceState() = default;
-BeginFrameSourceState::BeginFrameSourceState(const BeginFrameSourceState&) = default;
-BeginFrameSourceState& BeginFrameSourceState::operator=(const BeginFrameSourceState&) = default;
-BeginFrameSourceState::BeginFrameSourceState(BeginFrameSourceState&&) noexcept = default;
-BeginFrameSourceState& BeginFrameSourceState::operator=(BeginFrameSourceState&&) = default;
+DataSourceConfig_ExperimentalTracingV2Config_ChunkSizeOption::DataSourceConfig_ExperimentalTracingV2Config_ChunkSizeOption() = default;
+DataSourceConfig_ExperimentalTracingV2Config_ChunkSizeOption::~DataSourceConfig_ExperimentalTracingV2Config_ChunkSizeOption() = default;
+DataSourceConfig_ExperimentalTracingV2Config_ChunkSizeOption::DataSourceConfig_ExperimentalTracingV2Config_ChunkSizeOption(const DataSourceConfig_ExperimentalTracingV2Config_ChunkSizeOption&) = default;
+DataSourceConfig_ExperimentalTracingV2Config_ChunkSizeOption& DataSourceConfig_ExperimentalTracingV2Config_ChunkSizeOption::operator=(const DataSourceConfig_ExperimentalTracingV2Config_ChunkSizeOption&) = default;
+DataSourceConfig_ExperimentalTracingV2Config_ChunkSizeOption::DataSourceConfig_ExperimentalTracingV2Config_ChunkSizeOption(DataSourceConfig_ExperimentalTracingV2Config_ChunkSizeOption&&) noexcept = default;
+DataSourceConfig_ExperimentalTracingV2Config_ChunkSizeOption& DataSourceConfig_ExperimentalTracingV2Config_ChunkSizeOption::operator=(DataSourceConfig_ExperimentalTracingV2Config_ChunkSizeOption&&) = default;
-bool BeginFrameSourceState::operator==(const BeginFrameSourceState& other) const {
+bool DataSourceConfig_ExperimentalTracingV2Config_ChunkSizeOption::operator==(const DataSourceConfig_ExperimentalTracingV2Config_ChunkSizeOption& other) const {
return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
- && ::protozero::internal::gen_helpers::EqualsField(source_id_, other.source_id_)
- && ::protozero::internal::gen_helpers::EqualsField(paused_, other.paused_)
- && ::protozero::internal::gen_helpers::EqualsField(num_observers_, other.num_observers_)
- && ::protozero::internal::gen_helpers::EqualsField(last_begin_frame_args_, other.last_begin_frame_args_);
+ && ::protozero::internal::gen_helpers::EqualsField(size_bytes_, other.size_bytes_)
+ && ::protozero::internal::gen_helpers::EqualsField(weight_, other.weight_);
}
-bool BeginFrameSourceState::ParseFromArray(const void* raw, size_t size) {
+bool DataSourceConfig_ExperimentalTracingV2Config_ChunkSizeOption::ParseFromArray(const void* raw, size_t size) {
unknown_fields_.clear();
bool packed_error = false;
@@ -32535,17 +32551,11 @@ bool BeginFrameSourceState::ParseFromArray(const void* raw, size_t size) {
_has_field_.set(field.id());
}
switch (field.id()) {
- case 1 /* source_id */:
- field.get(&source_id_);
- break;
- case 2 /* paused */:
- field.get(&paused_);
- break;
- case 3 /* num_observers */:
- field.get(&num_observers_);
+ case 1 /* size_bytes */:
+ field.get(&size_bytes_);
break;
- case 4 /* last_begin_frame_args */:
- (*last_begin_frame_args_).ParseFromArray(field.data(), field.size());
+ case 2 /* weight */:
+ field.get(&weight_);
break;
default:
field.SerializeAndAppendTo(&unknown_fields_);
@@ -32555,66 +32565,86 @@ bool BeginFrameSourceState::ParseFromArray(const void* raw, size_t size) {
return !packed_error && !dec.bytes_left();
}
-std::string BeginFrameSourceState::SerializeAsString() const {
+std::string DataSourceConfig_ExperimentalTracingV2Config_ChunkSizeOption::SerializeAsString() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsString();
}
-std::vector<uint8_t> BeginFrameSourceState::SerializeAsArray() const {
+std::vector<uint8_t> DataSourceConfig_ExperimentalTracingV2Config_ChunkSizeOption::SerializeAsArray() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsArray();
}
-void BeginFrameSourceState::Serialize(::protozero::Message* msg) const {
- // Field 1: source_id
+void DataSourceConfig_ExperimentalTracingV2Config_ChunkSizeOption::Serialize(::protozero::Message* msg) const {
+ // Field 1: size_bytes
if (_has_field_[1]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(1, source_id_, msg);
+ ::protozero::internal::gen_helpers::SerializeVarInt(1, size_bytes_, msg);
}
- // Field 2: paused
+ // Field 2: weight
if (_has_field_[2]) {
- ::protozero::internal::gen_helpers::SerializeTinyVarInt(2, paused_, msg);
- }
-
- // Field 3: num_observers
- if (_has_field_[3]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(3, num_observers_, msg);
- }
-
- // Field 4: last_begin_frame_args
- if (_has_field_[4]) {
- (*last_begin_frame_args_).Serialize(msg->BeginNestedMessage<::protozero::Message>(4));
+ ::protozero::internal::gen_helpers::SerializeVarInt(2, weight_, msg);
}
protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
}
+} // namespace perfetto
+} // namespace protos
+} // namespace gen
+#if defined(__GNUC__) || defined(__clang__)
+#pragma GCC diagnostic pop
+#endif
+// gen_amalgamated begin source: gen/protos/perfetto/config/etw/etw_config.gen.cc
+// gen_amalgamated expanded: #include "perfetto/protozero/gen_field_helpers.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/message.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/packed_repeated_fields.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/proto_decoder.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/scattered_heap_buffer.h"
+// DO NOT EDIT. Autogenerated by Perfetto cppgen_plugin
+#if defined(__GNUC__) || defined(__clang__)
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wfloat-equal"
+#endif
+// gen_amalgamated expanded: #include "protos/perfetto/config/etw/etw_config.gen.h"
-BeginFrameArgs::BeginFrameArgs() = default;
-BeginFrameArgs::~BeginFrameArgs() = default;
-BeginFrameArgs::BeginFrameArgs(const BeginFrameArgs&) = default;
-BeginFrameArgs& BeginFrameArgs::operator=(const BeginFrameArgs&) = default;
-BeginFrameArgs::BeginFrameArgs(BeginFrameArgs&&) noexcept = default;
-BeginFrameArgs& BeginFrameArgs::operator=(BeginFrameArgs&&) = default;
+namespace perfetto {
+namespace protos {
+namespace gen {
-bool BeginFrameArgs::operator==(const BeginFrameArgs& other) const {
+EtwConfig::EtwConfig() = default;
+EtwConfig::~EtwConfig() = default;
+EtwConfig::EtwConfig(const EtwConfig&) = default;
+EtwConfig& EtwConfig::operator=(const EtwConfig&) = default;
+EtwConfig::EtwConfig(EtwConfig&&) noexcept = default;
+EtwConfig& EtwConfig::operator=(EtwConfig&&) = default;
+
+bool EtwConfig::operator==(const EtwConfig& other) const {
return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
- && ::protozero::internal::gen_helpers::EqualsField(type_, other.type_)
- && ::protozero::internal::gen_helpers::EqualsField(source_id_, other.source_id_)
- && ::protozero::internal::gen_helpers::EqualsField(sequence_number_, other.sequence_number_)
- && ::protozero::internal::gen_helpers::EqualsField(frame_time_us_, other.frame_time_us_)
- && ::protozero::internal::gen_helpers::EqualsField(deadline_us_, other.deadline_us_)
- && ::protozero::internal::gen_helpers::EqualsField(interval_delta_us_, other.interval_delta_us_)
- && ::protozero::internal::gen_helpers::EqualsField(on_critical_path_, other.on_critical_path_)
- && ::protozero::internal::gen_helpers::EqualsField(animate_only_, other.animate_only_)
- && ::protozero::internal::gen_helpers::EqualsField(source_location_iid_, other.source_location_iid_)
- && ::protozero::internal::gen_helpers::EqualsField(source_location_, other.source_location_)
- && ::protozero::internal::gen_helpers::EqualsField(frames_throttled_since_last_, other.frames_throttled_since_last_);
+ && ::protozero::internal::gen_helpers::EqualsField(kernel_flags_, other.kernel_flags_)
+ && ::protozero::internal::gen_helpers::EqualsField(scheduler_provider_events_, other.scheduler_provider_events_)
+ && ::protozero::internal::gen_helpers::EqualsField(memory_provider_events_, other.memory_provider_events_)
+ && ::protozero::internal::gen_helpers::EqualsField(file_provider_events_, other.file_provider_events_)
+ && ::protozero::internal::gen_helpers::EqualsField(stack_sampling_events_, other.stack_sampling_events_)
+ && ::protozero::internal::gen_helpers::EqualsField(disk_provider_events_, other.disk_provider_events_)
+ && ::protozero::internal::gen_helpers::EqualsField(system_io_provider_events_, other.system_io_provider_events_)
+ && ::protozero::internal::gen_helpers::EqualsField(stack_sampling_debug_ids_, other.stack_sampling_debug_ids_);
}
-bool BeginFrameArgs::ParseFromArray(const void* raw, size_t size) {
+int EtwConfig::stack_sampling_debug_ids_size() const { return static_cast<int>(stack_sampling_debug_ids_.size()); }
+void EtwConfig::clear_stack_sampling_debug_ids() { stack_sampling_debug_ids_.clear(); }
+EtwConfig_DebugId* EtwConfig::add_stack_sampling_debug_ids() { stack_sampling_debug_ids_.emplace_back(); return &stack_sampling_debug_ids_.back(); }
+bool EtwConfig::ParseFromArray(const void* raw, size_t size) {
+ kernel_flags_.clear();
+ scheduler_provider_events_.clear();
+ memory_provider_events_.clear();
+ file_provider_events_.clear();
+ stack_sampling_events_.clear();
+ disk_provider_events_.clear();
+ system_io_provider_events_.clear();
+ stack_sampling_debug_ids_.clear();
unknown_fields_.clear();
bool packed_error = false;
@@ -32624,38 +32654,37 @@ bool BeginFrameArgs::ParseFromArray(const void* raw, size_t size) {
_has_field_.set(field.id());
}
switch (field.id()) {
- case 1 /* type */:
- field.get(&type_);
- break;
- case 2 /* source_id */:
- field.get(&source_id_);
- break;
- case 3 /* sequence_number */:
- field.get(&sequence_number_);
- break;
- case 4 /* frame_time_us */:
- field.get(&frame_time_us_);
+ case 1 /* kernel_flags */:
+ kernel_flags_.emplace_back();
+ field.get(&kernel_flags_.back());
break;
- case 5 /* deadline_us */:
- field.get(&deadline_us_);
+ case 2 /* scheduler_provider_events */:
+ scheduler_provider_events_.emplace_back();
+ ::protozero::internal::gen_helpers::DeserializeString(field, &scheduler_provider_events_.back());
break;
- case 6 /* interval_delta_us */:
- field.get(&interval_delta_us_);
+ case 3 /* memory_provider_events */:
+ memory_provider_events_.emplace_back();
+ ::protozero::internal::gen_helpers::DeserializeString(field, &memory_provider_events_.back());
break;
- case 7 /* on_critical_path */:
- field.get(&on_critical_path_);
+ case 4 /* file_provider_events */:
+ file_provider_events_.emplace_back();
+ ::protozero::internal::gen_helpers::DeserializeString(field, &file_provider_events_.back());
break;
- case 8 /* animate_only */:
- field.get(&animate_only_);
+ case 5 /* stack_sampling_events */:
+ stack_sampling_events_.emplace_back();
+ ::protozero::internal::gen_helpers::DeserializeString(field, &stack_sampling_events_.back());
break;
- case 9 /* source_location_iid */:
- field.get(&source_location_iid_);
+ case 6 /* disk_provider_events */:
+ disk_provider_events_.emplace_back();
+ ::protozero::internal::gen_helpers::DeserializeString(field, &disk_provider_events_.back());
break;
- case 10 /* source_location */:
- (*source_location_).ParseFromArray(field.data(), field.size());
+ case 7 /* system_io_provider_events */:
+ system_io_provider_events_.emplace_back();
+ ::protozero::internal::gen_helpers::DeserializeString(field, &system_io_provider_events_.back());
break;
- case 12 /* frames_throttled_since_last */:
- field.get(&frames_throttled_since_last_);
+ case 8 /* stack_sampling_debug_ids */:
+ stack_sampling_debug_ids_.emplace_back();
+ stack_sampling_debug_ids_.back().ParseFromArray(field.data(), field.size());
break;
default:
field.SerializeAndAppendTo(&unknown_fields_);
@@ -32665,92 +32694,164 @@ bool BeginFrameArgs::ParseFromArray(const void* raw, size_t size) {
return !packed_error && !dec.bytes_left();
}
-std::string BeginFrameArgs::SerializeAsString() const {
+std::string EtwConfig::SerializeAsString() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsString();
}
-std::vector<uint8_t> BeginFrameArgs::SerializeAsArray() const {
+std::vector<uint8_t> EtwConfig::SerializeAsArray() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsArray();
}
-void BeginFrameArgs::Serialize(::protozero::Message* msg) const {
- // Field 1: type
- if (_has_field_[1]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(1, type_, msg);
+void EtwConfig::Serialize(::protozero::Message* msg) const {
+ // Field 1: kernel_flags
+ for (auto& it : kernel_flags_) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(1, it, msg);
}
- // Field 2: source_id
- if (_has_field_[2]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(2, source_id_, msg);
+ // Field 2: scheduler_provider_events
+ for (auto& it : scheduler_provider_events_) {
+ ::protozero::internal::gen_helpers::SerializeString(2, it, msg);
}
- // Field 3: sequence_number
- if (_has_field_[3]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(3, sequence_number_, msg);
+ // Field 3: memory_provider_events
+ for (auto& it : memory_provider_events_) {
+ ::protozero::internal::gen_helpers::SerializeString(3, it, msg);
}
- // Field 4: frame_time_us
- if (_has_field_[4]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(4, frame_time_us_, msg);
+ // Field 4: file_provider_events
+ for (auto& it : file_provider_events_) {
+ ::protozero::internal::gen_helpers::SerializeString(4, it, msg);
}
- // Field 5: deadline_us
- if (_has_field_[5]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(5, deadline_us_, msg);
+ // Field 5: stack_sampling_events
+ for (auto& it : stack_sampling_events_) {
+ ::protozero::internal::gen_helpers::SerializeString(5, it, msg);
}
- // Field 6: interval_delta_us
- if (_has_field_[6]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(6, interval_delta_us_, msg);
+ // Field 6: disk_provider_events
+ for (auto& it : disk_provider_events_) {
+ ::protozero::internal::gen_helpers::SerializeString(6, it, msg);
}
- // Field 7: on_critical_path
- if (_has_field_[7]) {
- ::protozero::internal::gen_helpers::SerializeTinyVarInt(7, on_critical_path_, msg);
+ // Field 7: system_io_provider_events
+ for (auto& it : system_io_provider_events_) {
+ ::protozero::internal::gen_helpers::SerializeString(7, it, msg);
}
- // Field 8: animate_only
- if (_has_field_[8]) {
- ::protozero::internal::gen_helpers::SerializeTinyVarInt(8, animate_only_, msg);
+ // Field 8: stack_sampling_debug_ids
+ for (auto& it : stack_sampling_debug_ids_) {
+ it.Serialize(msg->BeginNestedMessage<::protozero::Message>(8));
}
- // Field 9: source_location_iid
- if (_has_field_[9]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(9, source_location_iid_, msg);
+ protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
+}
+
+
+EtwConfig_DebugId::EtwConfig_DebugId() = default;
+EtwConfig_DebugId::~EtwConfig_DebugId() = default;
+EtwConfig_DebugId::EtwConfig_DebugId(const EtwConfig_DebugId&) = default;
+EtwConfig_DebugId& EtwConfig_DebugId::operator=(const EtwConfig_DebugId&) = default;
+EtwConfig_DebugId::EtwConfig_DebugId(EtwConfig_DebugId&&) noexcept = default;
+EtwConfig_DebugId& EtwConfig_DebugId::operator=(EtwConfig_DebugId&&) = default;
+
+bool EtwConfig_DebugId::operator==(const EtwConfig_DebugId& other) const {
+ return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
+ && ::protozero::internal::gen_helpers::EqualsField(path_, other.path_)
+ && ::protozero::internal::gen_helpers::EqualsField(debug_id_, other.debug_id_);
+}
+
+bool EtwConfig_DebugId::ParseFromArray(const void* raw, size_t size) {
+ unknown_fields_.clear();
+ bool packed_error = false;
+
+ ::protozero::ProtoDecoder dec(raw, size);
+ for (auto field = dec.ReadField(); field.valid(); field = dec.ReadField()) {
+ if (field.id() < _has_field_.size()) {
+ _has_field_.set(field.id());
+ }
+ switch (field.id()) {
+ case 1 /* path */:
+ ::protozero::internal::gen_helpers::DeserializeString(field, &path_);
+ break;
+ case 2 /* debug_id */:
+ ::protozero::internal::gen_helpers::DeserializeString(field, &debug_id_);
+ break;
+ default:
+ field.SerializeAndAppendTo(&unknown_fields_);
+ break;
+ }
}
+ return !packed_error && !dec.bytes_left();
+}
- // Field 10: source_location
- if (_has_field_[10]) {
- (*source_location_).Serialize(msg->BeginNestedMessage<::protozero::Message>(10));
+std::string EtwConfig_DebugId::SerializeAsString() const {
+ ::protozero::internal::gen_helpers::MessageSerializer msg;
+ Serialize(msg.get());
+ return msg.SerializeAsString();
+}
+
+std::vector<uint8_t> EtwConfig_DebugId::SerializeAsArray() const {
+ ::protozero::internal::gen_helpers::MessageSerializer msg;
+ Serialize(msg.get());
+ return msg.SerializeAsArray();
+}
+
+void EtwConfig_DebugId::Serialize(::protozero::Message* msg) const {
+ // Field 1: path
+ if (_has_field_[1]) {
+ ::protozero::internal::gen_helpers::SerializeString(1, path_, msg);
}
- // Field 12: frames_throttled_since_last
- if (_has_field_[12]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(12, frames_throttled_since_last_, msg);
+ // Field 2: debug_id
+ if (_has_field_[2]) {
+ ::protozero::internal::gen_helpers::SerializeString(2, debug_id_, msg);
}
protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
}
+} // namespace perfetto
+} // namespace protos
+} // namespace gen
+#if defined(__GNUC__) || defined(__clang__)
+#pragma GCC diagnostic pop
+#endif
+// gen_amalgamated begin source: gen/protos/perfetto/config/interceptor_config.gen.cc
+// gen_amalgamated expanded: #include "perfetto/protozero/gen_field_helpers.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/message.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/packed_repeated_fields.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/proto_decoder.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/scattered_heap_buffer.h"
+// DO NOT EDIT. Autogenerated by Perfetto cppgen_plugin
+#if defined(__GNUC__) || defined(__clang__)
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wfloat-equal"
+#endif
+// gen_amalgamated expanded: #include "protos/perfetto/config/interceptor_config.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/config/interceptors/console_config.gen.h"
+
+namespace perfetto {
+namespace protos {
+namespace gen {
-BeginFrameObserverState::BeginFrameObserverState() = default;
-BeginFrameObserverState::~BeginFrameObserverState() = default;
-BeginFrameObserverState::BeginFrameObserverState(const BeginFrameObserverState&) = default;
-BeginFrameObserverState& BeginFrameObserverState::operator=(const BeginFrameObserverState&) = default;
-BeginFrameObserverState::BeginFrameObserverState(BeginFrameObserverState&&) noexcept = default;
-BeginFrameObserverState& BeginFrameObserverState::operator=(BeginFrameObserverState&&) = default;
+InterceptorConfig::InterceptorConfig() = default;
+InterceptorConfig::~InterceptorConfig() = default;
+InterceptorConfig::InterceptorConfig(const InterceptorConfig&) = default;
+InterceptorConfig& InterceptorConfig::operator=(const InterceptorConfig&) = default;
+InterceptorConfig::InterceptorConfig(InterceptorConfig&&) noexcept = default;
+InterceptorConfig& InterceptorConfig::operator=(InterceptorConfig&&) = default;
-bool BeginFrameObserverState::operator==(const BeginFrameObserverState& other) const {
+bool InterceptorConfig::operator==(const InterceptorConfig& other) const {
return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
- && ::protozero::internal::gen_helpers::EqualsField(dropped_begin_frame_args_, other.dropped_begin_frame_args_)
- && ::protozero::internal::gen_helpers::EqualsField(last_begin_frame_args_, other.last_begin_frame_args_);
+ && ::protozero::internal::gen_helpers::EqualsField(name_, other.name_)
+ && ::protozero::internal::gen_helpers::EqualsField(console_config_, other.console_config_);
}
-bool BeginFrameObserverState::ParseFromArray(const void* raw, size_t size) {
+bool InterceptorConfig::ParseFromArray(const void* raw, size_t size) {
unknown_fields_.clear();
bool packed_error = false;
@@ -32760,11 +32861,11 @@ bool BeginFrameObserverState::ParseFromArray(const void* raw, size_t size) {
_has_field_.set(field.id());
}
switch (field.id()) {
- case 1 /* dropped_begin_frame_args */:
- field.get(&dropped_begin_frame_args_);
+ case 1 /* name */:
+ ::protozero::internal::gen_helpers::DeserializeString(field, &name_);
break;
- case 2 /* last_begin_frame_args */:
- (*last_begin_frame_args_).ParseFromArray(field.data(), field.size());
+ case 100 /* console_config */:
+ (*console_config_).ParseFromArray(field.data(), field.size());
break;
default:
field.SerializeAndAppendTo(&unknown_fields_);
@@ -32774,51 +32875,138 @@ bool BeginFrameObserverState::ParseFromArray(const void* raw, size_t size) {
return !packed_error && !dec.bytes_left();
}
-std::string BeginFrameObserverState::SerializeAsString() const {
+std::string InterceptorConfig::SerializeAsString() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsString();
}
-std::vector<uint8_t> BeginFrameObserverState::SerializeAsArray() const {
+std::vector<uint8_t> InterceptorConfig::SerializeAsArray() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsArray();
}
-void BeginFrameObserverState::Serialize(::protozero::Message* msg) const {
- // Field 1: dropped_begin_frame_args
+void InterceptorConfig::Serialize(::protozero::Message* msg) const {
+ // Field 1: name
if (_has_field_[1]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(1, dropped_begin_frame_args_, msg);
+ ::protozero::internal::gen_helpers::SerializeString(1, name_, msg);
}
- // Field 2: last_begin_frame_args
- if (_has_field_[2]) {
- (*last_begin_frame_args_).Serialize(msg->BeginNestedMessage<::protozero::Message>(2));
+ // Field 100: console_config
+ if (_has_field_[100]) {
+ (*console_config_).Serialize(msg->BeginNestedMessage<::protozero::Message>(100));
}
protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
}
+} // namespace perfetto
+} // namespace protos
+} // namespace gen
+#if defined(__GNUC__) || defined(__clang__)
+#pragma GCC diagnostic pop
+#endif
+// gen_amalgamated begin source: gen/protos/perfetto/config/stress_test_config.gen.cc
+// gen_amalgamated expanded: #include "perfetto/protozero/gen_field_helpers.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/message.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/packed_repeated_fields.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/proto_decoder.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/scattered_heap_buffer.h"
+// DO NOT EDIT. Autogenerated by Perfetto cppgen_plugin
+#if defined(__GNUC__) || defined(__clang__)
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wfloat-equal"
+#endif
+// gen_amalgamated expanded: #include "protos/perfetto/config/stress_test_config.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/config/trace_config.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/config/priority_boost/priority_boost_config.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/config/data_source_config.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/config/qnx/qnx_config.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/config/linux/journald_config.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/config/chrome/stack_sampling_profiler.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/config/chrome/sampling_heap_profiler.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/config/chrome/histogram_samples.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/config/system_info/system_info_config.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/config/track_event/track_event_config.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/config/test_config.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/config/sys_stats/sys_stats_config.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/common/sys_stats_counters.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/config/profiling/smaps_config.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/config/profiling/perf_event_config.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/common/perf_events.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/config/profiling/java_hprof_config.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/config/profiling/heapprofd_config.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/config/process_stats/process_stats_config.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/config/statsd/statsd_tracing_config.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/config/statsd/atom_ids.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/config/protovm/protovm_config.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/config/power/android_power_config.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/config/interceptor_config.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/config/interceptors/console_config.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/config/inode_file/inode_file_config.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/config/gpu/gpu_renderstages_config.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/config/gpu/vulkan_memory_config.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/config/gpu/gpu_counter_config.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/config/ftrace/frozen_ftrace_config.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/config/ftrace/ftrace_config.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/config/chrome/system_metrics.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/config/etw/etw_config.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/config/chrome/v8_config.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/config/chrome/chrome_config.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/config/android/windowmanager_config.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/config/android/user_list_config.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/config/android/surfaceflinger_transactions_config.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/config/android/surfaceflinger_layers_config.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/config/android/display_video_config.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/config/android/protolog_config.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/config/android/pixel_modem_config.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/config/android/packages_list_config.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/config/android/network_trace_config.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/config/android/kernel_wakelocks_config.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/config/android/inputmethod_config.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/config/android/cpu_per_uid_config.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/config/android/app_wakelock_config.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/config/android/android_sdk_sysprop_guard_config.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/config/android/android_system_property_config.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/config/android/android_process_state_config.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/config/android/android_polled_state_config.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/config/android/android_log_config.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/common/android_log_constants.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/config/android/android_input_event_config.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/config/android/android_game_intervention_list_config.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/config/android/android_aflags_config.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/common/trace_attributes.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/common/semantic_type.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/common/builtin_clock.gen.h"
+
+namespace perfetto {
+namespace protos {
+namespace gen {
-BeginImplFrameArgs::BeginImplFrameArgs() = default;
-BeginImplFrameArgs::~BeginImplFrameArgs() = default;
-BeginImplFrameArgs::BeginImplFrameArgs(const BeginImplFrameArgs&) = default;
-BeginImplFrameArgs& BeginImplFrameArgs::operator=(const BeginImplFrameArgs&) = default;
-BeginImplFrameArgs::BeginImplFrameArgs(BeginImplFrameArgs&&) noexcept = default;
-BeginImplFrameArgs& BeginImplFrameArgs::operator=(BeginImplFrameArgs&&) = default;
+StressTestConfig::StressTestConfig() = default;
+StressTestConfig::~StressTestConfig() = default;
+StressTestConfig::StressTestConfig(const StressTestConfig&) = default;
+StressTestConfig& StressTestConfig::operator=(const StressTestConfig&) = default;
+StressTestConfig::StressTestConfig(StressTestConfig&&) noexcept = default;
+StressTestConfig& StressTestConfig::operator=(StressTestConfig&&) = default;
-bool BeginImplFrameArgs::operator==(const BeginImplFrameArgs& other) const {
+bool StressTestConfig::operator==(const StressTestConfig& other) const {
return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
- && ::protozero::internal::gen_helpers::EqualsField(updated_at_us_, other.updated_at_us_)
- && ::protozero::internal::gen_helpers::EqualsField(finished_at_us_, other.finished_at_us_)
- && ::protozero::internal::gen_helpers::EqualsField(state_, other.state_)
- && ::protozero::internal::gen_helpers::EqualsField(current_args_, other.current_args_)
- && ::protozero::internal::gen_helpers::EqualsField(last_args_, other.last_args_)
- && ::protozero::internal::gen_helpers::EqualsField(timestamps_in_us_, other.timestamps_in_us_);
+ && ::protozero::internal::gen_helpers::EqualsField(trace_config_, other.trace_config_)
+ && ::protozero::internal::gen_helpers::EqualsField(shmem_size_kb_, other.shmem_size_kb_)
+ && ::protozero::internal::gen_helpers::EqualsField(shmem_page_size_kb_, other.shmem_page_size_kb_)
+ && ::protozero::internal::gen_helpers::EqualsField(num_processes_, other.num_processes_)
+ && ::protozero::internal::gen_helpers::EqualsField(num_threads_, other.num_threads_)
+ && ::protozero::internal::gen_helpers::EqualsField(max_events_, other.max_events_)
+ && ::protozero::internal::gen_helpers::EqualsField(nesting_, other.nesting_)
+ && ::protozero::internal::gen_helpers::EqualsField(steady_state_timings_, other.steady_state_timings_)
+ && ::protozero::internal::gen_helpers::EqualsField(burst_period_ms_, other.burst_period_ms_)
+ && ::protozero::internal::gen_helpers::EqualsField(burst_duration_ms_, other.burst_duration_ms_)
+ && ::protozero::internal::gen_helpers::EqualsField(burst_timings_, other.burst_timings_);
}
-bool BeginImplFrameArgs::ParseFromArray(const void* raw, size_t size) {
+bool StressTestConfig::ParseFromArray(const void* raw, size_t size) {
unknown_fields_.clear();
bool packed_error = false;
@@ -32828,23 +33016,38 @@ bool BeginImplFrameArgs::ParseFromArray(const void* raw, size_t size) {
_has_field_.set(field.id());
}
switch (field.id()) {
- case 1 /* updated_at_us */:
- field.get(&updated_at_us_);
+ case 1 /* trace_config */:
+ (*trace_config_).ParseFromArray(field.data(), field.size());
break;
- case 2 /* finished_at_us */:
- field.get(&finished_at_us_);
+ case 2 /* shmem_size_kb */:
+ field.get(&shmem_size_kb_);
break;
- case 3 /* state */:
- field.get(&state_);
+ case 3 /* shmem_page_size_kb */:
+ field.get(&shmem_page_size_kb_);
break;
- case 4 /* current_args */:
- (*current_args_).ParseFromArray(field.data(), field.size());
+ case 4 /* num_processes */:
+ field.get(&num_processes_);
break;
- case 5 /* last_args */:
- (*last_args_).ParseFromArray(field.data(), field.size());
+ case 5 /* num_threads */:
+ field.get(&num_threads_);
break;
- case 6 /* timestamps_in_us */:
- (*timestamps_in_us_).ParseFromArray(field.data(), field.size());
+ case 6 /* max_events */:
+ field.get(&max_events_);
+ break;
+ case 7 /* nesting */:
+ field.get(&nesting_);
+ break;
+ case 8 /* steady_state_timings */:
+ (*steady_state_timings_).ParseFromArray(field.data(), field.size());
+ break;
+ case 9 /* burst_period_ms */:
+ field.get(&burst_period_ms_);
+ break;
+ case 10 /* burst_duration_ms */:
+ field.get(&burst_duration_ms_);
+ break;
+ case 11 /* burst_timings */:
+ (*burst_timings_).ParseFromArray(field.data(), field.size());
break;
default:
field.SerializeAndAppendTo(&unknown_fields_);
@@ -32854,72 +33057,95 @@ bool BeginImplFrameArgs::ParseFromArray(const void* raw, size_t size) {
return !packed_error && !dec.bytes_left();
}
-std::string BeginImplFrameArgs::SerializeAsString() const {
+std::string StressTestConfig::SerializeAsString() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsString();
}
-std::vector<uint8_t> BeginImplFrameArgs::SerializeAsArray() const {
+std::vector<uint8_t> StressTestConfig::SerializeAsArray() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsArray();
}
-void BeginImplFrameArgs::Serialize(::protozero::Message* msg) const {
- // Field 1: updated_at_us
+void StressTestConfig::Serialize(::protozero::Message* msg) const {
+ // Field 1: trace_config
if (_has_field_[1]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(1, updated_at_us_, msg);
+ (*trace_config_).Serialize(msg->BeginNestedMessage<::protozero::Message>(1));
}
- // Field 2: finished_at_us
+ // Field 2: shmem_size_kb
if (_has_field_[2]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(2, finished_at_us_, msg);
+ ::protozero::internal::gen_helpers::SerializeVarInt(2, shmem_size_kb_, msg);
}
- // Field 3: state
+ // Field 3: shmem_page_size_kb
if (_has_field_[3]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(3, state_, msg);
+ ::protozero::internal::gen_helpers::SerializeVarInt(3, shmem_page_size_kb_, msg);
}
- // Field 4: current_args
+ // Field 4: num_processes
if (_has_field_[4]) {
- (*current_args_).Serialize(msg->BeginNestedMessage<::protozero::Message>(4));
+ ::protozero::internal::gen_helpers::SerializeVarInt(4, num_processes_, msg);
}
- // Field 5: last_args
+ // Field 5: num_threads
if (_has_field_[5]) {
- (*last_args_).Serialize(msg->BeginNestedMessage<::protozero::Message>(5));
+ ::protozero::internal::gen_helpers::SerializeVarInt(5, num_threads_, msg);
}
- // Field 6: timestamps_in_us
+ // Field 6: max_events
if (_has_field_[6]) {
- (*timestamps_in_us_).Serialize(msg->BeginNestedMessage<::protozero::Message>(6));
+ ::protozero::internal::gen_helpers::SerializeVarInt(6, max_events_, msg);
+ }
+
+ // Field 7: nesting
+ if (_has_field_[7]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(7, nesting_, msg);
+ }
+
+ // Field 8: steady_state_timings
+ if (_has_field_[8]) {
+ (*steady_state_timings_).Serialize(msg->BeginNestedMessage<::protozero::Message>(8));
+ }
+
+ // Field 9: burst_period_ms
+ if (_has_field_[9]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(9, burst_period_ms_, msg);
+ }
+
+ // Field 10: burst_duration_ms
+ if (_has_field_[10]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(10, burst_duration_ms_, msg);
+ }
+
+ // Field 11: burst_timings
+ if (_has_field_[11]) {
+ (*burst_timings_).Serialize(msg->BeginNestedMessage<::protozero::Message>(11));
}
protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
}
-BeginImplFrameArgs_TimestampsInUs::BeginImplFrameArgs_TimestampsInUs() = default;
-BeginImplFrameArgs_TimestampsInUs::~BeginImplFrameArgs_TimestampsInUs() = default;
-BeginImplFrameArgs_TimestampsInUs::BeginImplFrameArgs_TimestampsInUs(const BeginImplFrameArgs_TimestampsInUs&) = default;
-BeginImplFrameArgs_TimestampsInUs& BeginImplFrameArgs_TimestampsInUs::operator=(const BeginImplFrameArgs_TimestampsInUs&) = default;
-BeginImplFrameArgs_TimestampsInUs::BeginImplFrameArgs_TimestampsInUs(BeginImplFrameArgs_TimestampsInUs&&) noexcept = default;
-BeginImplFrameArgs_TimestampsInUs& BeginImplFrameArgs_TimestampsInUs::operator=(BeginImplFrameArgs_TimestampsInUs&&) = default;
+StressTestConfig_WriterTiming::StressTestConfig_WriterTiming() = default;
+StressTestConfig_WriterTiming::~StressTestConfig_WriterTiming() = default;
+StressTestConfig_WriterTiming::StressTestConfig_WriterTiming(const StressTestConfig_WriterTiming&) = default;
+StressTestConfig_WriterTiming& StressTestConfig_WriterTiming::operator=(const StressTestConfig_WriterTiming&) = default;
+StressTestConfig_WriterTiming::StressTestConfig_WriterTiming(StressTestConfig_WriterTiming&&) noexcept = default;
+StressTestConfig_WriterTiming& StressTestConfig_WriterTiming::operator=(StressTestConfig_WriterTiming&&) = default;
-bool BeginImplFrameArgs_TimestampsInUs::operator==(const BeginImplFrameArgs_TimestampsInUs& other) const {
+bool StressTestConfig_WriterTiming::operator==(const StressTestConfig_WriterTiming& other) const {
return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
- && ::protozero::internal::gen_helpers::EqualsField(interval_delta_, other.interval_delta_)
- && ::protozero::internal::gen_helpers::EqualsField(now_to_deadline_delta_, other.now_to_deadline_delta_)
- && ::protozero::internal::gen_helpers::EqualsField(frame_time_to_now_delta_, other.frame_time_to_now_delta_)
- && ::protozero::internal::gen_helpers::EqualsField(frame_time_to_deadline_delta_, other.frame_time_to_deadline_delta_)
- && ::protozero::internal::gen_helpers::EqualsField(now_, other.now_)
- && ::protozero::internal::gen_helpers::EqualsField(frame_time_, other.frame_time_)
- && ::protozero::internal::gen_helpers::EqualsField(deadline_, other.deadline_);
+ && ::protozero::internal::gen_helpers::EqualsField(payload_mean_, other.payload_mean_)
+ && ::protozero::internal::gen_helpers::EqualsField(payload_stddev_, other.payload_stddev_)
+ && ::protozero::internal::gen_helpers::EqualsField(rate_mean_, other.rate_mean_)
+ && ::protozero::internal::gen_helpers::EqualsField(rate_stddev_, other.rate_stddev_)
+ && ::protozero::internal::gen_helpers::EqualsField(payload_write_time_ms_, other.payload_write_time_ms_);
}
-bool BeginImplFrameArgs_TimestampsInUs::ParseFromArray(const void* raw, size_t size) {
+bool StressTestConfig_WriterTiming::ParseFromArray(const void* raw, size_t size) {
unknown_fields_.clear();
bool packed_error = false;
@@ -32929,26 +33155,20 @@ bool BeginImplFrameArgs_TimestampsInUs::ParseFromArray(const void* raw, size_t s
_has_field_.set(field.id());
}
switch (field.id()) {
- case 1 /* interval_delta */:
- field.get(&interval_delta_);
- break;
- case 2 /* now_to_deadline_delta */:
- field.get(&now_to_deadline_delta_);
- break;
- case 3 /* frame_time_to_now_delta */:
- field.get(&frame_time_to_now_delta_);
+ case 1 /* payload_mean */:
+ field.get(&payload_mean_);
break;
- case 4 /* frame_time_to_deadline_delta */:
- field.get(&frame_time_to_deadline_delta_);
+ case 2 /* payload_stddev */:
+ field.get(&payload_stddev_);
break;
- case 5 /* now */:
- field.get(&now_);
+ case 3 /* rate_mean */:
+ field.get(&rate_mean_);
break;
- case 6 /* frame_time */:
- field.get(&frame_time_);
+ case 4 /* rate_stddev */:
+ field.get(&rate_stddev_);
break;
- case 7 /* deadline */:
- field.get(&deadline_);
+ case 5 /* payload_write_time_ms */:
+ field.get(&payload_write_time_ms_);
break;
default:
field.SerializeAndAppendTo(&unknown_fields_);
@@ -32958,72 +33178,88 @@ bool BeginImplFrameArgs_TimestampsInUs::ParseFromArray(const void* raw, size_t s
return !packed_error && !dec.bytes_left();
}
-std::string BeginImplFrameArgs_TimestampsInUs::SerializeAsString() const {
+std::string StressTestConfig_WriterTiming::SerializeAsString() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsString();
}
-std::vector<uint8_t> BeginImplFrameArgs_TimestampsInUs::SerializeAsArray() const {
+std::vector<uint8_t> StressTestConfig_WriterTiming::SerializeAsArray() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsArray();
}
-void BeginImplFrameArgs_TimestampsInUs::Serialize(::protozero::Message* msg) const {
- // Field 1: interval_delta
+void StressTestConfig_WriterTiming::Serialize(::protozero::Message* msg) const {
+ // Field 1: payload_mean
if (_has_field_[1]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(1, interval_delta_, msg);
+ ::protozero::internal::gen_helpers::SerializeFixed(1, payload_mean_, msg);
}
- // Field 2: now_to_deadline_delta
+ // Field 2: payload_stddev
if (_has_field_[2]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(2, now_to_deadline_delta_, msg);
+ ::protozero::internal::gen_helpers::SerializeFixed(2, payload_stddev_, msg);
}
- // Field 3: frame_time_to_now_delta
+ // Field 3: rate_mean
if (_has_field_[3]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(3, frame_time_to_now_delta_, msg);
+ ::protozero::internal::gen_helpers::SerializeFixed(3, rate_mean_, msg);
}
- // Field 4: frame_time_to_deadline_delta
+ // Field 4: rate_stddev
if (_has_field_[4]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(4, frame_time_to_deadline_delta_, msg);
+ ::protozero::internal::gen_helpers::SerializeFixed(4, rate_stddev_, msg);
}
- // Field 5: now
+ // Field 5: payload_write_time_ms
if (_has_field_[5]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(5, now_, msg);
- }
-
- // Field 6: frame_time
- if (_has_field_[6]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(6, frame_time_, msg);
- }
-
- // Field 7: deadline
- if (_has_field_[7]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(7, deadline_, msg);
+ ::protozero::internal::gen_helpers::SerializeVarInt(5, payload_write_time_ms_, msg);
}
protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
}
+} // namespace perfetto
+} // namespace protos
+} // namespace gen
+#if defined(__GNUC__) || defined(__clang__)
+#pragma GCC diagnostic pop
+#endif
+// gen_amalgamated begin source: gen/protos/perfetto/config/test_config.gen.cc
+// gen_amalgamated expanded: #include "perfetto/protozero/gen_field_helpers.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/message.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/packed_repeated_fields.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/proto_decoder.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/scattered_heap_buffer.h"
+// DO NOT EDIT. Autogenerated by Perfetto cppgen_plugin
+#if defined(__GNUC__) || defined(__clang__)
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wfloat-equal"
+#endif
+// gen_amalgamated expanded: #include "protos/perfetto/config/test_config.gen.h"
+
+namespace perfetto {
+namespace protos {
+namespace gen {
-ChromeCompositorStateMachine::ChromeCompositorStateMachine() = default;
-ChromeCompositorStateMachine::~ChromeCompositorStateMachine() = default;
-ChromeCompositorStateMachine::ChromeCompositorStateMachine(const ChromeCompositorStateMachine&) = default;
-ChromeCompositorStateMachine& ChromeCompositorStateMachine::operator=(const ChromeCompositorStateMachine&) = default;
-ChromeCompositorStateMachine::ChromeCompositorStateMachine(ChromeCompositorStateMachine&&) noexcept = default;
-ChromeCompositorStateMachine& ChromeCompositorStateMachine::operator=(ChromeCompositorStateMachine&&) = default;
+TestConfig::TestConfig() = default;
+TestConfig::~TestConfig() = default;
+TestConfig::TestConfig(const TestConfig&) = default;
+TestConfig& TestConfig::operator=(const TestConfig&) = default;
+TestConfig::TestConfig(TestConfig&&) noexcept = default;
+TestConfig& TestConfig::operator=(TestConfig&&) = default;
-bool ChromeCompositorStateMachine::operator==(const ChromeCompositorStateMachine& other) const {
+bool TestConfig::operator==(const TestConfig& other) const {
return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
- && ::protozero::internal::gen_helpers::EqualsField(major_state_, other.major_state_)
- && ::protozero::internal::gen_helpers::EqualsField(minor_state_, other.minor_state_);
+ && ::protozero::internal::gen_helpers::EqualsField(message_count_, other.message_count_)
+ && ::protozero::internal::gen_helpers::EqualsField(max_messages_per_second_, other.max_messages_per_second_)
+ && ::protozero::internal::gen_helpers::EqualsField(seed_, other.seed_)
+ && ::protozero::internal::gen_helpers::EqualsField(message_size_, other.message_size_)
+ && ::protozero::internal::gen_helpers::EqualsField(send_batch_on_register_, other.send_batch_on_register_)
+ && ::protozero::internal::gen_helpers::EqualsField(dummy_fields_, other.dummy_fields_);
}
-bool ChromeCompositorStateMachine::ParseFromArray(const void* raw, size_t size) {
+bool TestConfig::ParseFromArray(const void* raw, size_t size) {
unknown_fields_.clear();
bool packed_error = false;
@@ -33033,11 +33269,23 @@ bool ChromeCompositorStateMachine::ParseFromArray(const void* raw, size_t size)
_has_field_.set(field.id());
}
switch (field.id()) {
- case 1 /* major_state */:
- (*major_state_).ParseFromArray(field.data(), field.size());
+ case 1 /* message_count */:
+ field.get(&message_count_);
break;
- case 2 /* minor_state */:
- (*minor_state_).ParseFromArray(field.data(), field.size());
+ case 2 /* max_messages_per_second */:
+ field.get(&max_messages_per_second_);
+ break;
+ case 3 /* seed */:
+ field.get(&seed_);
+ break;
+ case 4 /* message_size */:
+ field.get(&message_size_);
+ break;
+ case 5 /* send_batch_on_register */:
+ field.get(&send_batch_on_register_);
+ break;
+ case 6 /* dummy_fields */:
+ (*dummy_fields_).ParseFromArray(field.data(), field.size());
break;
default:
field.SerializeAndAppendTo(&unknown_fields_);
@@ -33047,90 +33295,79 @@ bool ChromeCompositorStateMachine::ParseFromArray(const void* raw, size_t size)
return !packed_error && !dec.bytes_left();
}
-std::string ChromeCompositorStateMachine::SerializeAsString() const {
+std::string TestConfig::SerializeAsString() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsString();
}
-std::vector<uint8_t> ChromeCompositorStateMachine::SerializeAsArray() const {
+std::vector<uint8_t> TestConfig::SerializeAsArray() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsArray();
}
-void ChromeCompositorStateMachine::Serialize(::protozero::Message* msg) const {
- // Field 1: major_state
+void TestConfig::Serialize(::protozero::Message* msg) const {
+ // Field 1: message_count
if (_has_field_[1]) {
- (*major_state_).Serialize(msg->BeginNestedMessage<::protozero::Message>(1));
+ ::protozero::internal::gen_helpers::SerializeVarInt(1, message_count_, msg);
}
- // Field 2: minor_state
+ // Field 2: max_messages_per_second
if (_has_field_[2]) {
- (*minor_state_).Serialize(msg->BeginNestedMessage<::protozero::Message>(2));
+ ::protozero::internal::gen_helpers::SerializeVarInt(2, max_messages_per_second_, msg);
+ }
+
+ // Field 3: seed
+ if (_has_field_[3]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(3, seed_, msg);
+ }
+
+ // Field 4: message_size
+ if (_has_field_[4]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(4, message_size_, msg);
+ }
+
+ // Field 5: send_batch_on_register
+ if (_has_field_[5]) {
+ ::protozero::internal::gen_helpers::SerializeTinyVarInt(5, send_batch_on_register_, msg);
+ }
+
+ // Field 6: dummy_fields
+ if (_has_field_[6]) {
+ (*dummy_fields_).Serialize(msg->BeginNestedMessage<::protozero::Message>(6));
}
protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
}
-ChromeCompositorStateMachine_MinorState::ChromeCompositorStateMachine_MinorState() = default;
-ChromeCompositorStateMachine_MinorState::~ChromeCompositorStateMachine_MinorState() = default;
-ChromeCompositorStateMachine_MinorState::ChromeCompositorStateMachine_MinorState(const ChromeCompositorStateMachine_MinorState&) = default;
-ChromeCompositorStateMachine_MinorState& ChromeCompositorStateMachine_MinorState::operator=(const ChromeCompositorStateMachine_MinorState&) = default;
-ChromeCompositorStateMachine_MinorState::ChromeCompositorStateMachine_MinorState(ChromeCompositorStateMachine_MinorState&&) noexcept = default;
-ChromeCompositorStateMachine_MinorState& ChromeCompositorStateMachine_MinorState::operator=(ChromeCompositorStateMachine_MinorState&&) = default;
+TestConfig_DummyFields::TestConfig_DummyFields() = default;
+TestConfig_DummyFields::~TestConfig_DummyFields() = default;
+TestConfig_DummyFields::TestConfig_DummyFields(const TestConfig_DummyFields&) = default;
+TestConfig_DummyFields& TestConfig_DummyFields::operator=(const TestConfig_DummyFields&) = default;
+TestConfig_DummyFields::TestConfig_DummyFields(TestConfig_DummyFields&&) noexcept = default;
+TestConfig_DummyFields& TestConfig_DummyFields::operator=(TestConfig_DummyFields&&) = default;
-bool ChromeCompositorStateMachine_MinorState::operator==(const ChromeCompositorStateMachine_MinorState& other) const {
+bool TestConfig_DummyFields::operator==(const TestConfig_DummyFields& other) const {
return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
- && ::protozero::internal::gen_helpers::EqualsField(commit_count_, other.commit_count_)
- && ::protozero::internal::gen_helpers::EqualsField(current_frame_number_, other.current_frame_number_)
- && ::protozero::internal::gen_helpers::EqualsField(last_frame_number_submit_performed_, other.last_frame_number_submit_performed_)
- && ::protozero::internal::gen_helpers::EqualsField(last_frame_number_draw_performed_, other.last_frame_number_draw_performed_)
- && ::protozero::internal::gen_helpers::EqualsField(last_frame_number_begin_main_frame_sent_, other.last_frame_number_begin_main_frame_sent_)
- && ::protozero::internal::gen_helpers::EqualsField(did_draw_, other.did_draw_)
- && ::protozero::internal::gen_helpers::EqualsField(did_send_begin_main_frame_for_current_frame_, other.did_send_begin_main_frame_for_current_frame_)
- && ::protozero::internal::gen_helpers::EqualsField(did_notify_begin_main_frame_not_expected_until_, other.did_notify_begin_main_frame_not_expected_until_)
- && ::protozero::internal::gen_helpers::EqualsField(did_notify_begin_main_frame_not_expected_soon_, other.did_notify_begin_main_frame_not_expected_soon_)
- && ::protozero::internal::gen_helpers::EqualsField(wants_begin_main_frame_not_expected_, other.wants_begin_main_frame_not_expected_)
- && ::protozero::internal::gen_helpers::EqualsField(did_commit_during_frame_, other.did_commit_during_frame_)
- && ::protozero::internal::gen_helpers::EqualsField(did_invalidate_layer_tree_frame_sink_, other.did_invalidate_layer_tree_frame_sink_)
- && ::protozero::internal::gen_helpers::EqualsField(did_perform_impl_side_invalidaion_, other.did_perform_impl_side_invalidaion_)
- && ::protozero::internal::gen_helpers::EqualsField(did_prepare_tiles_, other.did_prepare_tiles_)
- && ::protozero::internal::gen_helpers::EqualsField(consecutive_checkerboard_animations_, other.consecutive_checkerboard_animations_)
- && ::protozero::internal::gen_helpers::EqualsField(pending_submit_frames_, other.pending_submit_frames_)
- && ::protozero::internal::gen_helpers::EqualsField(submit_frames_with_current_layer_tree_frame_sink_, other.submit_frames_with_current_layer_tree_frame_sink_)
- && ::protozero::internal::gen_helpers::EqualsField(needs_redraw_, other.needs_redraw_)
- && ::protozero::internal::gen_helpers::EqualsField(needs_prepare_tiles_, other.needs_prepare_tiles_)
- && ::protozero::internal::gen_helpers::EqualsField(needs_begin_main_frame_, other.needs_begin_main_frame_)
- && ::protozero::internal::gen_helpers::EqualsField(needs_one_begin_impl_frame_, other.needs_one_begin_impl_frame_)
- && ::protozero::internal::gen_helpers::EqualsField(visible_, other.visible_)
- && ::protozero::internal::gen_helpers::EqualsField(begin_frame_source_paused_, other.begin_frame_source_paused_)
- && ::protozero::internal::gen_helpers::EqualsField(can_draw_, other.can_draw_)
- && ::protozero::internal::gen_helpers::EqualsField(resourceless_draw_, other.resourceless_draw_)
- && ::protozero::internal::gen_helpers::EqualsField(has_pending_tree_, other.has_pending_tree_)
- && ::protozero::internal::gen_helpers::EqualsField(pending_tree_is_ready_for_activation_, other.pending_tree_is_ready_for_activation_)
- && ::protozero::internal::gen_helpers::EqualsField(active_tree_needs_first_draw_, other.active_tree_needs_first_draw_)
- && ::protozero::internal::gen_helpers::EqualsField(active_tree_is_ready_to_draw_, other.active_tree_is_ready_to_draw_)
- && ::protozero::internal::gen_helpers::EqualsField(did_create_and_initialize_first_layer_tree_frame_sink_, other.did_create_and_initialize_first_layer_tree_frame_sink_)
- && ::protozero::internal::gen_helpers::EqualsField(tree_priority_, other.tree_priority_)
- && ::protozero::internal::gen_helpers::EqualsField(scroll_handler_state_, other.scroll_handler_state_)
- && ::protozero::internal::gen_helpers::EqualsField(critical_begin_main_frame_to_activate_is_fast_, other.critical_begin_main_frame_to_activate_is_fast_)
- && ::protozero::internal::gen_helpers::EqualsField(main_thread_missed_last_deadline_, other.main_thread_missed_last_deadline_)
- && ::protozero::internal::gen_helpers::EqualsField(video_needs_begin_frames_, other.video_needs_begin_frames_)
- && ::protozero::internal::gen_helpers::EqualsField(defer_begin_main_frame_, other.defer_begin_main_frame_)
- && ::protozero::internal::gen_helpers::EqualsField(last_commit_had_no_updates_, other.last_commit_had_no_updates_)
- && ::protozero::internal::gen_helpers::EqualsField(did_draw_in_last_frame_, other.did_draw_in_last_frame_)
- && ::protozero::internal::gen_helpers::EqualsField(did_submit_in_last_frame_, other.did_submit_in_last_frame_)
- && ::protozero::internal::gen_helpers::EqualsField(needs_impl_side_invalidation_, other.needs_impl_side_invalidation_)
- && ::protozero::internal::gen_helpers::EqualsField(current_pending_tree_is_impl_side_, other.current_pending_tree_is_impl_side_)
- && ::protozero::internal::gen_helpers::EqualsField(previous_pending_tree_was_impl_side_, other.previous_pending_tree_was_impl_side_)
- && ::protozero::internal::gen_helpers::EqualsField(processing_animation_worklets_for_active_tree_, other.processing_animation_worklets_for_active_tree_)
- && ::protozero::internal::gen_helpers::EqualsField(processing_animation_worklets_for_pending_tree_, other.processing_animation_worklets_for_pending_tree_)
- && ::protozero::internal::gen_helpers::EqualsField(processing_paint_worklets_for_pending_tree_, other.processing_paint_worklets_for_pending_tree_);
+ && ::protozero::internal::gen_helpers::EqualsField(field_uint32_, other.field_uint32_)
+ && ::protozero::internal::gen_helpers::EqualsField(field_int32_, other.field_int32_)
+ && ::protozero::internal::gen_helpers::EqualsField(field_uint64_, other.field_uint64_)
+ && ::protozero::internal::gen_helpers::EqualsField(field_int64_, other.field_int64_)
+ && ::protozero::internal::gen_helpers::EqualsField(field_fixed64_, other.field_fixed64_)
+ && ::protozero::internal::gen_helpers::EqualsField(field_sfixed64_, other.field_sfixed64_)
+ && ::protozero::internal::gen_helpers::EqualsField(field_fixed32_, other.field_fixed32_)
+ && ::protozero::internal::gen_helpers::EqualsField(field_sfixed32_, other.field_sfixed32_)
+ && ::protozero::internal::gen_helpers::EqualsField(field_double_, other.field_double_)
+ && ::protozero::internal::gen_helpers::EqualsField(field_float_, other.field_float_)
+ && ::protozero::internal::gen_helpers::EqualsField(field_sint64_, other.field_sint64_)
+ && ::protozero::internal::gen_helpers::EqualsField(field_sint32_, other.field_sint32_)
+ && ::protozero::internal::gen_helpers::EqualsField(field_string_, other.field_string_)
+ && ::protozero::internal::gen_helpers::EqualsField(field_bytes_, other.field_bytes_);
}
-bool ChromeCompositorStateMachine_MinorState::ParseFromArray(const void* raw, size_t size) {
+bool TestConfig_DummyFields::ParseFromArray(const void* raw, size_t size) {
unknown_fields_.clear();
bool packed_error = false;
@@ -33140,140 +33377,47 @@ bool ChromeCompositorStateMachine_MinorState::ParseFromArray(const void* raw, si
_has_field_.set(field.id());
}
switch (field.id()) {
- case 1 /* commit_count */:
- field.get(&commit_count_);
- break;
- case 2 /* current_frame_number */:
- field.get(¤t_frame_number_);
- break;
- case 3 /* last_frame_number_submit_performed */:
- field.get(&last_frame_number_submit_performed_);
- break;
- case 4 /* last_frame_number_draw_performed */:
- field.get(&last_frame_number_draw_performed_);
- break;
- case 5 /* last_frame_number_begin_main_frame_sent */:
- field.get(&last_frame_number_begin_main_frame_sent_);
- break;
- case 6 /* did_draw */:
- field.get(&did_draw_);
- break;
- case 7 /* did_send_begin_main_frame_for_current_frame */:
- field.get(&did_send_begin_main_frame_for_current_frame_);
- break;
- case 8 /* did_notify_begin_main_frame_not_expected_until */:
- field.get(&did_notify_begin_main_frame_not_expected_until_);
- break;
- case 9 /* did_notify_begin_main_frame_not_expected_soon */:
- field.get(&did_notify_begin_main_frame_not_expected_soon_);
- break;
- case 10 /* wants_begin_main_frame_not_expected */:
- field.get(&wants_begin_main_frame_not_expected_);
- break;
- case 11 /* did_commit_during_frame */:
- field.get(&did_commit_during_frame_);
- break;
- case 12 /* did_invalidate_layer_tree_frame_sink */:
- field.get(&did_invalidate_layer_tree_frame_sink_);
- break;
- case 13 /* did_perform_impl_side_invalidaion */:
- field.get(&did_perform_impl_side_invalidaion_);
- break;
- case 14 /* did_prepare_tiles */:
- field.get(&did_prepare_tiles_);
- break;
- case 15 /* consecutive_checkerboard_animations */:
- field.get(&consecutive_checkerboard_animations_);
- break;
- case 16 /* pending_submit_frames */:
- field.get(&pending_submit_frames_);
- break;
- case 17 /* submit_frames_with_current_layer_tree_frame_sink */:
- field.get(&submit_frames_with_current_layer_tree_frame_sink_);
- break;
- case 18 /* needs_redraw */:
- field.get(&needs_redraw_);
- break;
- case 19 /* needs_prepare_tiles */:
- field.get(&needs_prepare_tiles_);
- break;
- case 20 /* needs_begin_main_frame */:
- field.get(&needs_begin_main_frame_);
- break;
- case 21 /* needs_one_begin_impl_frame */:
- field.get(&needs_one_begin_impl_frame_);
- break;
- case 22 /* visible */:
- field.get(&visible_);
- break;
- case 23 /* begin_frame_source_paused */:
- field.get(&begin_frame_source_paused_);
- break;
- case 24 /* can_draw */:
- field.get(&can_draw_);
- break;
- case 25 /* resourceless_draw */:
- field.get(&resourceless_draw_);
- break;
- case 26 /* has_pending_tree */:
- field.get(&has_pending_tree_);
- break;
- case 27 /* pending_tree_is_ready_for_activation */:
- field.get(&pending_tree_is_ready_for_activation_);
- break;
- case 28 /* active_tree_needs_first_draw */:
- field.get(&active_tree_needs_first_draw_);
- break;
- case 29 /* active_tree_is_ready_to_draw */:
- field.get(&active_tree_is_ready_to_draw_);
- break;
- case 30 /* did_create_and_initialize_first_layer_tree_frame_sink */:
- field.get(&did_create_and_initialize_first_layer_tree_frame_sink_);
- break;
- case 31 /* tree_priority */:
- field.get(&tree_priority_);
- break;
- case 32 /* scroll_handler_state */:
- field.get(&scroll_handler_state_);
+ case 1 /* field_uint32 */:
+ field.get(&field_uint32_);
break;
- case 33 /* critical_begin_main_frame_to_activate_is_fast */:
- field.get(&critical_begin_main_frame_to_activate_is_fast_);
+ case 2 /* field_int32 */:
+ field.get(&field_int32_);
break;
- case 34 /* main_thread_missed_last_deadline */:
- field.get(&main_thread_missed_last_deadline_);
+ case 3 /* field_uint64 */:
+ field.get(&field_uint64_);
break;
- case 36 /* video_needs_begin_frames */:
- field.get(&video_needs_begin_frames_);
+ case 4 /* field_int64 */:
+ field.get(&field_int64_);
break;
- case 37 /* defer_begin_main_frame */:
- field.get(&defer_begin_main_frame_);
+ case 5 /* field_fixed64 */:
+ field.get(&field_fixed64_);
break;
- case 38 /* last_commit_had_no_updates */:
- field.get(&last_commit_had_no_updates_);
+ case 6 /* field_sfixed64 */:
+ field.get(&field_sfixed64_);
break;
- case 39 /* did_draw_in_last_frame */:
- field.get(&did_draw_in_last_frame_);
+ case 7 /* field_fixed32 */:
+ field.get(&field_fixed32_);
break;
- case 40 /* did_submit_in_last_frame */:
- field.get(&did_submit_in_last_frame_);
+ case 8 /* field_sfixed32 */:
+ field.get(&field_sfixed32_);
break;
- case 41 /* needs_impl_side_invalidation */:
- field.get(&needs_impl_side_invalidation_);
+ case 9 /* field_double */:
+ field.get(&field_double_);
break;
- case 42 /* current_pending_tree_is_impl_side */:
- field.get(¤t_pending_tree_is_impl_side_);
+ case 10 /* field_float */:
+ field.get(&field_float_);
break;
- case 43 /* previous_pending_tree_was_impl_side */:
- field.get(&previous_pending_tree_was_impl_side_);
+ case 11 /* field_sint64 */:
+ field.get_signed(&field_sint64_);
break;
- case 44 /* processing_animation_worklets_for_active_tree */:
- field.get(&processing_animation_worklets_for_active_tree_);
+ case 12 /* field_sint32 */:
+ field.get_signed(&field_sint32_);
break;
- case 45 /* processing_animation_worklets_for_pending_tree */:
- field.get(&processing_animation_worklets_for_pending_tree_);
+ case 13 /* field_string */:
+ ::protozero::internal::gen_helpers::DeserializeString(field, &field_string_);
break;
- case 46 /* processing_paint_worklets_for_pending_tree */:
- field.get(&processing_paint_worklets_for_pending_tree_);
+ case 14 /* field_bytes */:
+ field.get(&field_bytes_);
break;
default:
field.SerializeAndAppendTo(&unknown_fields_);
@@ -33283,265 +33427,652 @@ bool ChromeCompositorStateMachine_MinorState::ParseFromArray(const void* raw, si
return !packed_error && !dec.bytes_left();
}
-std::string ChromeCompositorStateMachine_MinorState::SerializeAsString() const {
+std::string TestConfig_DummyFields::SerializeAsString() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsString();
}
-std::vector<uint8_t> ChromeCompositorStateMachine_MinorState::SerializeAsArray() const {
+std::vector<uint8_t> TestConfig_DummyFields::SerializeAsArray() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsArray();
}
-void ChromeCompositorStateMachine_MinorState::Serialize(::protozero::Message* msg) const {
- // Field 1: commit_count
+void TestConfig_DummyFields::Serialize(::protozero::Message* msg) const {
+ // Field 1: field_uint32
if (_has_field_[1]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(1, commit_count_, msg);
+ ::protozero::internal::gen_helpers::SerializeVarInt(1, field_uint32_, msg);
}
- // Field 2: current_frame_number
+ // Field 2: field_int32
if (_has_field_[2]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(2, current_frame_number_, msg);
+ ::protozero::internal::gen_helpers::SerializeVarInt(2, field_int32_, msg);
}
- // Field 3: last_frame_number_submit_performed
+ // Field 3: field_uint64
if (_has_field_[3]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(3, last_frame_number_submit_performed_, msg);
+ ::protozero::internal::gen_helpers::SerializeVarInt(3, field_uint64_, msg);
}
- // Field 4: last_frame_number_draw_performed
+ // Field 4: field_int64
if (_has_field_[4]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(4, last_frame_number_draw_performed_, msg);
+ ::protozero::internal::gen_helpers::SerializeVarInt(4, field_int64_, msg);
}
- // Field 5: last_frame_number_begin_main_frame_sent
+ // Field 5: field_fixed64
if (_has_field_[5]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(5, last_frame_number_begin_main_frame_sent_, msg);
+ ::protozero::internal::gen_helpers::SerializeFixed(5, field_fixed64_, msg);
}
- // Field 6: did_draw
+ // Field 6: field_sfixed64
if (_has_field_[6]) {
- ::protozero::internal::gen_helpers::SerializeTinyVarInt(6, did_draw_, msg);
+ ::protozero::internal::gen_helpers::SerializeFixed(6, field_sfixed64_, msg);
}
- // Field 7: did_send_begin_main_frame_for_current_frame
+ // Field 7: field_fixed32
if (_has_field_[7]) {
- ::protozero::internal::gen_helpers::SerializeTinyVarInt(7, did_send_begin_main_frame_for_current_frame_, msg);
+ ::protozero::internal::gen_helpers::SerializeFixed(7, field_fixed32_, msg);
}
- // Field 8: did_notify_begin_main_frame_not_expected_until
+ // Field 8: field_sfixed32
if (_has_field_[8]) {
- ::protozero::internal::gen_helpers::SerializeTinyVarInt(8, did_notify_begin_main_frame_not_expected_until_, msg);
+ ::protozero::internal::gen_helpers::SerializeFixed(8, field_sfixed32_, msg);
}
- // Field 9: did_notify_begin_main_frame_not_expected_soon
+ // Field 9: field_double
if (_has_field_[9]) {
- ::protozero::internal::gen_helpers::SerializeTinyVarInt(9, did_notify_begin_main_frame_not_expected_soon_, msg);
+ ::protozero::internal::gen_helpers::SerializeFixed(9, field_double_, msg);
}
- // Field 10: wants_begin_main_frame_not_expected
+ // Field 10: field_float
if (_has_field_[10]) {
- ::protozero::internal::gen_helpers::SerializeTinyVarInt(10, wants_begin_main_frame_not_expected_, msg);
+ ::protozero::internal::gen_helpers::SerializeFixed(10, field_float_, msg);
}
- // Field 11: did_commit_during_frame
+ // Field 11: field_sint64
if (_has_field_[11]) {
- ::protozero::internal::gen_helpers::SerializeTinyVarInt(11, did_commit_during_frame_, msg);
+ ::protozero::internal::gen_helpers::SerializeSignedVarInt(11, field_sint64_, msg);
}
- // Field 12: did_invalidate_layer_tree_frame_sink
+ // Field 12: field_sint32
if (_has_field_[12]) {
- ::protozero::internal::gen_helpers::SerializeTinyVarInt(12, did_invalidate_layer_tree_frame_sink_, msg);
+ ::protozero::internal::gen_helpers::SerializeSignedVarInt(12, field_sint32_, msg);
}
- // Field 13: did_perform_impl_side_invalidaion
+ // Field 13: field_string
if (_has_field_[13]) {
- ::protozero::internal::gen_helpers::SerializeTinyVarInt(13, did_perform_impl_side_invalidaion_, msg);
+ ::protozero::internal::gen_helpers::SerializeString(13, field_string_, msg);
}
- // Field 14: did_prepare_tiles
+ // Field 14: field_bytes
if (_has_field_[14]) {
- ::protozero::internal::gen_helpers::SerializeTinyVarInt(14, did_prepare_tiles_, msg);
- }
-
- // Field 15: consecutive_checkerboard_animations
- if (_has_field_[15]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(15, consecutive_checkerboard_animations_, msg);
- }
-
- // Field 16: pending_submit_frames
- if (_has_field_[16]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(16, pending_submit_frames_, msg);
- }
-
- // Field 17: submit_frames_with_current_layer_tree_frame_sink
- if (_has_field_[17]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(17, submit_frames_with_current_layer_tree_frame_sink_, msg);
- }
-
- // Field 18: needs_redraw
- if (_has_field_[18]) {
- ::protozero::internal::gen_helpers::SerializeTinyVarInt(18, needs_redraw_, msg);
+ ::protozero::internal::gen_helpers::SerializeString(14, field_bytes_, msg);
}
- // Field 19: needs_prepare_tiles
- if (_has_field_[19]) {
- ::protozero::internal::gen_helpers::SerializeTinyVarInt(19, needs_prepare_tiles_, msg);
- }
+ protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
+}
- // Field 20: needs_begin_main_frame
- if (_has_field_[20]) {
- ::protozero::internal::gen_helpers::SerializeTinyVarInt(20, needs_begin_main_frame_, msg);
- }
+} // namespace perfetto
+} // namespace protos
+} // namespace gen
+#if defined(__GNUC__) || defined(__clang__)
+#pragma GCC diagnostic pop
+#endif
+// gen_amalgamated begin source: gen/protos/perfetto/config/trace_config.gen.cc
+// gen_amalgamated expanded: #include "perfetto/protozero/gen_field_helpers.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/message.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/packed_repeated_fields.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/proto_decoder.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/scattered_heap_buffer.h"
+// DO NOT EDIT. Autogenerated by Perfetto cppgen_plugin
+#if defined(__GNUC__) || defined(__clang__)
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wfloat-equal"
+#endif
+// gen_amalgamated expanded: #include "protos/perfetto/config/trace_config.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/config/priority_boost/priority_boost_config.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/config/data_source_config.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/config/qnx/qnx_config.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/config/linux/journald_config.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/config/chrome/stack_sampling_profiler.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/config/chrome/sampling_heap_profiler.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/config/chrome/histogram_samples.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/config/system_info/system_info_config.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/config/track_event/track_event_config.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/config/test_config.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/config/sys_stats/sys_stats_config.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/common/sys_stats_counters.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/config/profiling/smaps_config.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/config/profiling/perf_event_config.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/common/perf_events.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/config/profiling/java_hprof_config.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/config/profiling/heapprofd_config.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/config/process_stats/process_stats_config.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/config/statsd/statsd_tracing_config.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/config/statsd/atom_ids.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/config/protovm/protovm_config.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/config/power/android_power_config.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/config/interceptor_config.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/config/interceptors/console_config.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/config/inode_file/inode_file_config.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/config/gpu/gpu_renderstages_config.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/config/gpu/vulkan_memory_config.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/config/gpu/gpu_counter_config.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/config/ftrace/frozen_ftrace_config.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/config/ftrace/ftrace_config.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/config/chrome/system_metrics.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/config/etw/etw_config.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/config/chrome/v8_config.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/config/chrome/chrome_config.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/config/android/windowmanager_config.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/config/android/user_list_config.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/config/android/surfaceflinger_transactions_config.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/config/android/surfaceflinger_layers_config.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/config/android/display_video_config.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/config/android/protolog_config.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/config/android/pixel_modem_config.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/config/android/packages_list_config.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/config/android/network_trace_config.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/config/android/kernel_wakelocks_config.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/config/android/inputmethod_config.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/config/android/cpu_per_uid_config.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/config/android/app_wakelock_config.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/config/android/android_sdk_sysprop_guard_config.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/config/android/android_system_property_config.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/config/android/android_process_state_config.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/config/android/android_polled_state_config.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/config/android/android_log_config.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/common/android_log_constants.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/config/android/android_input_event_config.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/config/android/android_game_intervention_list_config.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/config/android/android_aflags_config.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/common/trace_attributes.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/common/semantic_type.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/common/builtin_clock.gen.h"
- // Field 21: needs_one_begin_impl_frame
- if (_has_field_[21]) {
- ::protozero::internal::gen_helpers::SerializeTinyVarInt(21, needs_one_begin_impl_frame_, msg);
- }
+namespace perfetto {
+namespace protos {
+namespace gen {
- // Field 22: visible
- if (_has_field_[22]) {
- ::protozero::internal::gen_helpers::SerializeTinyVarInt(22, visible_, msg);
- }
+TraceConfig::TraceConfig() = default;
+TraceConfig::~TraceConfig() = default;
+TraceConfig::TraceConfig(const TraceConfig&) = default;
+TraceConfig& TraceConfig::operator=(const TraceConfig&) = default;
+TraceConfig::TraceConfig(TraceConfig&&) noexcept = default;
+TraceConfig& TraceConfig::operator=(TraceConfig&&) = default;
- // Field 23: begin_frame_source_paused
- if (_has_field_[23]) {
- ::protozero::internal::gen_helpers::SerializeTinyVarInt(23, begin_frame_source_paused_, msg);
- }
+bool TraceConfig::operator==(const TraceConfig& other) const {
+ return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
+ && ::protozero::internal::gen_helpers::EqualsField(buffers_, other.buffers_)
+ && ::protozero::internal::gen_helpers::EqualsField(experimental_trace_buffer_v2_compaction_, other.experimental_trace_buffer_v2_compaction_)
+ && ::protozero::internal::gen_helpers::EqualsField(data_sources_, other.data_sources_)
+ && ::protozero::internal::gen_helpers::EqualsField(builtin_data_sources_, other.builtin_data_sources_)
+ && ::protozero::internal::gen_helpers::EqualsField(duration_ms_, other.duration_ms_)
+ && ::protozero::internal::gen_helpers::EqualsField(prefer_suspend_clock_for_duration_, other.prefer_suspend_clock_for_duration_)
+ && ::protozero::internal::gen_helpers::EqualsField(enable_extra_guardrails_, other.enable_extra_guardrails_)
+ && ::protozero::internal::gen_helpers::EqualsField(lockdown_mode_, other.lockdown_mode_)
+ && ::protozero::internal::gen_helpers::EqualsField(producers_, other.producers_)
+ && ::protozero::internal::gen_helpers::EqualsField(statsd_metadata_, other.statsd_metadata_)
+ && ::protozero::internal::gen_helpers::EqualsField(write_into_file_, other.write_into_file_)
+ && ::protozero::internal::gen_helpers::EqualsField(output_path_, other.output_path_)
+ && ::protozero::internal::gen_helpers::EqualsField(file_write_period_ms_, other.file_write_period_ms_)
+ && ::protozero::internal::gen_helpers::EqualsField(max_file_size_bytes_, other.max_file_size_bytes_)
+ && ::protozero::internal::gen_helpers::EqualsField(guardrail_overrides_, other.guardrail_overrides_)
+ && ::protozero::internal::gen_helpers::EqualsField(deferred_start_, other.deferred_start_)
+ && ::protozero::internal::gen_helpers::EqualsField(flush_period_ms_, other.flush_period_ms_)
+ && ::protozero::internal::gen_helpers::EqualsField(flush_timeout_ms_, other.flush_timeout_ms_)
+ && ::protozero::internal::gen_helpers::EqualsField(data_source_stop_timeout_ms_, other.data_source_stop_timeout_ms_)
+ && ::protozero::internal::gen_helpers::EqualsField(notify_traceur_, other.notify_traceur_)
+ && ::protozero::internal::gen_helpers::EqualsField(bugreport_score_, other.bugreport_score_)
+ && ::protozero::internal::gen_helpers::EqualsField(bugreport_filename_, other.bugreport_filename_)
+ && ::protozero::internal::gen_helpers::EqualsField(trigger_config_, other.trigger_config_)
+ && ::protozero::internal::gen_helpers::EqualsField(activate_triggers_, other.activate_triggers_)
+ && ::protozero::internal::gen_helpers::EqualsField(incremental_state_config_, other.incremental_state_config_)
+ && ::protozero::internal::gen_helpers::EqualsField(allow_user_build_tracing_, other.allow_user_build_tracing_)
+ && ::protozero::internal::gen_helpers::EqualsField(unique_session_name_, other.unique_session_name_)
+ && ::protozero::internal::gen_helpers::EqualsField(compression_type_, other.compression_type_)
+ && ::protozero::internal::gen_helpers::EqualsField(compression_, other.compression_)
+ && ::protozero::internal::gen_helpers::EqualsField(incident_report_config_, other.incident_report_config_)
+ && ::protozero::internal::gen_helpers::EqualsField(statsd_logging_, other.statsd_logging_)
+ && ::protozero::internal::gen_helpers::EqualsField(trace_uuid_msb_, other.trace_uuid_msb_)
+ && ::protozero::internal::gen_helpers::EqualsField(trace_uuid_lsb_, other.trace_uuid_lsb_)
+ && ::protozero::internal::gen_helpers::EqualsField(trace_filter_, other.trace_filter_)
+ && ::protozero::internal::gen_helpers::EqualsField(android_report_config_, other.android_report_config_)
+ && ::protozero::internal::gen_helpers::EqualsField(cmd_trace_start_delay_, other.cmd_trace_start_delay_)
+ && ::protozero::internal::gen_helpers::EqualsField(session_semaphores_, other.session_semaphores_)
+ && ::protozero::internal::gen_helpers::EqualsField(priority_boost_, other.priority_boost_)
+ && ::protozero::internal::gen_helpers::EqualsField(exclusive_prio_, other.exclusive_prio_)
+ && ::protozero::internal::gen_helpers::EqualsField(write_flush_mode_, other.write_flush_mode_)
+ && ::protozero::internal::gen_helpers::EqualsField(fflush_post_write_, other.fflush_post_write_)
+ && ::protozero::internal::gen_helpers::EqualsField(trace_all_machines_, other.trace_all_machines_)
+ && ::protozero::internal::gen_helpers::EqualsField(trace_attributes_, other.trace_attributes_)
+ && ::protozero::internal::gen_helpers::EqualsField(persist_trace_across_reboots_, other.persist_trace_across_reboots_);
+}
- // Field 24: can_draw
- if (_has_field_[24]) {
- ::protozero::internal::gen_helpers::SerializeTinyVarInt(24, can_draw_, msg);
- }
+int TraceConfig::buffers_size() const { return static_cast<int>(buffers_.size()); }
+void TraceConfig::clear_buffers() { buffers_.clear(); }
+TraceConfig_BufferConfig* TraceConfig::add_buffers() { buffers_.emplace_back(); return &buffers_.back(); }
+int TraceConfig::data_sources_size() const { return static_cast<int>(data_sources_.size()); }
+void TraceConfig::clear_data_sources() { data_sources_.clear(); }
+TraceConfig_DataSource* TraceConfig::add_data_sources() { data_sources_.emplace_back(); return &data_sources_.back(); }
+int TraceConfig::producers_size() const { return static_cast<int>(producers_.size()); }
+void TraceConfig::clear_producers() { producers_.clear(); }
+TraceConfig_ProducerConfig* TraceConfig::add_producers() { producers_.emplace_back(); return &producers_.back(); }
+int TraceConfig::session_semaphores_size() const { return static_cast<int>(session_semaphores_.size()); }
+void TraceConfig::clear_session_semaphores() { session_semaphores_.clear(); }
+TraceConfig_SessionSemaphore* TraceConfig::add_session_semaphores() { session_semaphores_.emplace_back(); return &session_semaphores_.back(); }
+bool TraceConfig::ParseFromArray(const void* raw, size_t size) {
+ buffers_.clear();
+ data_sources_.clear();
+ producers_.clear();
+ activate_triggers_.clear();
+ session_semaphores_.clear();
+ unknown_fields_.clear();
+ bool packed_error = false;
- // Field 25: resourceless_draw
- if (_has_field_[25]) {
- ::protozero::internal::gen_helpers::SerializeTinyVarInt(25, resourceless_draw_, msg);
- }
+ ::protozero::ProtoDecoder dec(raw, size);
+ for (auto field = dec.ReadField(); field.valid(); field = dec.ReadField()) {
+ if (field.id() < _has_field_.size()) {
+ _has_field_.set(field.id());
+ }
+ switch (field.id()) {
+ case 1 /* buffers */:
+ buffers_.emplace_back();
+ buffers_.back().ParseFromArray(field.data(), field.size());
+ break;
+ case 50 /* experimental_trace_buffer_v2_compaction */:
+ field.get(&experimental_trace_buffer_v2_compaction_);
+ break;
+ case 2 /* data_sources */:
+ data_sources_.emplace_back();
+ data_sources_.back().ParseFromArray(field.data(), field.size());
+ break;
+ case 20 /* builtin_data_sources */:
+ (*builtin_data_sources_).ParseFromArray(field.data(), field.size());
+ break;
+ case 3 /* duration_ms */:
+ field.get(&duration_ms_);
+ break;
+ case 36 /* prefer_suspend_clock_for_duration */:
+ field.get(&prefer_suspend_clock_for_duration_);
+ break;
+ case 4 /* enable_extra_guardrails */:
+ field.get(&enable_extra_guardrails_);
+ break;
+ case 5 /* lockdown_mode */:
+ field.get(&lockdown_mode_);
+ break;
+ case 6 /* producers */:
+ producers_.emplace_back();
+ producers_.back().ParseFromArray(field.data(), field.size());
+ break;
+ case 7 /* statsd_metadata */:
+ (*statsd_metadata_).ParseFromArray(field.data(), field.size());
+ break;
+ case 8 /* write_into_file */:
+ field.get(&write_into_file_);
+ break;
+ case 29 /* output_path */:
+ ::protozero::internal::gen_helpers::DeserializeString(field, &output_path_);
+ break;
+ case 9 /* file_write_period_ms */:
+ field.get(&file_write_period_ms_);
+ break;
+ case 10 /* max_file_size_bytes */:
+ field.get(&max_file_size_bytes_);
+ break;
+ case 11 /* guardrail_overrides */:
+ (*guardrail_overrides_).ParseFromArray(field.data(), field.size());
+ break;
+ case 12 /* deferred_start */:
+ field.get(&deferred_start_);
+ break;
+ case 13 /* flush_period_ms */:
+ field.get(&flush_period_ms_);
+ break;
+ case 14 /* flush_timeout_ms */:
+ field.get(&flush_timeout_ms_);
+ break;
+ case 23 /* data_source_stop_timeout_ms */:
+ field.get(&data_source_stop_timeout_ms_);
+ break;
+ case 16 /* notify_traceur */:
+ field.get(¬ify_traceur_);
+ break;
+ case 30 /* bugreport_score */:
+ field.get(&bugreport_score_);
+ break;
+ case 38 /* bugreport_filename */:
+ ::protozero::internal::gen_helpers::DeserializeString(field, &bugreport_filename_);
+ break;
+ case 17 /* trigger_config */:
+ (*trigger_config_).ParseFromArray(field.data(), field.size());
+ break;
+ case 18 /* activate_triggers */:
+ activate_triggers_.emplace_back();
+ ::protozero::internal::gen_helpers::DeserializeString(field, &activate_triggers_.back());
+ break;
+ case 21 /* incremental_state_config */:
+ (*incremental_state_config_).ParseFromArray(field.data(), field.size());
+ break;
+ case 19 /* allow_user_build_tracing */:
+ field.get(&allow_user_build_tracing_);
+ break;
+ case 22 /* unique_session_name */:
+ ::protozero::internal::gen_helpers::DeserializeString(field, &unique_session_name_);
+ break;
+ case 24 /* compression_type */:
+ field.get(&compression_type_);
+ break;
+ case 47 /* compression */:
+ (*compression_).ParseFromArray(field.data(), field.size());
+ break;
+ case 25 /* incident_report_config */:
+ (*incident_report_config_).ParseFromArray(field.data(), field.size());
+ break;
+ case 31 /* statsd_logging */:
+ field.get(&statsd_logging_);
+ break;
+ case 27 /* trace_uuid_msb */:
+ field.get(&trace_uuid_msb_);
+ break;
+ case 28 /* trace_uuid_lsb */:
+ field.get(&trace_uuid_lsb_);
+ break;
+ case 33 /* trace_filter */:
+ (*trace_filter_).ParseFromArray(field.data(), field.size());
+ break;
+ case 34 /* android_report_config */:
+ (*android_report_config_).ParseFromArray(field.data(), field.size());
+ break;
+ case 35 /* cmd_trace_start_delay */:
+ (*cmd_trace_start_delay_).ParseFromArray(field.data(), field.size());
+ break;
+ case 39 /* session_semaphores */:
+ session_semaphores_.emplace_back();
+ session_semaphores_.back().ParseFromArray(field.data(), field.size());
+ break;
+ case 40 /* priority_boost */:
+ (*priority_boost_).ParseFromArray(field.data(), field.size());
+ break;
+ case 41 /* exclusive_prio */:
+ field.get(&exclusive_prio_);
+ break;
+ case 44 /* write_flush_mode */:
+ field.get(&write_flush_mode_);
+ break;
+ case 45 /* fflush_post_write */:
+ field.get(&fflush_post_write_);
+ break;
+ case 43 /* trace_all_machines */:
+ field.get(&trace_all_machines_);
+ break;
+ case 48 /* trace_attributes */:
+ (*trace_attributes_).ParseFromArray(field.data(), field.size());
+ break;
+ case 49 /* persist_trace_across_reboots */:
+ field.get(&persist_trace_across_reboots_);
+ break;
+ default:
+ field.SerializeAndAppendTo(&unknown_fields_);
+ break;
+ }
+ }
+ return !packed_error && !dec.bytes_left();
+}
- // Field 26: has_pending_tree
- if (_has_field_[26]) {
- ::protozero::internal::gen_helpers::SerializeTinyVarInt(26, has_pending_tree_, msg);
+std::string TraceConfig::SerializeAsString() const {
+ ::protozero::internal::gen_helpers::MessageSerializer msg;
+ Serialize(msg.get());
+ return msg.SerializeAsString();
+}
+
+std::vector<uint8_t> TraceConfig::SerializeAsArray() const {
+ ::protozero::internal::gen_helpers::MessageSerializer msg;
+ Serialize(msg.get());
+ return msg.SerializeAsArray();
+}
+
+void TraceConfig::Serialize(::protozero::Message* msg) const {
+ // Field 1: buffers
+ for (auto& it : buffers_) {
+ it.Serialize(msg->BeginNestedMessage<::protozero::Message>(1));
}
- // Field 27: pending_tree_is_ready_for_activation
- if (_has_field_[27]) {
- ::protozero::internal::gen_helpers::SerializeTinyVarInt(27, pending_tree_is_ready_for_activation_, msg);
+ // Field 50: experimental_trace_buffer_v2_compaction
+ if (_has_field_[50]) {
+ ::protozero::internal::gen_helpers::SerializeTinyVarInt(50, experimental_trace_buffer_v2_compaction_, msg);
}
- // Field 28: active_tree_needs_first_draw
- if (_has_field_[28]) {
- ::protozero::internal::gen_helpers::SerializeTinyVarInt(28, active_tree_needs_first_draw_, msg);
+ // Field 2: data_sources
+ for (auto& it : data_sources_) {
+ it.Serialize(msg->BeginNestedMessage<::protozero::Message>(2));
}
- // Field 29: active_tree_is_ready_to_draw
+ // Field 20: builtin_data_sources
+ if (_has_field_[20]) {
+ (*builtin_data_sources_).Serialize(msg->BeginNestedMessage<::protozero::Message>(20));
+ }
+
+ // Field 3: duration_ms
+ if (_has_field_[3]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(3, duration_ms_, msg);
+ }
+
+ // Field 36: prefer_suspend_clock_for_duration
+ if (_has_field_[36]) {
+ ::protozero::internal::gen_helpers::SerializeTinyVarInt(36, prefer_suspend_clock_for_duration_, msg);
+ }
+
+ // Field 4: enable_extra_guardrails
+ if (_has_field_[4]) {
+ ::protozero::internal::gen_helpers::SerializeTinyVarInt(4, enable_extra_guardrails_, msg);
+ }
+
+ // Field 5: lockdown_mode
+ if (_has_field_[5]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(5, lockdown_mode_, msg);
+ }
+
+ // Field 6: producers
+ for (auto& it : producers_) {
+ it.Serialize(msg->BeginNestedMessage<::protozero::Message>(6));
+ }
+
+ // Field 7: statsd_metadata
+ if (_has_field_[7]) {
+ (*statsd_metadata_).Serialize(msg->BeginNestedMessage<::protozero::Message>(7));
+ }
+
+ // Field 8: write_into_file
+ if (_has_field_[8]) {
+ ::protozero::internal::gen_helpers::SerializeTinyVarInt(8, write_into_file_, msg);
+ }
+
+ // Field 29: output_path
if (_has_field_[29]) {
- ::protozero::internal::gen_helpers::SerializeTinyVarInt(29, active_tree_is_ready_to_draw_, msg);
+ ::protozero::internal::gen_helpers::SerializeString(29, output_path_, msg);
}
- // Field 30: did_create_and_initialize_first_layer_tree_frame_sink
- if (_has_field_[30]) {
- ::protozero::internal::gen_helpers::SerializeTinyVarInt(30, did_create_and_initialize_first_layer_tree_frame_sink_, msg);
+ // Field 9: file_write_period_ms
+ if (_has_field_[9]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(9, file_write_period_ms_, msg);
}
- // Field 31: tree_priority
- if (_has_field_[31]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(31, tree_priority_, msg);
+ // Field 10: max_file_size_bytes
+ if (_has_field_[10]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(10, max_file_size_bytes_, msg);
}
- // Field 32: scroll_handler_state
- if (_has_field_[32]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(32, scroll_handler_state_, msg);
+ // Field 11: guardrail_overrides
+ if (_has_field_[11]) {
+ (*guardrail_overrides_).Serialize(msg->BeginNestedMessage<::protozero::Message>(11));
}
- // Field 33: critical_begin_main_frame_to_activate_is_fast
- if (_has_field_[33]) {
- ::protozero::internal::gen_helpers::SerializeTinyVarInt(33, critical_begin_main_frame_to_activate_is_fast_, msg);
+ // Field 12: deferred_start
+ if (_has_field_[12]) {
+ ::protozero::internal::gen_helpers::SerializeTinyVarInt(12, deferred_start_, msg);
}
- // Field 34: main_thread_missed_last_deadline
- if (_has_field_[34]) {
- ::protozero::internal::gen_helpers::SerializeTinyVarInt(34, main_thread_missed_last_deadline_, msg);
+ // Field 13: flush_period_ms
+ if (_has_field_[13]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(13, flush_period_ms_, msg);
}
- // Field 36: video_needs_begin_frames
- if (_has_field_[36]) {
- ::protozero::internal::gen_helpers::SerializeTinyVarInt(36, video_needs_begin_frames_, msg);
+ // Field 14: flush_timeout_ms
+ if (_has_field_[14]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(14, flush_timeout_ms_, msg);
}
- // Field 37: defer_begin_main_frame
- if (_has_field_[37]) {
- ::protozero::internal::gen_helpers::SerializeTinyVarInt(37, defer_begin_main_frame_, msg);
+ // Field 23: data_source_stop_timeout_ms
+ if (_has_field_[23]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(23, data_source_stop_timeout_ms_, msg);
}
- // Field 38: last_commit_had_no_updates
+ // Field 16: notify_traceur
+ if (_has_field_[16]) {
+ ::protozero::internal::gen_helpers::SerializeTinyVarInt(16, notify_traceur_, msg);
+ }
+
+ // Field 30: bugreport_score
+ if (_has_field_[30]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(30, bugreport_score_, msg);
+ }
+
+ // Field 38: bugreport_filename
if (_has_field_[38]) {
- ::protozero::internal::gen_helpers::SerializeTinyVarInt(38, last_commit_had_no_updates_, msg);
+ ::protozero::internal::gen_helpers::SerializeString(38, bugreport_filename_, msg);
}
- // Field 39: did_draw_in_last_frame
- if (_has_field_[39]) {
- ::protozero::internal::gen_helpers::SerializeTinyVarInt(39, did_draw_in_last_frame_, msg);
+ // Field 17: trigger_config
+ if (_has_field_[17]) {
+ (*trigger_config_).Serialize(msg->BeginNestedMessage<::protozero::Message>(17));
}
- // Field 40: did_submit_in_last_frame
- if (_has_field_[40]) {
- ::protozero::internal::gen_helpers::SerializeTinyVarInt(40, did_submit_in_last_frame_, msg);
+ // Field 18: activate_triggers
+ for (auto& it : activate_triggers_) {
+ ::protozero::internal::gen_helpers::SerializeString(18, it, msg);
}
- // Field 41: needs_impl_side_invalidation
- if (_has_field_[41]) {
- ::protozero::internal::gen_helpers::SerializeTinyVarInt(41, needs_impl_side_invalidation_, msg);
+ // Field 21: incremental_state_config
+ if (_has_field_[21]) {
+ (*incremental_state_config_).Serialize(msg->BeginNestedMessage<::protozero::Message>(21));
}
- // Field 42: current_pending_tree_is_impl_side
- if (_has_field_[42]) {
- ::protozero::internal::gen_helpers::SerializeTinyVarInt(42, current_pending_tree_is_impl_side_, msg);
+ // Field 19: allow_user_build_tracing
+ if (_has_field_[19]) {
+ ::protozero::internal::gen_helpers::SerializeTinyVarInt(19, allow_user_build_tracing_, msg);
}
- // Field 43: previous_pending_tree_was_impl_side
- if (_has_field_[43]) {
- ::protozero::internal::gen_helpers::SerializeTinyVarInt(43, previous_pending_tree_was_impl_side_, msg);
+ // Field 22: unique_session_name
+ if (_has_field_[22]) {
+ ::protozero::internal::gen_helpers::SerializeString(22, unique_session_name_, msg);
}
- // Field 44: processing_animation_worklets_for_active_tree
+ // Field 24: compression_type
+ if (_has_field_[24]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(24, compression_type_, msg);
+ }
+
+ // Field 47: compression
+ if (_has_field_[47]) {
+ (*compression_).Serialize(msg->BeginNestedMessage<::protozero::Message>(47));
+ }
+
+ // Field 25: incident_report_config
+ if (_has_field_[25]) {
+ (*incident_report_config_).Serialize(msg->BeginNestedMessage<::protozero::Message>(25));
+ }
+
+ // Field 31: statsd_logging
+ if (_has_field_[31]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(31, statsd_logging_, msg);
+ }
+
+ // Field 27: trace_uuid_msb
+ if (_has_field_[27]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(27, trace_uuid_msb_, msg);
+ }
+
+ // Field 28: trace_uuid_lsb
+ if (_has_field_[28]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(28, trace_uuid_lsb_, msg);
+ }
+
+ // Field 33: trace_filter
+ if (_has_field_[33]) {
+ (*trace_filter_).Serialize(msg->BeginNestedMessage<::protozero::Message>(33));
+ }
+
+ // Field 34: android_report_config
+ if (_has_field_[34]) {
+ (*android_report_config_).Serialize(msg->BeginNestedMessage<::protozero::Message>(34));
+ }
+
+ // Field 35: cmd_trace_start_delay
+ if (_has_field_[35]) {
+ (*cmd_trace_start_delay_).Serialize(msg->BeginNestedMessage<::protozero::Message>(35));
+ }
+
+ // Field 39: session_semaphores
+ for (auto& it : session_semaphores_) {
+ it.Serialize(msg->BeginNestedMessage<::protozero::Message>(39));
+ }
+
+ // Field 40: priority_boost
+ if (_has_field_[40]) {
+ (*priority_boost_).Serialize(msg->BeginNestedMessage<::protozero::Message>(40));
+ }
+
+ // Field 41: exclusive_prio
+ if (_has_field_[41]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(41, exclusive_prio_, msg);
+ }
+
+ // Field 44: write_flush_mode
if (_has_field_[44]) {
- ::protozero::internal::gen_helpers::SerializeTinyVarInt(44, processing_animation_worklets_for_active_tree_, msg);
+ ::protozero::internal::gen_helpers::SerializeVarInt(44, write_flush_mode_, msg);
}
- // Field 45: processing_animation_worklets_for_pending_tree
+ // Field 45: fflush_post_write
if (_has_field_[45]) {
- ::protozero::internal::gen_helpers::SerializeTinyVarInt(45, processing_animation_worklets_for_pending_tree_, msg);
+ ::protozero::internal::gen_helpers::SerializeVarInt(45, fflush_post_write_, msg);
}
- // Field 46: processing_paint_worklets_for_pending_tree
- if (_has_field_[46]) {
- ::protozero::internal::gen_helpers::SerializeTinyVarInt(46, processing_paint_worklets_for_pending_tree_, msg);
+ // Field 43: trace_all_machines
+ if (_has_field_[43]) {
+ ::protozero::internal::gen_helpers::SerializeTinyVarInt(43, trace_all_machines_, msg);
+ }
+
+ // Field 48: trace_attributes
+ if (_has_field_[48]) {
+ (*trace_attributes_).Serialize(msg->BeginNestedMessage<::protozero::Message>(48));
+ }
+
+ // Field 49: persist_trace_across_reboots
+ if (_has_field_[49]) {
+ ::protozero::internal::gen_helpers::SerializeTinyVarInt(49, persist_trace_across_reboots_, msg);
}
protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
}
-ChromeCompositorStateMachine_MajorState::ChromeCompositorStateMachine_MajorState() = default;
-ChromeCompositorStateMachine_MajorState::~ChromeCompositorStateMachine_MajorState() = default;
-ChromeCompositorStateMachine_MajorState::ChromeCompositorStateMachine_MajorState(const ChromeCompositorStateMachine_MajorState&) = default;
-ChromeCompositorStateMachine_MajorState& ChromeCompositorStateMachine_MajorState::operator=(const ChromeCompositorStateMachine_MajorState&) = default;
-ChromeCompositorStateMachine_MajorState::ChromeCompositorStateMachine_MajorState(ChromeCompositorStateMachine_MajorState&&) noexcept = default;
-ChromeCompositorStateMachine_MajorState& ChromeCompositorStateMachine_MajorState::operator=(ChromeCompositorStateMachine_MajorState&&) = default;
+TraceConfig_SessionSemaphore::TraceConfig_SessionSemaphore() = default;
+TraceConfig_SessionSemaphore::~TraceConfig_SessionSemaphore() = default;
+TraceConfig_SessionSemaphore::TraceConfig_SessionSemaphore(const TraceConfig_SessionSemaphore&) = default;
+TraceConfig_SessionSemaphore& TraceConfig_SessionSemaphore::operator=(const TraceConfig_SessionSemaphore&) = default;
+TraceConfig_SessionSemaphore::TraceConfig_SessionSemaphore(TraceConfig_SessionSemaphore&&) noexcept = default;
+TraceConfig_SessionSemaphore& TraceConfig_SessionSemaphore::operator=(TraceConfig_SessionSemaphore&&) = default;
-bool ChromeCompositorStateMachine_MajorState::operator==(const ChromeCompositorStateMachine_MajorState& other) const {
+bool TraceConfig_SessionSemaphore::operator==(const TraceConfig_SessionSemaphore& other) const {
return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
- && ::protozero::internal::gen_helpers::EqualsField(next_action_, other.next_action_)
- && ::protozero::internal::gen_helpers::EqualsField(begin_impl_frame_state_, other.begin_impl_frame_state_)
- && ::protozero::internal::gen_helpers::EqualsField(begin_main_frame_state_, other.begin_main_frame_state_)
- && ::protozero::internal::gen_helpers::EqualsField(layer_tree_frame_sink_state_, other.layer_tree_frame_sink_state_)
- && ::protozero::internal::gen_helpers::EqualsField(forced_redraw_state_, other.forced_redraw_state_);
+ && ::protozero::internal::gen_helpers::EqualsField(name_, other.name_)
+ && ::protozero::internal::gen_helpers::EqualsField(max_other_session_count_, other.max_other_session_count_);
}
-bool ChromeCompositorStateMachine_MajorState::ParseFromArray(const void* raw, size_t size) {
+bool TraceConfig_SessionSemaphore::ParseFromArray(const void* raw, size_t size) {
unknown_fields_.clear();
bool packed_error = false;
@@ -33551,20 +34082,11 @@ bool ChromeCompositorStateMachine_MajorState::ParseFromArray(const void* raw, si
_has_field_.set(field.id());
}
switch (field.id()) {
- case 1 /* next_action */:
- field.get(&next_action_);
- break;
- case 2 /* begin_impl_frame_state */:
- field.get(&begin_impl_frame_state_);
- break;
- case 3 /* begin_main_frame_state */:
- field.get(&begin_main_frame_state_);
- break;
- case 4 /* layer_tree_frame_sink_state */:
- field.get(&layer_tree_frame_sink_state_);
+ case 1 /* name */:
+ ::protozero::internal::gen_helpers::DeserializeString(field, &name_);
break;
- case 5 /* forced_redraw_state */:
- field.get(&forced_redraw_state_);
+ case 2 /* max_other_session_count */:
+ field.get(&max_other_session_count_);
break;
default:
field.SerializeAndAppendTo(&unknown_fields_);
@@ -33574,76 +34096,47 @@ bool ChromeCompositorStateMachine_MajorState::ParseFromArray(const void* raw, si
return !packed_error && !dec.bytes_left();
}
-std::string ChromeCompositorStateMachine_MajorState::SerializeAsString() const {
+std::string TraceConfig_SessionSemaphore::SerializeAsString() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsString();
}
-std::vector<uint8_t> ChromeCompositorStateMachine_MajorState::SerializeAsArray() const {
+std::vector<uint8_t> TraceConfig_SessionSemaphore::SerializeAsArray() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsArray();
}
-void ChromeCompositorStateMachine_MajorState::Serialize(::protozero::Message* msg) const {
- // Field 1: next_action
+void TraceConfig_SessionSemaphore::Serialize(::protozero::Message* msg) const {
+ // Field 1: name
if (_has_field_[1]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(1, next_action_, msg);
+ ::protozero::internal::gen_helpers::SerializeString(1, name_, msg);
}
- // Field 2: begin_impl_frame_state
+ // Field 2: max_other_session_count
if (_has_field_[2]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(2, begin_impl_frame_state_, msg);
- }
-
- // Field 3: begin_main_frame_state
- if (_has_field_[3]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(3, begin_main_frame_state_, msg);
- }
-
- // Field 4: layer_tree_frame_sink_state
- if (_has_field_[4]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(4, layer_tree_frame_sink_state_, msg);
- }
-
- // Field 5: forced_redraw_state
- if (_has_field_[5]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(5, forced_redraw_state_, msg);
+ ::protozero::internal::gen_helpers::SerializeVarInt(2, max_other_session_count_, msg);
}
protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
}
-ChromeCompositorSchedulerState::ChromeCompositorSchedulerState() = default;
-ChromeCompositorSchedulerState::~ChromeCompositorSchedulerState() = default;
-ChromeCompositorSchedulerState::ChromeCompositorSchedulerState(const ChromeCompositorSchedulerState&) = default;
-ChromeCompositorSchedulerState& ChromeCompositorSchedulerState::operator=(const ChromeCompositorSchedulerState&) = default;
-ChromeCompositorSchedulerState::ChromeCompositorSchedulerState(ChromeCompositorSchedulerState&&) noexcept = default;
-ChromeCompositorSchedulerState& ChromeCompositorSchedulerState::operator=(ChromeCompositorSchedulerState&&) = default;
+TraceConfig_CmdTraceStartDelay::TraceConfig_CmdTraceStartDelay() = default;
+TraceConfig_CmdTraceStartDelay::~TraceConfig_CmdTraceStartDelay() = default;
+TraceConfig_CmdTraceStartDelay::TraceConfig_CmdTraceStartDelay(const TraceConfig_CmdTraceStartDelay&) = default;
+TraceConfig_CmdTraceStartDelay& TraceConfig_CmdTraceStartDelay::operator=(const TraceConfig_CmdTraceStartDelay&) = default;
+TraceConfig_CmdTraceStartDelay::TraceConfig_CmdTraceStartDelay(TraceConfig_CmdTraceStartDelay&&) noexcept = default;
+TraceConfig_CmdTraceStartDelay& TraceConfig_CmdTraceStartDelay::operator=(TraceConfig_CmdTraceStartDelay&&) = default;
-bool ChromeCompositorSchedulerState::operator==(const ChromeCompositorSchedulerState& other) const {
+bool TraceConfig_CmdTraceStartDelay::operator==(const TraceConfig_CmdTraceStartDelay& other) const {
return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
- && ::protozero::internal::gen_helpers::EqualsField(state_machine_, other.state_machine_)
- && ::protozero::internal::gen_helpers::EqualsField(observing_begin_frame_source_, other.observing_begin_frame_source_)
- && ::protozero::internal::gen_helpers::EqualsField(begin_impl_frame_deadline_task_, other.begin_impl_frame_deadline_task_)
- && ::protozero::internal::gen_helpers::EqualsField(pending_begin_frame_task_, other.pending_begin_frame_task_)
- && ::protozero::internal::gen_helpers::EqualsField(skipped_last_frame_missed_exceeded_deadline_, other.skipped_last_frame_missed_exceeded_deadline_)
- && ::protozero::internal::gen_helpers::EqualsField(inside_action_, other.inside_action_)
- && ::protozero::internal::gen_helpers::EqualsField(deadline_mode_, other.deadline_mode_)
- && ::protozero::internal::gen_helpers::EqualsField(deadline_us_, other.deadline_us_)
- && ::protozero::internal::gen_helpers::EqualsField(deadline_scheduled_at_us_, other.deadline_scheduled_at_us_)
- && ::protozero::internal::gen_helpers::EqualsField(now_us_, other.now_us_)
- && ::protozero::internal::gen_helpers::EqualsField(now_to_deadline_delta_us_, other.now_to_deadline_delta_us_)
- && ::protozero::internal::gen_helpers::EqualsField(now_to_deadline_scheduled_at_delta_us_, other.now_to_deadline_scheduled_at_delta_us_)
- && ::protozero::internal::gen_helpers::EqualsField(begin_impl_frame_args_, other.begin_impl_frame_args_)
- && ::protozero::internal::gen_helpers::EqualsField(begin_frame_observer_state_, other.begin_frame_observer_state_)
- && ::protozero::internal::gen_helpers::EqualsField(begin_frame_source_state_, other.begin_frame_source_state_)
- && ::protozero::internal::gen_helpers::EqualsField(compositor_timing_history_, other.compositor_timing_history_);
+ && ::protozero::internal::gen_helpers::EqualsField(min_delay_ms_, other.min_delay_ms_)
+ && ::protozero::internal::gen_helpers::EqualsField(max_delay_ms_, other.max_delay_ms_);
}
-bool ChromeCompositorSchedulerState::ParseFromArray(const void* raw, size_t size) {
+bool TraceConfig_CmdTraceStartDelay::ParseFromArray(const void* raw, size_t size) {
unknown_fields_.clear();
bool packed_error = false;
@@ -33653,194 +34146,63 @@ bool ChromeCompositorSchedulerState::ParseFromArray(const void* raw, size_t size
_has_field_.set(field.id());
}
switch (field.id()) {
- case 1 /* state_machine */:
- (*state_machine_).ParseFromArray(field.data(), field.size());
- break;
- case 2 /* observing_begin_frame_source */:
- field.get(&observing_begin_frame_source_);
- break;
- case 3 /* begin_impl_frame_deadline_task */:
- field.get(&begin_impl_frame_deadline_task_);
- break;
- case 4 /* pending_begin_frame_task */:
- field.get(&pending_begin_frame_task_);
+ case 1 /* min_delay_ms */:
+ field.get(&min_delay_ms_);
break;
- case 5 /* skipped_last_frame_missed_exceeded_deadline */:
- field.get(&skipped_last_frame_missed_exceeded_deadline_);
+ case 2 /* max_delay_ms */:
+ field.get(&max_delay_ms_);
break;
- case 7 /* inside_action */:
- field.get(&inside_action_);
- break;
- case 8 /* deadline_mode */:
- field.get(&deadline_mode_);
- break;
- case 9 /* deadline_us */:
- field.get(&deadline_us_);
- break;
- case 10 /* deadline_scheduled_at_us */:
- field.get(&deadline_scheduled_at_us_);
- break;
- case 11 /* now_us */:
- field.get(&now_us_);
- break;
- case 12 /* now_to_deadline_delta_us */:
- field.get(&now_to_deadline_delta_us_);
- break;
- case 13 /* now_to_deadline_scheduled_at_delta_us */:
- field.get(&now_to_deadline_scheduled_at_delta_us_);
- break;
- case 14 /* begin_impl_frame_args */:
- (*begin_impl_frame_args_).ParseFromArray(field.data(), field.size());
- break;
- case 15 /* begin_frame_observer_state */:
- (*begin_frame_observer_state_).ParseFromArray(field.data(), field.size());
- break;
- case 16 /* begin_frame_source_state */:
- (*begin_frame_source_state_).ParseFromArray(field.data(), field.size());
- break;
- case 17 /* compositor_timing_history */:
- (*compositor_timing_history_).ParseFromArray(field.data(), field.size());
- break;
- default:
- field.SerializeAndAppendTo(&unknown_fields_);
+ default:
+ field.SerializeAndAppendTo(&unknown_fields_);
break;
}
}
return !packed_error && !dec.bytes_left();
}
-std::string ChromeCompositorSchedulerState::SerializeAsString() const {
+std::string TraceConfig_CmdTraceStartDelay::SerializeAsString() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsString();
}
-std::vector<uint8_t> ChromeCompositorSchedulerState::SerializeAsArray() const {
+std::vector<uint8_t> TraceConfig_CmdTraceStartDelay::SerializeAsArray() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsArray();
}
-void ChromeCompositorSchedulerState::Serialize(::protozero::Message* msg) const {
- // Field 1: state_machine
+void TraceConfig_CmdTraceStartDelay::Serialize(::protozero::Message* msg) const {
+ // Field 1: min_delay_ms
if (_has_field_[1]) {
- (*state_machine_).Serialize(msg->BeginNestedMessage<::protozero::Message>(1));
+ ::protozero::internal::gen_helpers::SerializeVarInt(1, min_delay_ms_, msg);
}
- // Field 2: observing_begin_frame_source
+ // Field 2: max_delay_ms
if (_has_field_[2]) {
- ::protozero::internal::gen_helpers::SerializeTinyVarInt(2, observing_begin_frame_source_, msg);
- }
-
- // Field 3: begin_impl_frame_deadline_task
- if (_has_field_[3]) {
- ::protozero::internal::gen_helpers::SerializeTinyVarInt(3, begin_impl_frame_deadline_task_, msg);
- }
-
- // Field 4: pending_begin_frame_task
- if (_has_field_[4]) {
- ::protozero::internal::gen_helpers::SerializeTinyVarInt(4, pending_begin_frame_task_, msg);
- }
-
- // Field 5: skipped_last_frame_missed_exceeded_deadline
- if (_has_field_[5]) {
- ::protozero::internal::gen_helpers::SerializeTinyVarInt(5, skipped_last_frame_missed_exceeded_deadline_, msg);
- }
-
- // Field 7: inside_action
- if (_has_field_[7]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(7, inside_action_, msg);
- }
-
- // Field 8: deadline_mode
- if (_has_field_[8]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(8, deadline_mode_, msg);
- }
-
- // Field 9: deadline_us
- if (_has_field_[9]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(9, deadline_us_, msg);
- }
-
- // Field 10: deadline_scheduled_at_us
- if (_has_field_[10]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(10, deadline_scheduled_at_us_, msg);
- }
-
- // Field 11: now_us
- if (_has_field_[11]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(11, now_us_, msg);
- }
-
- // Field 12: now_to_deadline_delta_us
- if (_has_field_[12]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(12, now_to_deadline_delta_us_, msg);
- }
-
- // Field 13: now_to_deadline_scheduled_at_delta_us
- if (_has_field_[13]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(13, now_to_deadline_scheduled_at_delta_us_, msg);
- }
-
- // Field 14: begin_impl_frame_args
- if (_has_field_[14]) {
- (*begin_impl_frame_args_).Serialize(msg->BeginNestedMessage<::protozero::Message>(14));
- }
-
- // Field 15: begin_frame_observer_state
- if (_has_field_[15]) {
- (*begin_frame_observer_state_).Serialize(msg->BeginNestedMessage<::protozero::Message>(15));
- }
-
- // Field 16: begin_frame_source_state
- if (_has_field_[16]) {
- (*begin_frame_source_state_).Serialize(msg->BeginNestedMessage<::protozero::Message>(16));
- }
-
- // Field 17: compositor_timing_history
- if (_has_field_[17]) {
- (*compositor_timing_history_).Serialize(msg->BeginNestedMessage<::protozero::Message>(17));
+ ::protozero::internal::gen_helpers::SerializeVarInt(2, max_delay_ms_, msg);
}
protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
}
-} // namespace perfetto
-} // namespace protos
-} // namespace gen
-#if defined(__GNUC__) || defined(__clang__)
-#pragma GCC diagnostic pop
-#endif
-// gen_amalgamated begin source: gen/protos/perfetto/trace/track_event/chrome_content_settings_event_info.gen.cc
-// gen_amalgamated expanded: #include "perfetto/protozero/gen_field_helpers.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/message.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/packed_repeated_fields.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/proto_decoder.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/scattered_heap_buffer.h"
-// DO NOT EDIT. Autogenerated by Perfetto cppgen_plugin
-#if defined(__GNUC__) || defined(__clang__)
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wfloat-equal"
-#endif
-// gen_amalgamated expanded: #include "protos/perfetto/trace/track_event/chrome_content_settings_event_info.gen.h"
-
-namespace perfetto {
-namespace protos {
-namespace gen {
-ChromeContentSettingsEventInfo::ChromeContentSettingsEventInfo() = default;
-ChromeContentSettingsEventInfo::~ChromeContentSettingsEventInfo() = default;
-ChromeContentSettingsEventInfo::ChromeContentSettingsEventInfo(const ChromeContentSettingsEventInfo&) = default;
-ChromeContentSettingsEventInfo& ChromeContentSettingsEventInfo::operator=(const ChromeContentSettingsEventInfo&) = default;
-ChromeContentSettingsEventInfo::ChromeContentSettingsEventInfo(ChromeContentSettingsEventInfo&&) noexcept = default;
-ChromeContentSettingsEventInfo& ChromeContentSettingsEventInfo::operator=(ChromeContentSettingsEventInfo&&) = default;
+TraceConfig_AndroidReportConfig::TraceConfig_AndroidReportConfig() = default;
+TraceConfig_AndroidReportConfig::~TraceConfig_AndroidReportConfig() = default;
+TraceConfig_AndroidReportConfig::TraceConfig_AndroidReportConfig(const TraceConfig_AndroidReportConfig&) = default;
+TraceConfig_AndroidReportConfig& TraceConfig_AndroidReportConfig::operator=(const TraceConfig_AndroidReportConfig&) = default;
+TraceConfig_AndroidReportConfig::TraceConfig_AndroidReportConfig(TraceConfig_AndroidReportConfig&&) noexcept = default;
+TraceConfig_AndroidReportConfig& TraceConfig_AndroidReportConfig::operator=(TraceConfig_AndroidReportConfig&&) = default;
-bool ChromeContentSettingsEventInfo::operator==(const ChromeContentSettingsEventInfo& other) const {
+bool TraceConfig_AndroidReportConfig::operator==(const TraceConfig_AndroidReportConfig& other) const {
return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
- && ::protozero::internal::gen_helpers::EqualsField(number_of_exceptions_, other.number_of_exceptions_);
+ && ::protozero::internal::gen_helpers::EqualsField(reporter_service_package_, other.reporter_service_package_)
+ && ::protozero::internal::gen_helpers::EqualsField(reporter_service_class_, other.reporter_service_class_)
+ && ::protozero::internal::gen_helpers::EqualsField(skip_report_, other.skip_report_)
+ && ::protozero::internal::gen_helpers::EqualsField(use_pipe_in_framework_for_testing_, other.use_pipe_in_framework_for_testing_);
}
-bool ChromeContentSettingsEventInfo::ParseFromArray(const void* raw, size_t size) {
+bool TraceConfig_AndroidReportConfig::ParseFromArray(const void* raw, size_t size) {
unknown_fields_.clear();
bool packed_error = false;
@@ -33850,8 +34212,17 @@ bool ChromeContentSettingsEventInfo::ParseFromArray(const void* raw, size_t size
_has_field_.set(field.id());
}
switch (field.id()) {
- case 1 /* number_of_exceptions */:
- field.get(&number_of_exceptions_);
+ case 1 /* reporter_service_package */:
+ ::protozero::internal::gen_helpers::DeserializeString(field, &reporter_service_package_);
+ break;
+ case 2 /* reporter_service_class */:
+ ::protozero::internal::gen_helpers::DeserializeString(field, &reporter_service_class_);
+ break;
+ case 3 /* skip_report */:
+ field.get(&skip_report_);
+ break;
+ case 4 /* use_pipe_in_framework_for_testing */:
+ field.get(&use_pipe_in_framework_for_testing_);
break;
default:
field.SerializeAndAppendTo(&unknown_fields_);
@@ -33861,81 +34232,60 @@ bool ChromeContentSettingsEventInfo::ParseFromArray(const void* raw, size_t size
return !packed_error && !dec.bytes_left();
}
-std::string ChromeContentSettingsEventInfo::SerializeAsString() const {
+std::string TraceConfig_AndroidReportConfig::SerializeAsString() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsString();
}
-std::vector<uint8_t> ChromeContentSettingsEventInfo::SerializeAsArray() const {
+std::vector<uint8_t> TraceConfig_AndroidReportConfig::SerializeAsArray() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsArray();
}
-void ChromeContentSettingsEventInfo::Serialize(::protozero::Message* msg) const {
- // Field 1: number_of_exceptions
+void TraceConfig_AndroidReportConfig::Serialize(::protozero::Message* msg) const {
+ // Field 1: reporter_service_package
if (_has_field_[1]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(1, number_of_exceptions_, msg);
+ ::protozero::internal::gen_helpers::SerializeString(1, reporter_service_package_, msg);
+ }
+
+ // Field 2: reporter_service_class
+ if (_has_field_[2]) {
+ ::protozero::internal::gen_helpers::SerializeString(2, reporter_service_class_, msg);
+ }
+
+ // Field 3: skip_report
+ if (_has_field_[3]) {
+ ::protozero::internal::gen_helpers::SerializeTinyVarInt(3, skip_report_, msg);
+ }
+
+ // Field 4: use_pipe_in_framework_for_testing
+ if (_has_field_[4]) {
+ ::protozero::internal::gen_helpers::SerializeTinyVarInt(4, use_pipe_in_framework_for_testing_, msg);
}
protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
}
-} // namespace perfetto
-} // namespace protos
-} // namespace gen
-#if defined(__GNUC__) || defined(__clang__)
-#pragma GCC diagnostic pop
-#endif
-// gen_amalgamated begin source: gen/protos/perfetto/trace/track_event/chrome_frame_reporter.gen.cc
-// gen_amalgamated expanded: #include "perfetto/protozero/gen_field_helpers.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/message.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/packed_repeated_fields.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/proto_decoder.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/scattered_heap_buffer.h"
-// DO NOT EDIT. Autogenerated by Perfetto cppgen_plugin
-#if defined(__GNUC__) || defined(__clang__)
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wfloat-equal"
-#endif
-// gen_amalgamated expanded: #include "protos/perfetto/trace/track_event/chrome_frame_reporter.gen.h"
-
-namespace perfetto {
-namespace protos {
-namespace gen {
-ChromeFrameReporter::ChromeFrameReporter() = default;
-ChromeFrameReporter::~ChromeFrameReporter() = default;
-ChromeFrameReporter::ChromeFrameReporter(const ChromeFrameReporter&) = default;
-ChromeFrameReporter& ChromeFrameReporter::operator=(const ChromeFrameReporter&) = default;
-ChromeFrameReporter::ChromeFrameReporter(ChromeFrameReporter&&) noexcept = default;
-ChromeFrameReporter& ChromeFrameReporter::operator=(ChromeFrameReporter&&) = default;
+TraceConfig_TraceFilter::TraceConfig_TraceFilter() = default;
+TraceConfig_TraceFilter::~TraceConfig_TraceFilter() = default;
+TraceConfig_TraceFilter::TraceConfig_TraceFilter(const TraceConfig_TraceFilter&) = default;
+TraceConfig_TraceFilter& TraceConfig_TraceFilter::operator=(const TraceConfig_TraceFilter&) = default;
+TraceConfig_TraceFilter::TraceConfig_TraceFilter(TraceConfig_TraceFilter&&) noexcept = default;
+TraceConfig_TraceFilter& TraceConfig_TraceFilter::operator=(TraceConfig_TraceFilter&&) = default;
-bool ChromeFrameReporter::operator==(const ChromeFrameReporter& other) const {
+bool TraceConfig_TraceFilter::operator==(const TraceConfig_TraceFilter& other) const {
return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
- && ::protozero::internal::gen_helpers::EqualsField(state_, other.state_)
- && ::protozero::internal::gen_helpers::EqualsField(reason_, other.reason_)
- && ::protozero::internal::gen_helpers::EqualsField(frame_source_, other.frame_source_)
- && ::protozero::internal::gen_helpers::EqualsField(frame_sequence_, other.frame_sequence_)
- && ::protozero::internal::gen_helpers::EqualsField(affects_smoothness_, other.affects_smoothness_)
- && ::protozero::internal::gen_helpers::EqualsField(scroll_state_, other.scroll_state_)
- && ::protozero::internal::gen_helpers::EqualsField(has_main_animation_, other.has_main_animation_)
- && ::protozero::internal::gen_helpers::EqualsField(has_compositor_animation_, other.has_compositor_animation_)
- && ::protozero::internal::gen_helpers::EqualsField(has_smooth_input_main_, other.has_smooth_input_main_)
- && ::protozero::internal::gen_helpers::EqualsField(has_missing_content_, other.has_missing_content_)
- && ::protozero::internal::gen_helpers::EqualsField(layer_tree_host_id_, other.layer_tree_host_id_)
- && ::protozero::internal::gen_helpers::EqualsField(has_high_latency_, other.has_high_latency_)
- && ::protozero::internal::gen_helpers::EqualsField(frame_type_, other.frame_type_)
- && ::protozero::internal::gen_helpers::EqualsField(high_latency_contribution_stage_, other.high_latency_contribution_stage_)
- && ::protozero::internal::gen_helpers::EqualsField(checkerboarded_needs_raster_, other.checkerboarded_needs_raster_)
- && ::protozero::internal::gen_helpers::EqualsField(checkerboarded_needs_record_, other.checkerboarded_needs_record_)
- && ::protozero::internal::gen_helpers::EqualsField(surface_frame_trace_id_, other.surface_frame_trace_id_)
- && ::protozero::internal::gen_helpers::EqualsField(display_trace_id_, other.display_trace_id_);
+ && ::protozero::internal::gen_helpers::EqualsField(bytecode_, other.bytecode_)
+ && ::protozero::internal::gen_helpers::EqualsField(bytecode_v2_, other.bytecode_v2_)
+ && ::protozero::internal::gen_helpers::EqualsField(string_filter_chain_, other.string_filter_chain_)
+ && ::protozero::internal::gen_helpers::EqualsField(bytecode_overlay_v54_, other.bytecode_overlay_v54_)
+ && ::protozero::internal::gen_helpers::EqualsField(string_filter_chain_v54_, other.string_filter_chain_v54_);
}
-bool ChromeFrameReporter::ParseFromArray(const void* raw, size_t size) {
- high_latency_contribution_stage_.clear();
+bool TraceConfig_TraceFilter::ParseFromArray(const void* raw, size_t size) {
unknown_fields_.clear();
bool packed_error = false;
@@ -33945,60 +34295,20 @@ bool ChromeFrameReporter::ParseFromArray(const void* raw, size_t size) {
_has_field_.set(field.id());
}
switch (field.id()) {
- case 1 /* state */:
- field.get(&state_);
- break;
- case 2 /* reason */:
- field.get(&reason_);
- break;
- case 3 /* frame_source */:
- field.get(&frame_source_);
- break;
- case 4 /* frame_sequence */:
- field.get(&frame_sequence_);
- break;
- case 5 /* affects_smoothness */:
- field.get(&affects_smoothness_);
- break;
- case 6 /* scroll_state */:
- field.get(&scroll_state_);
- break;
- case 7 /* has_main_animation */:
- field.get(&has_main_animation_);
- break;
- case 8 /* has_compositor_animation */:
- field.get(&has_compositor_animation_);
- break;
- case 9 /* has_smooth_input_main */:
- field.get(&has_smooth_input_main_);
- break;
- case 10 /* has_missing_content */:
- field.get(&has_missing_content_);
- break;
- case 11 /* layer_tree_host_id */:
- field.get(&layer_tree_host_id_);
- break;
- case 12 /* has_high_latency */:
- field.get(&has_high_latency_);
- break;
- case 13 /* frame_type */:
- field.get(&frame_type_);
- break;
- case 14 /* high_latency_contribution_stage */:
- high_latency_contribution_stage_.emplace_back();
- ::protozero::internal::gen_helpers::DeserializeString(field, &high_latency_contribution_stage_.back());
+ case 1 /* bytecode */:
+ field.get(&bytecode_);
break;
- case 15 /* checkerboarded_needs_raster */:
- field.get(&checkerboarded_needs_raster_);
+ case 2 /* bytecode_v2 */:
+ field.get(&bytecode_v2_);
break;
- case 16 /* checkerboarded_needs_record */:
- field.get(&checkerboarded_needs_record_);
+ case 3 /* string_filter_chain */:
+ (*string_filter_chain_).ParseFromArray(field.data(), field.size());
break;
- case 17 /* surface_frame_trace_id */:
- field.get(&surface_frame_trace_id_);
+ case 4 /* bytecode_overlay_v54 */:
+ field.get(&bytecode_overlay_v54_);
break;
- case 18 /* display_trace_id */:
- field.get(&display_trace_id_);
+ case 5 /* string_filter_chain_v54 */:
+ (*string_filter_chain_v54_).ParseFromArray(field.data(), field.size());
break;
default:
field.SerializeAndAppendTo(&unknown_fields_);
@@ -34008,151 +34318,65 @@ bool ChromeFrameReporter::ParseFromArray(const void* raw, size_t size) {
return !packed_error && !dec.bytes_left();
}
-std::string ChromeFrameReporter::SerializeAsString() const {
+std::string TraceConfig_TraceFilter::SerializeAsString() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsString();
}
-std::vector<uint8_t> ChromeFrameReporter::SerializeAsArray() const {
+std::vector<uint8_t> TraceConfig_TraceFilter::SerializeAsArray() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsArray();
}
-void ChromeFrameReporter::Serialize(::protozero::Message* msg) const {
- // Field 1: state
+void TraceConfig_TraceFilter::Serialize(::protozero::Message* msg) const {
+ // Field 1: bytecode
if (_has_field_[1]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(1, state_, msg);
+ ::protozero::internal::gen_helpers::SerializeString(1, bytecode_, msg);
}
- // Field 2: reason
+ // Field 2: bytecode_v2
if (_has_field_[2]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(2, reason_, msg);
+ ::protozero::internal::gen_helpers::SerializeString(2, bytecode_v2_, msg);
}
- // Field 3: frame_source
+ // Field 3: string_filter_chain
if (_has_field_[3]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(3, frame_source_, msg);
+ (*string_filter_chain_).Serialize(msg->BeginNestedMessage<::protozero::Message>(3));
}
- // Field 4: frame_sequence
+ // Field 4: bytecode_overlay_v54
if (_has_field_[4]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(4, frame_sequence_, msg);
+ ::protozero::internal::gen_helpers::SerializeString(4, bytecode_overlay_v54_, msg);
}
- // Field 5: affects_smoothness
+ // Field 5: string_filter_chain_v54
if (_has_field_[5]) {
- ::protozero::internal::gen_helpers::SerializeTinyVarInt(5, affects_smoothness_, msg);
- }
-
- // Field 6: scroll_state
- if (_has_field_[6]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(6, scroll_state_, msg);
- }
-
- // Field 7: has_main_animation
- if (_has_field_[7]) {
- ::protozero::internal::gen_helpers::SerializeTinyVarInt(7, has_main_animation_, msg);
- }
-
- // Field 8: has_compositor_animation
- if (_has_field_[8]) {
- ::protozero::internal::gen_helpers::SerializeTinyVarInt(8, has_compositor_animation_, msg);
- }
-
- // Field 9: has_smooth_input_main
- if (_has_field_[9]) {
- ::protozero::internal::gen_helpers::SerializeTinyVarInt(9, has_smooth_input_main_, msg);
- }
-
- // Field 10: has_missing_content
- if (_has_field_[10]) {
- ::protozero::internal::gen_helpers::SerializeTinyVarInt(10, has_missing_content_, msg);
- }
-
- // Field 11: layer_tree_host_id
- if (_has_field_[11]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(11, layer_tree_host_id_, msg);
- }
-
- // Field 12: has_high_latency
- if (_has_field_[12]) {
- ::protozero::internal::gen_helpers::SerializeTinyVarInt(12, has_high_latency_, msg);
- }
-
- // Field 13: frame_type
- if (_has_field_[13]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(13, frame_type_, msg);
- }
-
- // Field 14: high_latency_contribution_stage
- for (auto& it : high_latency_contribution_stage_) {
- ::protozero::internal::gen_helpers::SerializeString(14, it, msg);
- }
-
- // Field 15: checkerboarded_needs_raster
- if (_has_field_[15]) {
- ::protozero::internal::gen_helpers::SerializeTinyVarInt(15, checkerboarded_needs_raster_, msg);
- }
-
- // Field 16: checkerboarded_needs_record
- if (_has_field_[16]) {
- ::protozero::internal::gen_helpers::SerializeTinyVarInt(16, checkerboarded_needs_record_, msg);
- }
-
- // Field 17: surface_frame_trace_id
- if (_has_field_[17]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(17, surface_frame_trace_id_, msg);
- }
-
- // Field 18: display_trace_id
- if (_has_field_[18]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(18, display_trace_id_, msg);
+ (*string_filter_chain_v54_).Serialize(msg->BeginNestedMessage<::protozero::Message>(5));
}
protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
}
-} // namespace perfetto
-} // namespace protos
-} // namespace gen
-#if defined(__GNUC__) || defined(__clang__)
-#pragma GCC diagnostic pop
-#endif
-// gen_amalgamated begin source: gen/protos/perfetto/trace/track_event/chrome_histogram_sample.gen.cc
-// gen_amalgamated expanded: #include "perfetto/protozero/gen_field_helpers.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/message.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/packed_repeated_fields.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/proto_decoder.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/scattered_heap_buffer.h"
-// DO NOT EDIT. Autogenerated by Perfetto cppgen_plugin
-#if defined(__GNUC__) || defined(__clang__)
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wfloat-equal"
-#endif
-// gen_amalgamated expanded: #include "protos/perfetto/trace/track_event/chrome_histogram_sample.gen.h"
-
-namespace perfetto {
-namespace protos {
-namespace gen {
-ChromeHistogramSample::ChromeHistogramSample() = default;
-ChromeHistogramSample::~ChromeHistogramSample() = default;
-ChromeHistogramSample::ChromeHistogramSample(const ChromeHistogramSample&) = default;
-ChromeHistogramSample& ChromeHistogramSample::operator=(const ChromeHistogramSample&) = default;
-ChromeHistogramSample::ChromeHistogramSample(ChromeHistogramSample&&) noexcept = default;
-ChromeHistogramSample& ChromeHistogramSample::operator=(ChromeHistogramSample&&) = default;
+TraceConfig_TraceFilter_StringFilterChain::TraceConfig_TraceFilter_StringFilterChain() = default;
+TraceConfig_TraceFilter_StringFilterChain::~TraceConfig_TraceFilter_StringFilterChain() = default;
+TraceConfig_TraceFilter_StringFilterChain::TraceConfig_TraceFilter_StringFilterChain(const TraceConfig_TraceFilter_StringFilterChain&) = default;
+TraceConfig_TraceFilter_StringFilterChain& TraceConfig_TraceFilter_StringFilterChain::operator=(const TraceConfig_TraceFilter_StringFilterChain&) = default;
+TraceConfig_TraceFilter_StringFilterChain::TraceConfig_TraceFilter_StringFilterChain(TraceConfig_TraceFilter_StringFilterChain&&) noexcept = default;
+TraceConfig_TraceFilter_StringFilterChain& TraceConfig_TraceFilter_StringFilterChain::operator=(TraceConfig_TraceFilter_StringFilterChain&&) = default;
-bool ChromeHistogramSample::operator==(const ChromeHistogramSample& other) const {
+bool TraceConfig_TraceFilter_StringFilterChain::operator==(const TraceConfig_TraceFilter_StringFilterChain& other) const {
return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
- && ::protozero::internal::gen_helpers::EqualsField(name_hash_, other.name_hash_)
- && ::protozero::internal::gen_helpers::EqualsField(name_, other.name_)
- && ::protozero::internal::gen_helpers::EqualsField(sample_, other.sample_)
- && ::protozero::internal::gen_helpers::EqualsField(name_iid_, other.name_iid_);
+ && ::protozero::internal::gen_helpers::EqualsField(rules_, other.rules_);
}
-bool ChromeHistogramSample::ParseFromArray(const void* raw, size_t size) {
+int TraceConfig_TraceFilter_StringFilterChain::rules_size() const { return static_cast<int>(rules_.size()); }
+void TraceConfig_TraceFilter_StringFilterChain::clear_rules() { rules_.clear(); }
+TraceConfig_TraceFilter_StringFilterRule* TraceConfig_TraceFilter_StringFilterChain::add_rules() { rules_.emplace_back(); return &rules_.back(); }
+bool TraceConfig_TraceFilter_StringFilterChain::ParseFromArray(const void* raw, size_t size) {
+ rules_.clear();
unknown_fields_.clear();
bool packed_error = false;
@@ -34162,17 +34386,9 @@ bool ChromeHistogramSample::ParseFromArray(const void* raw, size_t size) {
_has_field_.set(field.id());
}
switch (field.id()) {
- case 1 /* name_hash */:
- field.get(&name_hash_);
- break;
- case 2 /* name */:
- ::protozero::internal::gen_helpers::DeserializeString(field, &name_);
- break;
- case 3 /* sample */:
- field.get(&sample_);
- break;
- case 4 /* name_iid */:
- field.get(&name_iid_);
+ case 1 /* rules */:
+ rules_.emplace_back();
+ rules_.back().ParseFromArray(field.data(), field.size());
break;
default:
field.SerializeAndAppendTo(&unknown_fields_);
@@ -34182,57 +34398,46 @@ bool ChromeHistogramSample::ParseFromArray(const void* raw, size_t size) {
return !packed_error && !dec.bytes_left();
}
-std::string ChromeHistogramSample::SerializeAsString() const {
+std::string TraceConfig_TraceFilter_StringFilterChain::SerializeAsString() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsString();
}
-std::vector<uint8_t> ChromeHistogramSample::SerializeAsArray() const {
+std::vector<uint8_t> TraceConfig_TraceFilter_StringFilterChain::SerializeAsArray() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsArray();
}
-void ChromeHistogramSample::Serialize(::protozero::Message* msg) const {
- // Field 1: name_hash
- if (_has_field_[1]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(1, name_hash_, msg);
- }
-
- // Field 2: name
- if (_has_field_[2]) {
- ::protozero::internal::gen_helpers::SerializeString(2, name_, msg);
- }
-
- // Field 3: sample
- if (_has_field_[3]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(3, sample_, msg);
- }
-
- // Field 4: name_iid
- if (_has_field_[4]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(4, name_iid_, msg);
+void TraceConfig_TraceFilter_StringFilterChain::Serialize(::protozero::Message* msg) const {
+ // Field 1: rules
+ for (auto& it : rules_) {
+ it.Serialize(msg->BeginNestedMessage<::protozero::Message>(1));
}
protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
}
-HistogramName::HistogramName() = default;
-HistogramName::~HistogramName() = default;
-HistogramName::HistogramName(const HistogramName&) = default;
-HistogramName& HistogramName::operator=(const HistogramName&) = default;
-HistogramName::HistogramName(HistogramName&&) noexcept = default;
-HistogramName& HistogramName::operator=(HistogramName&&) = default;
+TraceConfig_TraceFilter_StringFilterRule::TraceConfig_TraceFilter_StringFilterRule() = default;
+TraceConfig_TraceFilter_StringFilterRule::~TraceConfig_TraceFilter_StringFilterRule() = default;
+TraceConfig_TraceFilter_StringFilterRule::TraceConfig_TraceFilter_StringFilterRule(const TraceConfig_TraceFilter_StringFilterRule&) = default;
+TraceConfig_TraceFilter_StringFilterRule& TraceConfig_TraceFilter_StringFilterRule::operator=(const TraceConfig_TraceFilter_StringFilterRule&) = default;
+TraceConfig_TraceFilter_StringFilterRule::TraceConfig_TraceFilter_StringFilterRule(TraceConfig_TraceFilter_StringFilterRule&&) noexcept = default;
+TraceConfig_TraceFilter_StringFilterRule& TraceConfig_TraceFilter_StringFilterRule::operator=(TraceConfig_TraceFilter_StringFilterRule&&) = default;
-bool HistogramName::operator==(const HistogramName& other) const {
+bool TraceConfig_TraceFilter_StringFilterRule::operator==(const TraceConfig_TraceFilter_StringFilterRule& other) const {
return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
- && ::protozero::internal::gen_helpers::EqualsField(iid_, other.iid_)
- && ::protozero::internal::gen_helpers::EqualsField(name_, other.name_);
+ && ::protozero::internal::gen_helpers::EqualsField(policy_, other.policy_)
+ && ::protozero::internal::gen_helpers::EqualsField(regex_pattern_, other.regex_pattern_)
+ && ::protozero::internal::gen_helpers::EqualsField(atrace_payload_starts_with_, other.atrace_payload_starts_with_)
+ && ::protozero::internal::gen_helpers::EqualsField(name_, other.name_)
+ && ::protozero::internal::gen_helpers::EqualsField(semantic_type_, other.semantic_type_);
}
-bool HistogramName::ParseFromArray(const void* raw, size_t size) {
+bool TraceConfig_TraceFilter_StringFilterRule::ParseFromArray(const void* raw, size_t size) {
+ semantic_type_.clear();
unknown_fields_.clear();
bool packed_error = false;
@@ -34242,12 +34447,22 @@ bool HistogramName::ParseFromArray(const void* raw, size_t size) {
_has_field_.set(field.id());
}
switch (field.id()) {
- case 1 /* iid */:
- field.get(&iid_);
+ case 1 /* policy */:
+ field.get(&policy_);
break;
- case 2 /* name */:
+ case 2 /* regex_pattern */:
+ ::protozero::internal::gen_helpers::DeserializeString(field, ®ex_pattern_);
+ break;
+ case 3 /* atrace_payload_starts_with */:
+ ::protozero::internal::gen_helpers::DeserializeString(field, &atrace_payload_starts_with_);
+ break;
+ case 4 /* name */:
::protozero::internal::gen_helpers::DeserializeString(field, &name_);
break;
+ case 5 /* semantic_type */:
+ semantic_type_.emplace_back();
+ field.get(&semantic_type_.back());
+ break;
default:
field.SerializeAndAppendTo(&unknown_fields_);
break;
@@ -34256,156 +34471,65 @@ bool HistogramName::ParseFromArray(const void* raw, size_t size) {
return !packed_error && !dec.bytes_left();
}
-std::string HistogramName::SerializeAsString() const {
+std::string TraceConfig_TraceFilter_StringFilterRule::SerializeAsString() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsString();
}
-std::vector<uint8_t> HistogramName::SerializeAsArray() const {
+std::vector<uint8_t> TraceConfig_TraceFilter_StringFilterRule::SerializeAsArray() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsArray();
}
-void HistogramName::Serialize(::protozero::Message* msg) const {
- // Field 1: iid
+void TraceConfig_TraceFilter_StringFilterRule::Serialize(::protozero::Message* msg) const {
+ // Field 1: policy
if (_has_field_[1]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(1, iid_, msg);
+ ::protozero::internal::gen_helpers::SerializeVarInt(1, policy_, msg);
}
- // Field 2: name
+ // Field 2: regex_pattern
if (_has_field_[2]) {
- ::protozero::internal::gen_helpers::SerializeString(2, name_, msg);
+ ::protozero::internal::gen_helpers::SerializeString(2, regex_pattern_, msg);
}
- protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
-}
-
-} // namespace perfetto
-} // namespace protos
-} // namespace gen
-#if defined(__GNUC__) || defined(__clang__)
-#pragma GCC diagnostic pop
-#endif
-// gen_amalgamated begin source: gen/protos/perfetto/trace/track_event/chrome_keyed_service.gen.cc
-// gen_amalgamated expanded: #include "perfetto/protozero/gen_field_helpers.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/message.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/packed_repeated_fields.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/proto_decoder.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/scattered_heap_buffer.h"
-// DO NOT EDIT. Autogenerated by Perfetto cppgen_plugin
-#if defined(__GNUC__) || defined(__clang__)
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wfloat-equal"
-#endif
-// gen_amalgamated expanded: #include "protos/perfetto/trace/track_event/chrome_keyed_service.gen.h"
-
-namespace perfetto {
-namespace protos {
-namespace gen {
-
-ChromeKeyedService::ChromeKeyedService() = default;
-ChromeKeyedService::~ChromeKeyedService() = default;
-ChromeKeyedService::ChromeKeyedService(const ChromeKeyedService&) = default;
-ChromeKeyedService& ChromeKeyedService::operator=(const ChromeKeyedService&) = default;
-ChromeKeyedService::ChromeKeyedService(ChromeKeyedService&&) noexcept = default;
-ChromeKeyedService& ChromeKeyedService::operator=(ChromeKeyedService&&) = default;
-
-bool ChromeKeyedService::operator==(const ChromeKeyedService& other) const {
- return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
- && ::protozero::internal::gen_helpers::EqualsField(name_, other.name_);
-}
-
-bool ChromeKeyedService::ParseFromArray(const void* raw, size_t size) {
- unknown_fields_.clear();
- bool packed_error = false;
-
- ::protozero::ProtoDecoder dec(raw, size);
- for (auto field = dec.ReadField(); field.valid(); field = dec.ReadField()) {
- if (field.id() < _has_field_.size()) {
- _has_field_.set(field.id());
- }
- switch (field.id()) {
- case 1 /* name */:
- ::protozero::internal::gen_helpers::DeserializeString(field, &name_);
- break;
- default:
- field.SerializeAndAppendTo(&unknown_fields_);
- break;
- }
+ // Field 3: atrace_payload_starts_with
+ if (_has_field_[3]) {
+ ::protozero::internal::gen_helpers::SerializeString(3, atrace_payload_starts_with_, msg);
}
- return !packed_error && !dec.bytes_left();
-}
-
-std::string ChromeKeyedService::SerializeAsString() const {
- ::protozero::internal::gen_helpers::MessageSerializer msg;
- Serialize(msg.get());
- return msg.SerializeAsString();
-}
-std::vector<uint8_t> ChromeKeyedService::SerializeAsArray() const {
- ::protozero::internal::gen_helpers::MessageSerializer msg;
- Serialize(msg.get());
- return msg.SerializeAsArray();
-}
+ // Field 4: name
+ if (_has_field_[4]) {
+ ::protozero::internal::gen_helpers::SerializeString(4, name_, msg);
+ }
-void ChromeKeyedService::Serialize(::protozero::Message* msg) const {
- // Field 1: name
- if (_has_field_[1]) {
- ::protozero::internal::gen_helpers::SerializeString(1, name_, msg);
+ // Field 5: semantic_type
+ for (auto& it : semantic_type_) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(5, it, msg);
}
protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
}
-} // namespace perfetto
-} // namespace protos
-} // namespace gen
-#if defined(__GNUC__) || defined(__clang__)
-#pragma GCC diagnostic pop
-#endif
-// gen_amalgamated begin source: gen/protos/perfetto/trace/track_event/chrome_latency_info.gen.cc
-// gen_amalgamated expanded: #include "perfetto/protozero/gen_field_helpers.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/message.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/packed_repeated_fields.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/proto_decoder.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/scattered_heap_buffer.h"
-// DO NOT EDIT. Autogenerated by Perfetto cppgen_plugin
-#if defined(__GNUC__) || defined(__clang__)
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wfloat-equal"
-#endif
-// gen_amalgamated expanded: #include "protos/perfetto/trace/track_event/chrome_latency_info.gen.h"
-
-namespace perfetto {
-namespace protos {
-namespace gen {
-ChromeLatencyInfo::ChromeLatencyInfo() = default;
-ChromeLatencyInfo::~ChromeLatencyInfo() = default;
-ChromeLatencyInfo::ChromeLatencyInfo(const ChromeLatencyInfo&) = default;
-ChromeLatencyInfo& ChromeLatencyInfo::operator=(const ChromeLatencyInfo&) = default;
-ChromeLatencyInfo::ChromeLatencyInfo(ChromeLatencyInfo&&) noexcept = default;
-ChromeLatencyInfo& ChromeLatencyInfo::operator=(ChromeLatencyInfo&&) = default;
+TraceConfig_IncidentReportConfig::TraceConfig_IncidentReportConfig() = default;
+TraceConfig_IncidentReportConfig::~TraceConfig_IncidentReportConfig() = default;
+TraceConfig_IncidentReportConfig::TraceConfig_IncidentReportConfig(const TraceConfig_IncidentReportConfig&) = default;
+TraceConfig_IncidentReportConfig& TraceConfig_IncidentReportConfig::operator=(const TraceConfig_IncidentReportConfig&) = default;
+TraceConfig_IncidentReportConfig::TraceConfig_IncidentReportConfig(TraceConfig_IncidentReportConfig&&) noexcept = default;
+TraceConfig_IncidentReportConfig& TraceConfig_IncidentReportConfig::operator=(TraceConfig_IncidentReportConfig&&) = default;
-bool ChromeLatencyInfo::operator==(const ChromeLatencyInfo& other) const {
+bool TraceConfig_IncidentReportConfig::operator==(const TraceConfig_IncidentReportConfig& other) const {
return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
- && ::protozero::internal::gen_helpers::EqualsField(trace_id_, other.trace_id_)
- && ::protozero::internal::gen_helpers::EqualsField(step_, other.step_)
- && ::protozero::internal::gen_helpers::EqualsField(frame_tree_node_id_, other.frame_tree_node_id_)
- && ::protozero::internal::gen_helpers::EqualsField(component_info_, other.component_info_)
- && ::protozero::internal::gen_helpers::EqualsField(is_coalesced_, other.is_coalesced_)
- && ::protozero::internal::gen_helpers::EqualsField(gesture_scroll_id_, other.gesture_scroll_id_)
- && ::protozero::internal::gen_helpers::EqualsField(touch_id_, other.touch_id_)
- && ::protozero::internal::gen_helpers::EqualsField(input_type_, other.input_type_);
+ && ::protozero::internal::gen_helpers::EqualsField(destination_package_, other.destination_package_)
+ && ::protozero::internal::gen_helpers::EqualsField(destination_class_, other.destination_class_)
+ && ::protozero::internal::gen_helpers::EqualsField(privacy_level_, other.privacy_level_)
+ && ::protozero::internal::gen_helpers::EqualsField(skip_incidentd_, other.skip_incidentd_)
+ && ::protozero::internal::gen_helpers::EqualsField(skip_dropbox_, other.skip_dropbox_);
}
-int ChromeLatencyInfo::component_info_size() const { return static_cast<int>(component_info_.size()); }
-void ChromeLatencyInfo::clear_component_info() { component_info_.clear(); }
-ChromeLatencyInfo_ComponentInfo* ChromeLatencyInfo::add_component_info() { component_info_.emplace_back(); return &component_info_.back(); }
-bool ChromeLatencyInfo::ParseFromArray(const void* raw, size_t size) {
- component_info_.clear();
+bool TraceConfig_IncidentReportConfig::ParseFromArray(const void* raw, size_t size) {
unknown_fields_.clear();
bool packed_error = false;
@@ -34415,30 +34539,20 @@ bool ChromeLatencyInfo::ParseFromArray(const void* raw, size_t size) {
_has_field_.set(field.id());
}
switch (field.id()) {
- case 1 /* trace_id */:
- field.get(&trace_id_);
- break;
- case 2 /* step */:
- field.get(&step_);
- break;
- case 3 /* frame_tree_node_id */:
- field.get(&frame_tree_node_id_);
- break;
- case 4 /* component_info */:
- component_info_.emplace_back();
- component_info_.back().ParseFromArray(field.data(), field.size());
+ case 1 /* destination_package */:
+ ::protozero::internal::gen_helpers::DeserializeString(field, &destination_package_);
break;
- case 5 /* is_coalesced */:
- field.get(&is_coalesced_);
+ case 2 /* destination_class */:
+ ::protozero::internal::gen_helpers::DeserializeString(field, &destination_class_);
break;
- case 6 /* gesture_scroll_id */:
- field.get(&gesture_scroll_id_);
+ case 3 /* privacy_level */:
+ field.get(&privacy_level_);
break;
- case 7 /* touch_id */:
- field.get(&touch_id_);
+ case 5 /* skip_incidentd */:
+ field.get(&skip_incidentd_);
break;
- case 8 /* input_type */:
- field.get(&input_type_);
+ case 4 /* skip_dropbox */:
+ field.get(&skip_dropbox_);
break;
default:
field.SerializeAndAppendTo(&unknown_fields_);
@@ -34448,77 +34562,62 @@ bool ChromeLatencyInfo::ParseFromArray(const void* raw, size_t size) {
return !packed_error && !dec.bytes_left();
}
-std::string ChromeLatencyInfo::SerializeAsString() const {
+std::string TraceConfig_IncidentReportConfig::SerializeAsString() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsString();
}
-std::vector<uint8_t> ChromeLatencyInfo::SerializeAsArray() const {
+std::vector<uint8_t> TraceConfig_IncidentReportConfig::SerializeAsArray() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsArray();
}
-void ChromeLatencyInfo::Serialize(::protozero::Message* msg) const {
- // Field 1: trace_id
+void TraceConfig_IncidentReportConfig::Serialize(::protozero::Message* msg) const {
+ // Field 1: destination_package
if (_has_field_[1]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(1, trace_id_, msg);
+ ::protozero::internal::gen_helpers::SerializeString(1, destination_package_, msg);
}
- // Field 2: step
+ // Field 2: destination_class
if (_has_field_[2]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(2, step_, msg);
+ ::protozero::internal::gen_helpers::SerializeString(2, destination_class_, msg);
}
- // Field 3: frame_tree_node_id
+ // Field 3: privacy_level
if (_has_field_[3]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(3, frame_tree_node_id_, msg);
- }
-
- // Field 4: component_info
- for (auto& it : component_info_) {
- it.Serialize(msg->BeginNestedMessage<::protozero::Message>(4));
+ ::protozero::internal::gen_helpers::SerializeVarInt(3, privacy_level_, msg);
}
- // Field 5: is_coalesced
+ // Field 5: skip_incidentd
if (_has_field_[5]) {
- ::protozero::internal::gen_helpers::SerializeTinyVarInt(5, is_coalesced_, msg);
- }
-
- // Field 6: gesture_scroll_id
- if (_has_field_[6]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(6, gesture_scroll_id_, msg);
- }
-
- // Field 7: touch_id
- if (_has_field_[7]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(7, touch_id_, msg);
+ ::protozero::internal::gen_helpers::SerializeTinyVarInt(5, skip_incidentd_, msg);
}
- // Field 8: input_type
- if (_has_field_[8]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(8, input_type_, msg);
+ // Field 4: skip_dropbox
+ if (_has_field_[4]) {
+ ::protozero::internal::gen_helpers::SerializeTinyVarInt(4, skip_dropbox_, msg);
}
protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
}
-ChromeLatencyInfo_ComponentInfo::ChromeLatencyInfo_ComponentInfo() = default;
-ChromeLatencyInfo_ComponentInfo::~ChromeLatencyInfo_ComponentInfo() = default;
-ChromeLatencyInfo_ComponentInfo::ChromeLatencyInfo_ComponentInfo(const ChromeLatencyInfo_ComponentInfo&) = default;
-ChromeLatencyInfo_ComponentInfo& ChromeLatencyInfo_ComponentInfo::operator=(const ChromeLatencyInfo_ComponentInfo&) = default;
-ChromeLatencyInfo_ComponentInfo::ChromeLatencyInfo_ComponentInfo(ChromeLatencyInfo_ComponentInfo&&) noexcept = default;
-ChromeLatencyInfo_ComponentInfo& ChromeLatencyInfo_ComponentInfo::operator=(ChromeLatencyInfo_ComponentInfo&&) = default;
+TraceConfig_CompressionConfig::TraceConfig_CompressionConfig() = default;
+TraceConfig_CompressionConfig::~TraceConfig_CompressionConfig() = default;
+TraceConfig_CompressionConfig::TraceConfig_CompressionConfig(const TraceConfig_CompressionConfig&) = default;
+TraceConfig_CompressionConfig& TraceConfig_CompressionConfig::operator=(const TraceConfig_CompressionConfig&) = default;
+TraceConfig_CompressionConfig::TraceConfig_CompressionConfig(TraceConfig_CompressionConfig&&) noexcept = default;
+TraceConfig_CompressionConfig& TraceConfig_CompressionConfig::operator=(TraceConfig_CompressionConfig&&) = default;
-bool ChromeLatencyInfo_ComponentInfo::operator==(const ChromeLatencyInfo_ComponentInfo& other) const {
+bool TraceConfig_CompressionConfig::operator==(const TraceConfig_CompressionConfig& other) const {
return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
- && ::protozero::internal::gen_helpers::EqualsField(component_type_, other.component_type_)
- && ::protozero::internal::gen_helpers::EqualsField(time_us_, other.time_us_);
+ && ::protozero::internal::gen_helpers::EqualsField(deflate_, other.deflate_)
+ && ::protozero::internal::gen_helpers::EqualsField(zstd_, other.zstd_);
}
-bool ChromeLatencyInfo_ComponentInfo::ParseFromArray(const void* raw, size_t size) {
+bool TraceConfig_CompressionConfig::ParseFromArray(const void* raw, size_t size) {
unknown_fields_.clear();
bool packed_error = false;
@@ -34528,11 +34627,11 @@ bool ChromeLatencyInfo_ComponentInfo::ParseFromArray(const void* raw, size_t siz
_has_field_.set(field.id());
}
switch (field.id()) {
- case 1 /* component_type */:
- field.get(&component_type_);
+ case 1 /* deflate */:
+ (*deflate_).ParseFromArray(field.data(), field.size());
break;
- case 2 /* time_us */:
- field.get(&time_us_);
+ case 2 /* zstd */:
+ (*zstd_).ParseFromArray(field.data(), field.size());
break;
default:
field.SerializeAndAppendTo(&unknown_fields_);
@@ -34542,69 +34641,46 @@ bool ChromeLatencyInfo_ComponentInfo::ParseFromArray(const void* raw, size_t siz
return !packed_error && !dec.bytes_left();
}
-std::string ChromeLatencyInfo_ComponentInfo::SerializeAsString() const {
+std::string TraceConfig_CompressionConfig::SerializeAsString() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsString();
}
-std::vector<uint8_t> ChromeLatencyInfo_ComponentInfo::SerializeAsArray() const {
+std::vector<uint8_t> TraceConfig_CompressionConfig::SerializeAsArray() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsArray();
}
-void ChromeLatencyInfo_ComponentInfo::Serialize(::protozero::Message* msg) const {
- // Field 1: component_type
+void TraceConfig_CompressionConfig::Serialize(::protozero::Message* msg) const {
+ // Field 1: deflate
if (_has_field_[1]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(1, component_type_, msg);
+ (*deflate_).Serialize(msg->BeginNestedMessage<::protozero::Message>(1));
}
- // Field 2: time_us
+ // Field 2: zstd
if (_has_field_[2]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(2, time_us_, msg);
+ (*zstd_).Serialize(msg->BeginNestedMessage<::protozero::Message>(2));
}
protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
}
-} // namespace perfetto
-} // namespace protos
-} // namespace gen
-#if defined(__GNUC__) || defined(__clang__)
-#pragma GCC diagnostic pop
-#endif
-// gen_amalgamated begin source: gen/protos/perfetto/trace/track_event/chrome_legacy_ipc.gen.cc
-// gen_amalgamated expanded: #include "perfetto/protozero/gen_field_helpers.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/message.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/packed_repeated_fields.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/proto_decoder.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/scattered_heap_buffer.h"
-// DO NOT EDIT. Autogenerated by Perfetto cppgen_plugin
-#if defined(__GNUC__) || defined(__clang__)
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wfloat-equal"
-#endif
-// gen_amalgamated expanded: #include "protos/perfetto/trace/track_event/chrome_legacy_ipc.gen.h"
-
-namespace perfetto {
-namespace protos {
-namespace gen {
-ChromeLegacyIpc::ChromeLegacyIpc() = default;
-ChromeLegacyIpc::~ChromeLegacyIpc() = default;
-ChromeLegacyIpc::ChromeLegacyIpc(const ChromeLegacyIpc&) = default;
-ChromeLegacyIpc& ChromeLegacyIpc::operator=(const ChromeLegacyIpc&) = default;
-ChromeLegacyIpc::ChromeLegacyIpc(ChromeLegacyIpc&&) noexcept = default;
-ChromeLegacyIpc& ChromeLegacyIpc::operator=(ChromeLegacyIpc&&) = default;
+TraceConfig_CompressionConfig_Zstd::TraceConfig_CompressionConfig_Zstd() = default;
+TraceConfig_CompressionConfig_Zstd::~TraceConfig_CompressionConfig_Zstd() = default;
+TraceConfig_CompressionConfig_Zstd::TraceConfig_CompressionConfig_Zstd(const TraceConfig_CompressionConfig_Zstd&) = default;
+TraceConfig_CompressionConfig_Zstd& TraceConfig_CompressionConfig_Zstd::operator=(const TraceConfig_CompressionConfig_Zstd&) = default;
+TraceConfig_CompressionConfig_Zstd::TraceConfig_CompressionConfig_Zstd(TraceConfig_CompressionConfig_Zstd&&) noexcept = default;
+TraceConfig_CompressionConfig_Zstd& TraceConfig_CompressionConfig_Zstd::operator=(TraceConfig_CompressionConfig_Zstd&&) = default;
-bool ChromeLegacyIpc::operator==(const ChromeLegacyIpc& other) const {
+bool TraceConfig_CompressionConfig_Zstd::operator==(const TraceConfig_CompressionConfig_Zstd& other) const {
return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
- && ::protozero::internal::gen_helpers::EqualsField(message_class_, other.message_class_)
- && ::protozero::internal::gen_helpers::EqualsField(message_line_, other.message_line_);
+ && ::protozero::internal::gen_helpers::EqualsField(level_, other.level_);
}
-bool ChromeLegacyIpc::ParseFromArray(const void* raw, size_t size) {
+bool TraceConfig_CompressionConfig_Zstd::ParseFromArray(const void* raw, size_t size) {
unknown_fields_.clear();
bool packed_error = false;
@@ -34614,11 +34690,8 @@ bool ChromeLegacyIpc::ParseFromArray(const void* raw, size_t size) {
_has_field_.set(field.id());
}
switch (field.id()) {
- case 1 /* message_class */:
- field.get(&message_class_);
- break;
- case 2 /* message_line */:
- field.get(&message_line_);
+ case 1 /* level */:
+ field.get(&level_);
break;
default:
field.SerializeAndAppendTo(&unknown_fields_);
@@ -34628,69 +34701,40 @@ bool ChromeLegacyIpc::ParseFromArray(const void* raw, size_t size) {
return !packed_error && !dec.bytes_left();
}
-std::string ChromeLegacyIpc::SerializeAsString() const {
+std::string TraceConfig_CompressionConfig_Zstd::SerializeAsString() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsString();
}
-std::vector<uint8_t> ChromeLegacyIpc::SerializeAsArray() const {
+std::vector<uint8_t> TraceConfig_CompressionConfig_Zstd::SerializeAsArray() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsArray();
}
-void ChromeLegacyIpc::Serialize(::protozero::Message* msg) const {
- // Field 1: message_class
+void TraceConfig_CompressionConfig_Zstd::Serialize(::protozero::Message* msg) const {
+ // Field 1: level
if (_has_field_[1]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(1, message_class_, msg);
- }
-
- // Field 2: message_line
- if (_has_field_[2]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(2, message_line_, msg);
+ ::protozero::internal::gen_helpers::SerializeVarInt(1, level_, msg);
}
protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
}
-} // namespace perfetto
-} // namespace protos
-} // namespace gen
-#if defined(__GNUC__) || defined(__clang__)
-#pragma GCC diagnostic pop
-#endif
-// gen_amalgamated begin source: gen/protos/perfetto/trace/track_event/chrome_message_pump.gen.cc
-// gen_amalgamated expanded: #include "perfetto/protozero/gen_field_helpers.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/message.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/packed_repeated_fields.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/proto_decoder.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/scattered_heap_buffer.h"
-// DO NOT EDIT. Autogenerated by Perfetto cppgen_plugin
-#if defined(__GNUC__) || defined(__clang__)
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wfloat-equal"
-#endif
-// gen_amalgamated expanded: #include "protos/perfetto/trace/track_event/chrome_message_pump.gen.h"
-
-namespace perfetto {
-namespace protos {
-namespace gen {
-ChromeMessagePump::ChromeMessagePump() = default;
-ChromeMessagePump::~ChromeMessagePump() = default;
-ChromeMessagePump::ChromeMessagePump(const ChromeMessagePump&) = default;
-ChromeMessagePump& ChromeMessagePump::operator=(const ChromeMessagePump&) = default;
-ChromeMessagePump::ChromeMessagePump(ChromeMessagePump&&) noexcept = default;
-ChromeMessagePump& ChromeMessagePump::operator=(ChromeMessagePump&&) = default;
+TraceConfig_CompressionConfig_Deflate::TraceConfig_CompressionConfig_Deflate() = default;
+TraceConfig_CompressionConfig_Deflate::~TraceConfig_CompressionConfig_Deflate() = default;
+TraceConfig_CompressionConfig_Deflate::TraceConfig_CompressionConfig_Deflate(const TraceConfig_CompressionConfig_Deflate&) = default;
+TraceConfig_CompressionConfig_Deflate& TraceConfig_CompressionConfig_Deflate::operator=(const TraceConfig_CompressionConfig_Deflate&) = default;
+TraceConfig_CompressionConfig_Deflate::TraceConfig_CompressionConfig_Deflate(TraceConfig_CompressionConfig_Deflate&&) noexcept = default;
+TraceConfig_CompressionConfig_Deflate& TraceConfig_CompressionConfig_Deflate::operator=(TraceConfig_CompressionConfig_Deflate&&) = default;
-bool ChromeMessagePump::operator==(const ChromeMessagePump& other) const {
- return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
- && ::protozero::internal::gen_helpers::EqualsField(sent_messages_in_queue_, other.sent_messages_in_queue_)
- && ::protozero::internal::gen_helpers::EqualsField(io_handler_location_iid_, other.io_handler_location_iid_);
+bool TraceConfig_CompressionConfig_Deflate::operator==(const TraceConfig_CompressionConfig_Deflate& other) const {
+ return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_);
}
-bool ChromeMessagePump::ParseFromArray(const void* raw, size_t size) {
+bool TraceConfig_CompressionConfig_Deflate::ParseFromArray(const void* raw, size_t size) {
unknown_fields_.clear();
bool packed_error = false;
@@ -34700,12 +34744,6 @@ bool ChromeMessagePump::ParseFromArray(const void* raw, size_t size) {
_has_field_.set(field.id());
}
switch (field.id()) {
- case 1 /* sent_messages_in_queue */:
- field.get(&sent_messages_in_queue_);
- break;
- case 2 /* io_handler_location_iid */:
- field.get(&io_handler_location_iid_);
- break;
default:
field.SerializeAndAppendTo(&unknown_fields_);
break;
@@ -34714,74 +34752,36 @@ bool ChromeMessagePump::ParseFromArray(const void* raw, size_t size) {
return !packed_error && !dec.bytes_left();
}
-std::string ChromeMessagePump::SerializeAsString() const {
+std::string TraceConfig_CompressionConfig_Deflate::SerializeAsString() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsString();
}
-std::vector<uint8_t> ChromeMessagePump::SerializeAsArray() const {
+std::vector<uint8_t> TraceConfig_CompressionConfig_Deflate::SerializeAsArray() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsArray();
}
-void ChromeMessagePump::Serialize(::protozero::Message* msg) const {
- // Field 1: sent_messages_in_queue
- if (_has_field_[1]) {
- ::protozero::internal::gen_helpers::SerializeTinyVarInt(1, sent_messages_in_queue_, msg);
- }
-
- // Field 2: io_handler_location_iid
- if (_has_field_[2]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(2, io_handler_location_iid_, msg);
- }
-
+void TraceConfig_CompressionConfig_Deflate::Serialize(::protozero::Message* msg) const {
protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
}
-} // namespace perfetto
-} // namespace protos
-} // namespace gen
-#if defined(__GNUC__) || defined(__clang__)
-#pragma GCC diagnostic pop
-#endif
-// gen_amalgamated begin source: gen/protos/perfetto/trace/track_event/chrome_mojo_event_info.gen.cc
-// gen_amalgamated expanded: #include "perfetto/protozero/gen_field_helpers.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/message.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/packed_repeated_fields.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/proto_decoder.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/scattered_heap_buffer.h"
-// DO NOT EDIT. Autogenerated by Perfetto cppgen_plugin
-#if defined(__GNUC__) || defined(__clang__)
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wfloat-equal"
-#endif
-// gen_amalgamated expanded: #include "protos/perfetto/trace/track_event/chrome_mojo_event_info.gen.h"
-
-namespace perfetto {
-namespace protos {
-namespace gen {
-ChromeMojoEventInfo::ChromeMojoEventInfo() = default;
-ChromeMojoEventInfo::~ChromeMojoEventInfo() = default;
-ChromeMojoEventInfo::ChromeMojoEventInfo(const ChromeMojoEventInfo&) = default;
-ChromeMojoEventInfo& ChromeMojoEventInfo::operator=(const ChromeMojoEventInfo&) = default;
-ChromeMojoEventInfo::ChromeMojoEventInfo(ChromeMojoEventInfo&&) noexcept = default;
-ChromeMojoEventInfo& ChromeMojoEventInfo::operator=(ChromeMojoEventInfo&&) = default;
+TraceConfig_IncrementalStateConfig::TraceConfig_IncrementalStateConfig() = default;
+TraceConfig_IncrementalStateConfig::~TraceConfig_IncrementalStateConfig() = default;
+TraceConfig_IncrementalStateConfig::TraceConfig_IncrementalStateConfig(const TraceConfig_IncrementalStateConfig&) = default;
+TraceConfig_IncrementalStateConfig& TraceConfig_IncrementalStateConfig::operator=(const TraceConfig_IncrementalStateConfig&) = default;
+TraceConfig_IncrementalStateConfig::TraceConfig_IncrementalStateConfig(TraceConfig_IncrementalStateConfig&&) noexcept = default;
+TraceConfig_IncrementalStateConfig& TraceConfig_IncrementalStateConfig::operator=(TraceConfig_IncrementalStateConfig&&) = default;
-bool ChromeMojoEventInfo::operator==(const ChromeMojoEventInfo& other) const {
+bool TraceConfig_IncrementalStateConfig::operator==(const TraceConfig_IncrementalStateConfig& other) const {
return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
- && ::protozero::internal::gen_helpers::EqualsField(watcher_notify_interface_tag_, other.watcher_notify_interface_tag_)
- && ::protozero::internal::gen_helpers::EqualsField(ipc_hash_, other.ipc_hash_)
- && ::protozero::internal::gen_helpers::EqualsField(mojo_interface_tag_, other.mojo_interface_tag_)
- && ::protozero::internal::gen_helpers::EqualsField(mojo_interface_method_iid_, other.mojo_interface_method_iid_)
- && ::protozero::internal::gen_helpers::EqualsField(is_reply_, other.is_reply_)
- && ::protozero::internal::gen_helpers::EqualsField(payload_size_, other.payload_size_)
- && ::protozero::internal::gen_helpers::EqualsField(data_num_bytes_, other.data_num_bytes_);
+ && ::protozero::internal::gen_helpers::EqualsField(clear_period_ms_, other.clear_period_ms_);
}
-bool ChromeMojoEventInfo::ParseFromArray(const void* raw, size_t size) {
+bool TraceConfig_IncrementalStateConfig::ParseFromArray(const void* raw, size_t size) {
unknown_fields_.clear();
bool packed_error = false;
@@ -34791,26 +34791,8 @@ bool ChromeMojoEventInfo::ParseFromArray(const void* raw, size_t size) {
_has_field_.set(field.id());
}
switch (field.id()) {
- case 1 /* watcher_notify_interface_tag */:
- ::protozero::internal::gen_helpers::DeserializeString(field, &watcher_notify_interface_tag_);
- break;
- case 2 /* ipc_hash */:
- field.get(&ipc_hash_);
- break;
- case 3 /* mojo_interface_tag */:
- ::protozero::internal::gen_helpers::DeserializeString(field, &mojo_interface_tag_);
- break;
- case 4 /* mojo_interface_method_iid */:
- field.get(&mojo_interface_method_iid_);
- break;
- case 5 /* is_reply */:
- field.get(&is_reply_);
- break;
- case 6 /* payload_size */:
- field.get(&payload_size_);
- break;
- case 7 /* data_num_bytes */:
- field.get(&data_num_bytes_);
+ case 1 /* clear_period_ms */:
+ field.get(&clear_period_ms_);
break;
default:
field.SerializeAndAppendTo(&unknown_fields_);
@@ -34820,97 +34802,48 @@ bool ChromeMojoEventInfo::ParseFromArray(const void* raw, size_t size) {
return !packed_error && !dec.bytes_left();
}
-std::string ChromeMojoEventInfo::SerializeAsString() const {
+std::string TraceConfig_IncrementalStateConfig::SerializeAsString() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsString();
}
-std::vector<uint8_t> ChromeMojoEventInfo::SerializeAsArray() const {
+std::vector<uint8_t> TraceConfig_IncrementalStateConfig::SerializeAsArray() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsArray();
}
-void ChromeMojoEventInfo::Serialize(::protozero::Message* msg) const {
- // Field 1: watcher_notify_interface_tag
+void TraceConfig_IncrementalStateConfig::Serialize(::protozero::Message* msg) const {
+ // Field 1: clear_period_ms
if (_has_field_[1]) {
- ::protozero::internal::gen_helpers::SerializeString(1, watcher_notify_interface_tag_, msg);
- }
-
- // Field 2: ipc_hash
- if (_has_field_[2]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(2, ipc_hash_, msg);
+ ::protozero::internal::gen_helpers::SerializeVarInt(1, clear_period_ms_, msg);
}
- // Field 3: mojo_interface_tag
- if (_has_field_[3]) {
- ::protozero::internal::gen_helpers::SerializeString(3, mojo_interface_tag_, msg);
- }
+ protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
+}
- // Field 4: mojo_interface_method_iid
- if (_has_field_[4]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(4, mojo_interface_method_iid_, msg);
- }
- // Field 5: is_reply
- if (_has_field_[5]) {
- ::protozero::internal::gen_helpers::SerializeTinyVarInt(5, is_reply_, msg);
- }
-
- // Field 6: payload_size
- if (_has_field_[6]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(6, payload_size_, msg);
- }
-
- // Field 7: data_num_bytes
- if (_has_field_[7]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(7, data_num_bytes_, msg);
- }
-
- protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
-}
-
-} // namespace perfetto
-} // namespace protos
-} // namespace gen
-#if defined(__GNUC__) || defined(__clang__)
-#pragma GCC diagnostic pop
-#endif
-// gen_amalgamated begin source: gen/protos/perfetto/trace/track_event/chrome_process_descriptor.gen.cc
-// gen_amalgamated expanded: #include "perfetto/protozero/gen_field_helpers.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/message.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/packed_repeated_fields.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/proto_decoder.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/scattered_heap_buffer.h"
-// DO NOT EDIT. Autogenerated by Perfetto cppgen_plugin
-#if defined(__GNUC__) || defined(__clang__)
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wfloat-equal"
-#endif
-// gen_amalgamated expanded: #include "protos/perfetto/trace/track_event/chrome_process_descriptor.gen.h"
-
-namespace perfetto {
-namespace protos {
-namespace gen {
-
-ChromeProcessDescriptor::ChromeProcessDescriptor() = default;
-ChromeProcessDescriptor::~ChromeProcessDescriptor() = default;
-ChromeProcessDescriptor::ChromeProcessDescriptor(const ChromeProcessDescriptor&) = default;
-ChromeProcessDescriptor& ChromeProcessDescriptor::operator=(const ChromeProcessDescriptor&) = default;
-ChromeProcessDescriptor::ChromeProcessDescriptor(ChromeProcessDescriptor&&) noexcept = default;
-ChromeProcessDescriptor& ChromeProcessDescriptor::operator=(ChromeProcessDescriptor&&) = default;
+TraceConfig_TriggerConfig::TraceConfig_TriggerConfig() = default;
+TraceConfig_TriggerConfig::~TraceConfig_TriggerConfig() = default;
+TraceConfig_TriggerConfig::TraceConfig_TriggerConfig(const TraceConfig_TriggerConfig&) = default;
+TraceConfig_TriggerConfig& TraceConfig_TriggerConfig::operator=(const TraceConfig_TriggerConfig&) = default;
+TraceConfig_TriggerConfig::TraceConfig_TriggerConfig(TraceConfig_TriggerConfig&&) noexcept = default;
+TraceConfig_TriggerConfig& TraceConfig_TriggerConfig::operator=(TraceConfig_TriggerConfig&&) = default;
-bool ChromeProcessDescriptor::operator==(const ChromeProcessDescriptor& other) const {
+bool TraceConfig_TriggerConfig::operator==(const TraceConfig_TriggerConfig& other) const {
return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
- && ::protozero::internal::gen_helpers::EqualsField(process_type_, other.process_type_)
- && ::protozero::internal::gen_helpers::EqualsField(process_priority_, other.process_priority_)
- && ::protozero::internal::gen_helpers::EqualsField(legacy_sort_index_, other.legacy_sort_index_)
- && ::protozero::internal::gen_helpers::EqualsField(host_app_package_name_, other.host_app_package_name_)
- && ::protozero::internal::gen_helpers::EqualsField(crash_trace_id_, other.crash_trace_id_);
+ && ::protozero::internal::gen_helpers::EqualsField(trigger_mode_, other.trigger_mode_)
+ && ::protozero::internal::gen_helpers::EqualsField(use_clone_snapshot_if_available_, other.use_clone_snapshot_if_available_)
+ && ::protozero::internal::gen_helpers::EqualsField(triggers_, other.triggers_)
+ && ::protozero::internal::gen_helpers::EqualsField(trigger_timeout_ms_, other.trigger_timeout_ms_);
}
-bool ChromeProcessDescriptor::ParseFromArray(const void* raw, size_t size) {
+int TraceConfig_TriggerConfig::triggers_size() const { return static_cast<int>(triggers_.size()); }
+void TraceConfig_TriggerConfig::clear_triggers() { triggers_.clear(); }
+TraceConfig_TriggerConfig_Trigger* TraceConfig_TriggerConfig::add_triggers() { triggers_.emplace_back(); return &triggers_.back(); }
+bool TraceConfig_TriggerConfig::ParseFromArray(const void* raw, size_t size) {
+ triggers_.clear();
unknown_fields_.clear();
bool packed_error = false;
@@ -34920,20 +34853,18 @@ bool ChromeProcessDescriptor::ParseFromArray(const void* raw, size_t size) {
_has_field_.set(field.id());
}
switch (field.id()) {
- case 1 /* process_type */:
- field.get(&process_type_);
- break;
- case 2 /* process_priority */:
- field.get(&process_priority_);
+ case 1 /* trigger_mode */:
+ field.get(&trigger_mode_);
break;
- case 3 /* legacy_sort_index */:
- field.get(&legacy_sort_index_);
+ case 5 /* use_clone_snapshot_if_available */:
+ field.get(&use_clone_snapshot_if_available_);
break;
- case 4 /* host_app_package_name */:
- ::protozero::internal::gen_helpers::DeserializeString(field, &host_app_package_name_);
+ case 2 /* triggers */:
+ triggers_.emplace_back();
+ triggers_.back().ParseFromArray(field.data(), field.size());
break;
- case 5 /* crash_trace_id */:
- field.get(&crash_trace_id_);
+ case 3 /* trigger_timeout_ms */:
+ field.get(&trigger_timeout_ms_);
break;
default:
field.SerializeAndAppendTo(&unknown_fields_);
@@ -34943,85 +34874,60 @@ bool ChromeProcessDescriptor::ParseFromArray(const void* raw, size_t size) {
return !packed_error && !dec.bytes_left();
}
-std::string ChromeProcessDescriptor::SerializeAsString() const {
+std::string TraceConfig_TriggerConfig::SerializeAsString() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsString();
}
-std::vector<uint8_t> ChromeProcessDescriptor::SerializeAsArray() const {
+std::vector<uint8_t> TraceConfig_TriggerConfig::SerializeAsArray() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsArray();
}
-void ChromeProcessDescriptor::Serialize(::protozero::Message* msg) const {
- // Field 1: process_type
+void TraceConfig_TriggerConfig::Serialize(::protozero::Message* msg) const {
+ // Field 1: trigger_mode
if (_has_field_[1]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(1, process_type_, msg);
- }
-
- // Field 2: process_priority
- if (_has_field_[2]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(2, process_priority_, msg);
+ ::protozero::internal::gen_helpers::SerializeVarInt(1, trigger_mode_, msg);
}
- // Field 3: legacy_sort_index
- if (_has_field_[3]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(3, legacy_sort_index_, msg);
+ // Field 5: use_clone_snapshot_if_available
+ if (_has_field_[5]) {
+ ::protozero::internal::gen_helpers::SerializeTinyVarInt(5, use_clone_snapshot_if_available_, msg);
}
- // Field 4: host_app_package_name
- if (_has_field_[4]) {
- ::protozero::internal::gen_helpers::SerializeString(4, host_app_package_name_, msg);
+ // Field 2: triggers
+ for (auto& it : triggers_) {
+ it.Serialize(msg->BeginNestedMessage<::protozero::Message>(2));
}
- // Field 5: crash_trace_id
- if (_has_field_[5]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(5, crash_trace_id_, msg);
+ // Field 3: trigger_timeout_ms
+ if (_has_field_[3]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(3, trigger_timeout_ms_, msg);
}
protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
}
-} // namespace perfetto
-} // namespace protos
-} // namespace gen
-#if defined(__GNUC__) || defined(__clang__)
-#pragma GCC diagnostic pop
-#endif
-// gen_amalgamated begin source: gen/protos/perfetto/trace/track_event/chrome_renderer_scheduler_state.gen.cc
-// gen_amalgamated expanded: #include "perfetto/protozero/gen_field_helpers.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/message.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/packed_repeated_fields.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/proto_decoder.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/scattered_heap_buffer.h"
-// DO NOT EDIT. Autogenerated by Perfetto cppgen_plugin
-#if defined(__GNUC__) || defined(__clang__)
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wfloat-equal"
-#endif
-// gen_amalgamated expanded: #include "protos/perfetto/trace/track_event/chrome_renderer_scheduler_state.gen.h"
-
-namespace perfetto {
-namespace protos {
-namespace gen {
-ChromeRendererSchedulerState::ChromeRendererSchedulerState() = default;
-ChromeRendererSchedulerState::~ChromeRendererSchedulerState() = default;
-ChromeRendererSchedulerState::ChromeRendererSchedulerState(const ChromeRendererSchedulerState&) = default;
-ChromeRendererSchedulerState& ChromeRendererSchedulerState::operator=(const ChromeRendererSchedulerState&) = default;
-ChromeRendererSchedulerState::ChromeRendererSchedulerState(ChromeRendererSchedulerState&&) noexcept = default;
-ChromeRendererSchedulerState& ChromeRendererSchedulerState::operator=(ChromeRendererSchedulerState&&) = default;
+TraceConfig_TriggerConfig_Trigger::TraceConfig_TriggerConfig_Trigger() = default;
+TraceConfig_TriggerConfig_Trigger::~TraceConfig_TriggerConfig_Trigger() = default;
+TraceConfig_TriggerConfig_Trigger::TraceConfig_TriggerConfig_Trigger(const TraceConfig_TriggerConfig_Trigger&) = default;
+TraceConfig_TriggerConfig_Trigger& TraceConfig_TriggerConfig_Trigger::operator=(const TraceConfig_TriggerConfig_Trigger&) = default;
+TraceConfig_TriggerConfig_Trigger::TraceConfig_TriggerConfig_Trigger(TraceConfig_TriggerConfig_Trigger&&) noexcept = default;
+TraceConfig_TriggerConfig_Trigger& TraceConfig_TriggerConfig_Trigger::operator=(TraceConfig_TriggerConfig_Trigger&&) = default;
-bool ChromeRendererSchedulerState::operator==(const ChromeRendererSchedulerState& other) const {
+bool TraceConfig_TriggerConfig_Trigger::operator==(const TraceConfig_TriggerConfig_Trigger& other) const {
return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
- && ::protozero::internal::gen_helpers::EqualsField(rail_mode_, other.rail_mode_)
- && ::protozero::internal::gen_helpers::EqualsField(is_backgrounded_, other.is_backgrounded_)
- && ::protozero::internal::gen_helpers::EqualsField(is_hidden_, other.is_hidden_);
+ && ::protozero::internal::gen_helpers::EqualsField(name_, other.name_)
+ && ::protozero::internal::gen_helpers::EqualsField(producer_name_regex_, other.producer_name_regex_)
+ && ::protozero::internal::gen_helpers::EqualsField(stop_delay_ms_, other.stop_delay_ms_)
+ && ::protozero::internal::gen_helpers::EqualsField(max_per_24_h_, other.max_per_24_h_)
+ && ::protozero::internal::gen_helpers::EqualsField(skip_probability_, other.skip_probability_);
}
-bool ChromeRendererSchedulerState::ParseFromArray(const void* raw, size_t size) {
+bool TraceConfig_TriggerConfig_Trigger::ParseFromArray(const void* raw, size_t size) {
unknown_fields_.clear();
bool packed_error = false;
@@ -35031,14 +34937,20 @@ bool ChromeRendererSchedulerState::ParseFromArray(const void* raw, size_t size)
_has_field_.set(field.id());
}
switch (field.id()) {
- case 1 /* rail_mode */:
- field.get(&rail_mode_);
+ case 1 /* name */:
+ ::protozero::internal::gen_helpers::DeserializeString(field, &name_);
break;
- case 2 /* is_backgrounded */:
- field.get(&is_backgrounded_);
+ case 2 /* producer_name_regex */:
+ ::protozero::internal::gen_helpers::DeserializeString(field, &producer_name_regex_);
break;
- case 3 /* is_hidden */:
- field.get(&is_hidden_);
+ case 3 /* stop_delay_ms */:
+ field.get(&stop_delay_ms_);
+ break;
+ case 4 /* max_per_24_h */:
+ field.get(&max_per_24_h_);
+ break;
+ case 5 /* skip_probability */:
+ field.get(&skip_probability_);
break;
default:
field.SerializeAndAppendTo(&unknown_fields_);
@@ -35048,75 +34960,62 @@ bool ChromeRendererSchedulerState::ParseFromArray(const void* raw, size_t size)
return !packed_error && !dec.bytes_left();
}
-std::string ChromeRendererSchedulerState::SerializeAsString() const {
+std::string TraceConfig_TriggerConfig_Trigger::SerializeAsString() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsString();
}
-std::vector<uint8_t> ChromeRendererSchedulerState::SerializeAsArray() const {
+std::vector<uint8_t> TraceConfig_TriggerConfig_Trigger::SerializeAsArray() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsArray();
}
-void ChromeRendererSchedulerState::Serialize(::protozero::Message* msg) const {
- // Field 1: rail_mode
+void TraceConfig_TriggerConfig_Trigger::Serialize(::protozero::Message* msg) const {
+ // Field 1: name
if (_has_field_[1]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(1, rail_mode_, msg);
+ ::protozero::internal::gen_helpers::SerializeString(1, name_, msg);
}
- // Field 2: is_backgrounded
+ // Field 2: producer_name_regex
if (_has_field_[2]) {
- ::protozero::internal::gen_helpers::SerializeTinyVarInt(2, is_backgrounded_, msg);
+ ::protozero::internal::gen_helpers::SerializeString(2, producer_name_regex_, msg);
}
- // Field 3: is_hidden
+ // Field 3: stop_delay_ms
if (_has_field_[3]) {
- ::protozero::internal::gen_helpers::SerializeTinyVarInt(3, is_hidden_, msg);
+ ::protozero::internal::gen_helpers::SerializeVarInt(3, stop_delay_ms_, msg);
+ }
+
+ // Field 4: max_per_24_h
+ if (_has_field_[4]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(4, max_per_24_h_, msg);
+ }
+
+ // Field 5: skip_probability
+ if (_has_field_[5]) {
+ ::protozero::internal::gen_helpers::SerializeFixed(5, skip_probability_, msg);
}
protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
}
-} // namespace perfetto
-} // namespace protos
-} // namespace gen
-#if defined(__GNUC__) || defined(__clang__)
-#pragma GCC diagnostic pop
-#endif
-// gen_amalgamated begin source: gen/protos/perfetto/trace/track_event/chrome_thread_descriptor.gen.cc
-// gen_amalgamated expanded: #include "perfetto/protozero/gen_field_helpers.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/message.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/packed_repeated_fields.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/proto_decoder.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/scattered_heap_buffer.h"
-// DO NOT EDIT. Autogenerated by Perfetto cppgen_plugin
-#if defined(__GNUC__) || defined(__clang__)
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wfloat-equal"
-#endif
-// gen_amalgamated expanded: #include "protos/perfetto/trace/track_event/chrome_thread_descriptor.gen.h"
-
-namespace perfetto {
-namespace protos {
-namespace gen {
-ChromeThreadDescriptor::ChromeThreadDescriptor() = default;
-ChromeThreadDescriptor::~ChromeThreadDescriptor() = default;
-ChromeThreadDescriptor::ChromeThreadDescriptor(const ChromeThreadDescriptor&) = default;
-ChromeThreadDescriptor& ChromeThreadDescriptor::operator=(const ChromeThreadDescriptor&) = default;
-ChromeThreadDescriptor::ChromeThreadDescriptor(ChromeThreadDescriptor&&) noexcept = default;
-ChromeThreadDescriptor& ChromeThreadDescriptor::operator=(ChromeThreadDescriptor&&) = default;
+TraceConfig_GuardrailOverrides::TraceConfig_GuardrailOverrides() = default;
+TraceConfig_GuardrailOverrides::~TraceConfig_GuardrailOverrides() = default;
+TraceConfig_GuardrailOverrides::TraceConfig_GuardrailOverrides(const TraceConfig_GuardrailOverrides&) = default;
+TraceConfig_GuardrailOverrides& TraceConfig_GuardrailOverrides::operator=(const TraceConfig_GuardrailOverrides&) = default;
+TraceConfig_GuardrailOverrides::TraceConfig_GuardrailOverrides(TraceConfig_GuardrailOverrides&&) noexcept = default;
+TraceConfig_GuardrailOverrides& TraceConfig_GuardrailOverrides::operator=(TraceConfig_GuardrailOverrides&&) = default;
-bool ChromeThreadDescriptor::operator==(const ChromeThreadDescriptor& other) const {
+bool TraceConfig_GuardrailOverrides::operator==(const TraceConfig_GuardrailOverrides& other) const {
return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
- && ::protozero::internal::gen_helpers::EqualsField(thread_type_, other.thread_type_)
- && ::protozero::internal::gen_helpers::EqualsField(legacy_sort_index_, other.legacy_sort_index_)
- && ::protozero::internal::gen_helpers::EqualsField(is_sandboxed_tid_, other.is_sandboxed_tid_);
+ && ::protozero::internal::gen_helpers::EqualsField(max_upload_per_day_bytes_, other.max_upload_per_day_bytes_)
+ && ::protozero::internal::gen_helpers::EqualsField(max_tracing_buffer_size_kb_, other.max_tracing_buffer_size_kb_);
}
-bool ChromeThreadDescriptor::ParseFromArray(const void* raw, size_t size) {
+bool TraceConfig_GuardrailOverrides::ParseFromArray(const void* raw, size_t size) {
unknown_fields_.clear();
bool packed_error = false;
@@ -35126,14 +35025,11 @@ bool ChromeThreadDescriptor::ParseFromArray(const void* raw, size_t size) {
_has_field_.set(field.id());
}
switch (field.id()) {
- case 1 /* thread_type */:
- field.get(&thread_type_);
- break;
- case 2 /* legacy_sort_index */:
- field.get(&legacy_sort_index_);
+ case 1 /* max_upload_per_day_bytes */:
+ field.get(&max_upload_per_day_bytes_);
break;
- case 3 /* is_sandboxed_tid */:
- field.get(&is_sandboxed_tid_);
+ case 2 /* max_tracing_buffer_size_kb */:
+ field.get(&max_tracing_buffer_size_kb_);
break;
default:
field.SerializeAndAppendTo(&unknown_fields_);
@@ -35143,74 +35039,49 @@ bool ChromeThreadDescriptor::ParseFromArray(const void* raw, size_t size) {
return !packed_error && !dec.bytes_left();
}
-std::string ChromeThreadDescriptor::SerializeAsString() const {
+std::string TraceConfig_GuardrailOverrides::SerializeAsString() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsString();
}
-std::vector<uint8_t> ChromeThreadDescriptor::SerializeAsArray() const {
+std::vector<uint8_t> TraceConfig_GuardrailOverrides::SerializeAsArray() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsArray();
}
-void ChromeThreadDescriptor::Serialize(::protozero::Message* msg) const {
- // Field 1: thread_type
+void TraceConfig_GuardrailOverrides::Serialize(::protozero::Message* msg) const {
+ // Field 1: max_upload_per_day_bytes
if (_has_field_[1]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(1, thread_type_, msg);
+ ::protozero::internal::gen_helpers::SerializeVarInt(1, max_upload_per_day_bytes_, msg);
}
- // Field 2: legacy_sort_index
+ // Field 2: max_tracing_buffer_size_kb
if (_has_field_[2]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(2, legacy_sort_index_, msg);
- }
-
- // Field 3: is_sandboxed_tid
- if (_has_field_[3]) {
- ::protozero::internal::gen_helpers::SerializeTinyVarInt(3, is_sandboxed_tid_, msg);
+ ::protozero::internal::gen_helpers::SerializeVarInt(2, max_tracing_buffer_size_kb_, msg);
}
protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
}
-} // namespace perfetto
-} // namespace protos
-} // namespace gen
-#if defined(__GNUC__) || defined(__clang__)
-#pragma GCC diagnostic pop
-#endif
-// gen_amalgamated begin source: gen/protos/perfetto/trace/track_event/chrome_user_event.gen.cc
-// gen_amalgamated expanded: #include "perfetto/protozero/gen_field_helpers.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/message.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/packed_repeated_fields.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/proto_decoder.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/scattered_heap_buffer.h"
-// DO NOT EDIT. Autogenerated by Perfetto cppgen_plugin
-#if defined(__GNUC__) || defined(__clang__)
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wfloat-equal"
-#endif
-// gen_amalgamated expanded: #include "protos/perfetto/trace/track_event/chrome_user_event.gen.h"
-
-namespace perfetto {
-namespace protos {
-namespace gen {
-ChromeUserEvent::ChromeUserEvent() = default;
-ChromeUserEvent::~ChromeUserEvent() = default;
-ChromeUserEvent::ChromeUserEvent(const ChromeUserEvent&) = default;
-ChromeUserEvent& ChromeUserEvent::operator=(const ChromeUserEvent&) = default;
-ChromeUserEvent::ChromeUserEvent(ChromeUserEvent&&) noexcept = default;
-ChromeUserEvent& ChromeUserEvent::operator=(ChromeUserEvent&&) = default;
+TraceConfig_StatsdMetadata::TraceConfig_StatsdMetadata() = default;
+TraceConfig_StatsdMetadata::~TraceConfig_StatsdMetadata() = default;
+TraceConfig_StatsdMetadata::TraceConfig_StatsdMetadata(const TraceConfig_StatsdMetadata&) = default;
+TraceConfig_StatsdMetadata& TraceConfig_StatsdMetadata::operator=(const TraceConfig_StatsdMetadata&) = default;
+TraceConfig_StatsdMetadata::TraceConfig_StatsdMetadata(TraceConfig_StatsdMetadata&&) noexcept = default;
+TraceConfig_StatsdMetadata& TraceConfig_StatsdMetadata::operator=(TraceConfig_StatsdMetadata&&) = default;
-bool ChromeUserEvent::operator==(const ChromeUserEvent& other) const {
+bool TraceConfig_StatsdMetadata::operator==(const TraceConfig_StatsdMetadata& other) const {
return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
- && ::protozero::internal::gen_helpers::EqualsField(action_, other.action_)
- && ::protozero::internal::gen_helpers::EqualsField(action_hash_, other.action_hash_);
+ && ::protozero::internal::gen_helpers::EqualsField(triggering_alert_id_, other.triggering_alert_id_)
+ && ::protozero::internal::gen_helpers::EqualsField(triggering_config_uid_, other.triggering_config_uid_)
+ && ::protozero::internal::gen_helpers::EqualsField(triggering_config_id_, other.triggering_config_id_)
+ && ::protozero::internal::gen_helpers::EqualsField(triggering_subscription_id_, other.triggering_subscription_id_);
}
-bool ChromeUserEvent::ParseFromArray(const void* raw, size_t size) {
+bool TraceConfig_StatsdMetadata::ParseFromArray(const void* raw, size_t size) {
unknown_fields_.clear();
bool packed_error = false;
@@ -35220,11 +35091,17 @@ bool ChromeUserEvent::ParseFromArray(const void* raw, size_t size) {
_has_field_.set(field.id());
}
switch (field.id()) {
- case 1 /* action */:
- ::protozero::internal::gen_helpers::DeserializeString(field, &action_);
+ case 1 /* triggering_alert_id */:
+ field.get(&triggering_alert_id_);
break;
- case 2 /* action_hash */:
- field.get(&action_hash_);
+ case 2 /* triggering_config_uid */:
+ field.get(&triggering_config_uid_);
+ break;
+ case 3 /* triggering_config_id */:
+ field.get(&triggering_config_id_);
+ break;
+ case 4 /* triggering_subscription_id */:
+ field.get(&triggering_subscription_id_);
break;
default:
field.SerializeAndAppendTo(&unknown_fields_);
@@ -35234,70 +35111,58 @@ bool ChromeUserEvent::ParseFromArray(const void* raw, size_t size) {
return !packed_error && !dec.bytes_left();
}
-std::string ChromeUserEvent::SerializeAsString() const {
+std::string TraceConfig_StatsdMetadata::SerializeAsString() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsString();
}
-std::vector<uint8_t> ChromeUserEvent::SerializeAsArray() const {
+std::vector<uint8_t> TraceConfig_StatsdMetadata::SerializeAsArray() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsArray();
}
-void ChromeUserEvent::Serialize(::protozero::Message* msg) const {
- // Field 1: action
+void TraceConfig_StatsdMetadata::Serialize(::protozero::Message* msg) const {
+ // Field 1: triggering_alert_id
if (_has_field_[1]) {
- ::protozero::internal::gen_helpers::SerializeString(1, action_, msg);
+ ::protozero::internal::gen_helpers::SerializeVarInt(1, triggering_alert_id_, msg);
}
- // Field 2: action_hash
+ // Field 2: triggering_config_uid
if (_has_field_[2]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(2, action_hash_, msg);
+ ::protozero::internal::gen_helpers::SerializeVarInt(2, triggering_config_uid_, msg);
+ }
+
+ // Field 3: triggering_config_id
+ if (_has_field_[3]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(3, triggering_config_id_, msg);
+ }
+
+ // Field 4: triggering_subscription_id
+ if (_has_field_[4]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(4, triggering_subscription_id_, msg);
}
protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
}
-} // namespace perfetto
-} // namespace protos
-} // namespace gen
-#if defined(__GNUC__) || defined(__clang__)
-#pragma GCC diagnostic pop
-#endif
-// gen_amalgamated begin source: gen/protos/perfetto/trace/track_event/chrome_window_handle_event_info.gen.cc
-// gen_amalgamated expanded: #include "perfetto/protozero/gen_field_helpers.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/message.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/packed_repeated_fields.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/proto_decoder.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/scattered_heap_buffer.h"
-// DO NOT EDIT. Autogenerated by Perfetto cppgen_plugin
-#if defined(__GNUC__) || defined(__clang__)
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wfloat-equal"
-#endif
-// gen_amalgamated expanded: #include "protos/perfetto/trace/track_event/chrome_window_handle_event_info.gen.h"
-
-namespace perfetto {
-namespace protos {
-namespace gen {
-ChromeWindowHandleEventInfo::ChromeWindowHandleEventInfo() = default;
-ChromeWindowHandleEventInfo::~ChromeWindowHandleEventInfo() = default;
-ChromeWindowHandleEventInfo::ChromeWindowHandleEventInfo(const ChromeWindowHandleEventInfo&) = default;
-ChromeWindowHandleEventInfo& ChromeWindowHandleEventInfo::operator=(const ChromeWindowHandleEventInfo&) = default;
-ChromeWindowHandleEventInfo::ChromeWindowHandleEventInfo(ChromeWindowHandleEventInfo&&) noexcept = default;
-ChromeWindowHandleEventInfo& ChromeWindowHandleEventInfo::operator=(ChromeWindowHandleEventInfo&&) = default;
+TraceConfig_ProducerConfig::TraceConfig_ProducerConfig() = default;
+TraceConfig_ProducerConfig::~TraceConfig_ProducerConfig() = default;
+TraceConfig_ProducerConfig::TraceConfig_ProducerConfig(const TraceConfig_ProducerConfig&) = default;
+TraceConfig_ProducerConfig& TraceConfig_ProducerConfig::operator=(const TraceConfig_ProducerConfig&) = default;
+TraceConfig_ProducerConfig::TraceConfig_ProducerConfig(TraceConfig_ProducerConfig&&) noexcept = default;
+TraceConfig_ProducerConfig& TraceConfig_ProducerConfig::operator=(TraceConfig_ProducerConfig&&) = default;
-bool ChromeWindowHandleEventInfo::operator==(const ChromeWindowHandleEventInfo& other) const {
+bool TraceConfig_ProducerConfig::operator==(const TraceConfig_ProducerConfig& other) const {
return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
- && ::protozero::internal::gen_helpers::EqualsField(dpi_, other.dpi_)
- && ::protozero::internal::gen_helpers::EqualsField(message_id_, other.message_id_)
- && ::protozero::internal::gen_helpers::EqualsField(hwnd_ptr_, other.hwnd_ptr_);
+ && ::protozero::internal::gen_helpers::EqualsField(producer_name_, other.producer_name_)
+ && ::protozero::internal::gen_helpers::EqualsField(shm_size_kb_, other.shm_size_kb_)
+ && ::protozero::internal::gen_helpers::EqualsField(page_size_kb_, other.page_size_kb_);
}
-bool ChromeWindowHandleEventInfo::ParseFromArray(const void* raw, size_t size) {
+bool TraceConfig_ProducerConfig::ParseFromArray(const void* raw, size_t size) {
unknown_fields_.clear();
bool packed_error = false;
@@ -35307,14 +35172,14 @@ bool ChromeWindowHandleEventInfo::ParseFromArray(const void* raw, size_t size) {
_has_field_.set(field.id());
}
switch (field.id()) {
- case 1 /* dpi */:
- field.get(&dpi_);
+ case 1 /* producer_name */:
+ ::protozero::internal::gen_helpers::DeserializeString(field, &producer_name_);
break;
- case 2 /* message_id */:
- field.get(&message_id_);
+ case 2 /* shm_size_kb */:
+ field.get(&shm_size_kb_);
break;
- case 3 /* hwnd_ptr */:
- field.get(&hwnd_ptr_);
+ case 3 /* page_size_kb */:
+ field.get(&page_size_kb_);
break;
default:
field.SerializeAndAppendTo(&unknown_fields_);
@@ -35324,80 +35189,60 @@ bool ChromeWindowHandleEventInfo::ParseFromArray(const void* raw, size_t size) {
return !packed_error && !dec.bytes_left();
}
-std::string ChromeWindowHandleEventInfo::SerializeAsString() const {
+std::string TraceConfig_ProducerConfig::SerializeAsString() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsString();
}
-std::vector<uint8_t> ChromeWindowHandleEventInfo::SerializeAsArray() const {
+std::vector<uint8_t> TraceConfig_ProducerConfig::SerializeAsArray() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsArray();
}
-void ChromeWindowHandleEventInfo::Serialize(::protozero::Message* msg) const {
- // Field 1: dpi
+void TraceConfig_ProducerConfig::Serialize(::protozero::Message* msg) const {
+ // Field 1: producer_name
if (_has_field_[1]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(1, dpi_, msg);
+ ::protozero::internal::gen_helpers::SerializeString(1, producer_name_, msg);
}
- // Field 2: message_id
+ // Field 2: shm_size_kb
if (_has_field_[2]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(2, message_id_, msg);
+ ::protozero::internal::gen_helpers::SerializeVarInt(2, shm_size_kb_, msg);
}
- // Field 3: hwnd_ptr
+ // Field 3: page_size_kb
if (_has_field_[3]) {
- ::protozero::internal::gen_helpers::SerializeFixed(3, hwnd_ptr_, msg);
+ ::protozero::internal::gen_helpers::SerializeVarInt(3, page_size_kb_, msg);
}
protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
}
-} // namespace perfetto
-} // namespace protos
-} // namespace gen
-#if defined(__GNUC__) || defined(__clang__)
-#pragma GCC diagnostic pop
-#endif
-// gen_amalgamated begin source: gen/protos/perfetto/trace/track_event/counter_descriptor.gen.cc
-// gen_amalgamated expanded: #include "perfetto/protozero/gen_field_helpers.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/message.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/packed_repeated_fields.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/proto_decoder.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/scattered_heap_buffer.h"
-// DO NOT EDIT. Autogenerated by Perfetto cppgen_plugin
-#if defined(__GNUC__) || defined(__clang__)
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wfloat-equal"
-#endif
-// gen_amalgamated expanded: #include "protos/perfetto/trace/track_event/counter_descriptor.gen.h"
-
-namespace perfetto {
-namespace protos {
-namespace gen {
-CounterDescriptor::CounterDescriptor() = default;
-CounterDescriptor::~CounterDescriptor() = default;
-CounterDescriptor::CounterDescriptor(const CounterDescriptor&) = default;
-CounterDescriptor& CounterDescriptor::operator=(const CounterDescriptor&) = default;
-CounterDescriptor::CounterDescriptor(CounterDescriptor&&) noexcept = default;
-CounterDescriptor& CounterDescriptor::operator=(CounterDescriptor&&) = default;
+TraceConfig_BuiltinDataSource::TraceConfig_BuiltinDataSource() = default;
+TraceConfig_BuiltinDataSource::~TraceConfig_BuiltinDataSource() = default;
+TraceConfig_BuiltinDataSource::TraceConfig_BuiltinDataSource(const TraceConfig_BuiltinDataSource&) = default;
+TraceConfig_BuiltinDataSource& TraceConfig_BuiltinDataSource::operator=(const TraceConfig_BuiltinDataSource&) = default;
+TraceConfig_BuiltinDataSource::TraceConfig_BuiltinDataSource(TraceConfig_BuiltinDataSource&&) noexcept = default;
+TraceConfig_BuiltinDataSource& TraceConfig_BuiltinDataSource::operator=(TraceConfig_BuiltinDataSource&&) = default;
-bool CounterDescriptor::operator==(const CounterDescriptor& other) const {
+bool TraceConfig_BuiltinDataSource::operator==(const TraceConfig_BuiltinDataSource& other) const {
return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
- && ::protozero::internal::gen_helpers::EqualsField(type_, other.type_)
- && ::protozero::internal::gen_helpers::EqualsField(categories_, other.categories_)
- && ::protozero::internal::gen_helpers::EqualsField(unit_, other.unit_)
- && ::protozero::internal::gen_helpers::EqualsField(unit_name_, other.unit_name_)
- && ::protozero::internal::gen_helpers::EqualsField(unit_multiplier_, other.unit_multiplier_)
- && ::protozero::internal::gen_helpers::EqualsField(is_incremental_, other.is_incremental_)
- && ::protozero::internal::gen_helpers::EqualsField(y_axis_share_key_, other.y_axis_share_key_);
+ && ::protozero::internal::gen_helpers::EqualsField(disable_clock_snapshotting_, other.disable_clock_snapshotting_)
+ && ::protozero::internal::gen_helpers::EqualsField(disable_trace_config_, other.disable_trace_config_)
+ && ::protozero::internal::gen_helpers::EqualsField(disable_system_info_, other.disable_system_info_)
+ && ::protozero::internal::gen_helpers::EqualsField(disable_service_events_, other.disable_service_events_)
+ && ::protozero::internal::gen_helpers::EqualsField(primary_trace_clock_, other.primary_trace_clock_)
+ && ::protozero::internal::gen_helpers::EqualsField(snapshot_interval_ms_, other.snapshot_interval_ms_)
+ && ::protozero::internal::gen_helpers::EqualsField(prefer_suspend_clock_for_snapshot_, other.prefer_suspend_clock_for_snapshot_)
+ && ::protozero::internal::gen_helpers::EqualsField(disable_chunk_usage_histograms_, other.disable_chunk_usage_histograms_)
+ && ::protozero::internal::gen_helpers::EqualsField(disable_extension_descriptors_, other.disable_extension_descriptors_)
+ && ::protozero::internal::gen_helpers::EqualsField(enable_concurrent_session_events_, other.enable_concurrent_session_events_);
}
-bool CounterDescriptor::ParseFromArray(const void* raw, size_t size) {
- categories_.clear();
+bool TraceConfig_BuiltinDataSource::ParseFromArray(const void* raw, size_t size) {
unknown_fields_.clear();
bool packed_error = false;
@@ -35407,27 +35252,35 @@ bool CounterDescriptor::ParseFromArray(const void* raw, size_t size) {
_has_field_.set(field.id());
}
switch (field.id()) {
- case 1 /* type */:
- field.get(&type_);
- break;
- case 2 /* categories */:
- categories_.emplace_back();
- ::protozero::internal::gen_helpers::DeserializeString(field, &categories_.back());
+ case 1 /* disable_clock_snapshotting */:
+ field.get(&disable_clock_snapshotting_);
break;
- case 3 /* unit */:
- field.get(&unit_);
+ case 2 /* disable_trace_config */:
+ field.get(&disable_trace_config_);
break;
- case 6 /* unit_name */:
- ::protozero::internal::gen_helpers::DeserializeString(field, &unit_name_);
+ case 3 /* disable_system_info */:
+ field.get(&disable_system_info_);
break;
- case 4 /* unit_multiplier */:
- field.get(&unit_multiplier_);
+ case 4 /* disable_service_events */:
+ field.get(&disable_service_events_);
break;
- case 5 /* is_incremental */:
- field.get(&is_incremental_);
+ case 5 /* primary_trace_clock */:
+ field.get(&primary_trace_clock_);
break;
- case 7 /* y_axis_share_key */:
- ::protozero::internal::gen_helpers::DeserializeString(field, &y_axis_share_key_);
+ case 6 /* snapshot_interval_ms */:
+ field.get(&snapshot_interval_ms_);
+ break;
+ case 7 /* prefer_suspend_clock_for_snapshot */:
+ field.get(&prefer_suspend_clock_for_snapshot_);
+ break;
+ case 8 /* disable_chunk_usage_histograms */:
+ field.get(&disable_chunk_usage_histograms_);
+ break;
+ case 9 /* disable_extension_descriptors */:
+ field.get(&disable_extension_descriptors_);
+ break;
+ case 10 /* enable_concurrent_session_events */:
+ field.get(&enable_concurrent_session_events_);
break;
default:
field.SerializeAndAppendTo(&unknown_fields_);
@@ -35437,158 +35290,92 @@ bool CounterDescriptor::ParseFromArray(const void* raw, size_t size) {
return !packed_error && !dec.bytes_left();
}
-std::string CounterDescriptor::SerializeAsString() const {
+std::string TraceConfig_BuiltinDataSource::SerializeAsString() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsString();
}
-std::vector<uint8_t> CounterDescriptor::SerializeAsArray() const {
+std::vector<uint8_t> TraceConfig_BuiltinDataSource::SerializeAsArray() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsArray();
}
-void CounterDescriptor::Serialize(::protozero::Message* msg) const {
- // Field 1: type
+void TraceConfig_BuiltinDataSource::Serialize(::protozero::Message* msg) const {
+ // Field 1: disable_clock_snapshotting
if (_has_field_[1]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(1, type_, msg);
+ ::protozero::internal::gen_helpers::SerializeTinyVarInt(1, disable_clock_snapshotting_, msg);
}
- // Field 2: categories
- for (auto& it : categories_) {
- ::protozero::internal::gen_helpers::SerializeString(2, it, msg);
+ // Field 2: disable_trace_config
+ if (_has_field_[2]) {
+ ::protozero::internal::gen_helpers::SerializeTinyVarInt(2, disable_trace_config_, msg);
}
- // Field 3: unit
+ // Field 3: disable_system_info
if (_has_field_[3]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(3, unit_, msg);
- }
-
- // Field 6: unit_name
- if (_has_field_[6]) {
- ::protozero::internal::gen_helpers::SerializeString(6, unit_name_, msg);
+ ::protozero::internal::gen_helpers::SerializeTinyVarInt(3, disable_system_info_, msg);
}
- // Field 4: unit_multiplier
+ // Field 4: disable_service_events
if (_has_field_[4]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(4, unit_multiplier_, msg);
+ ::protozero::internal::gen_helpers::SerializeTinyVarInt(4, disable_service_events_, msg);
}
- // Field 5: is_incremental
+ // Field 5: primary_trace_clock
if (_has_field_[5]) {
- ::protozero::internal::gen_helpers::SerializeTinyVarInt(5, is_incremental_, msg);
+ ::protozero::internal::gen_helpers::SerializeVarInt(5, primary_trace_clock_, msg);
}
- // Field 7: y_axis_share_key
- if (_has_field_[7]) {
- ::protozero::internal::gen_helpers::SerializeString(7, y_axis_share_key_, msg);
+ // Field 6: snapshot_interval_ms
+ if (_has_field_[6]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(6, snapshot_interval_ms_, msg);
}
- protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
-}
-
-} // namespace perfetto
-} // namespace protos
-} // namespace gen
-#if defined(__GNUC__) || defined(__clang__)
-#pragma GCC diagnostic pop
-#endif
-// gen_amalgamated begin source: gen/protos/perfetto/trace/track_event/debug_annotation.gen.cc
-// gen_amalgamated expanded: #include "perfetto/protozero/gen_field_helpers.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/message.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/packed_repeated_fields.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/proto_decoder.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/scattered_heap_buffer.h"
-// DO NOT EDIT. Autogenerated by Perfetto cppgen_plugin
-#if defined(__GNUC__) || defined(__clang__)
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wfloat-equal"
-#endif
-// gen_amalgamated expanded: #include "protos/perfetto/trace/track_event/debug_annotation.gen.h"
-
-namespace perfetto {
-namespace protos {
-namespace gen {
-
-DebugAnnotationValueTypeName::DebugAnnotationValueTypeName() = default;
-DebugAnnotationValueTypeName::~DebugAnnotationValueTypeName() = default;
-DebugAnnotationValueTypeName::DebugAnnotationValueTypeName(const DebugAnnotationValueTypeName&) = default;
-DebugAnnotationValueTypeName& DebugAnnotationValueTypeName::operator=(const DebugAnnotationValueTypeName&) = default;
-DebugAnnotationValueTypeName::DebugAnnotationValueTypeName(DebugAnnotationValueTypeName&&) noexcept = default;
-DebugAnnotationValueTypeName& DebugAnnotationValueTypeName::operator=(DebugAnnotationValueTypeName&&) = default;
-
-bool DebugAnnotationValueTypeName::operator==(const DebugAnnotationValueTypeName& other) const {
- return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
- && ::protozero::internal::gen_helpers::EqualsField(iid_, other.iid_)
- && ::protozero::internal::gen_helpers::EqualsField(name_, other.name_);
-}
-
-bool DebugAnnotationValueTypeName::ParseFromArray(const void* raw, size_t size) {
- unknown_fields_.clear();
- bool packed_error = false;
-
- ::protozero::ProtoDecoder dec(raw, size);
- for (auto field = dec.ReadField(); field.valid(); field = dec.ReadField()) {
- if (field.id() < _has_field_.size()) {
- _has_field_.set(field.id());
- }
- switch (field.id()) {
- case 1 /* iid */:
- field.get(&iid_);
- break;
- case 2 /* name */:
- ::protozero::internal::gen_helpers::DeserializeString(field, &name_);
- break;
- default:
- field.SerializeAndAppendTo(&unknown_fields_);
- break;
- }
+ // Field 7: prefer_suspend_clock_for_snapshot
+ if (_has_field_[7]) {
+ ::protozero::internal::gen_helpers::SerializeTinyVarInt(7, prefer_suspend_clock_for_snapshot_, msg);
}
- return !packed_error && !dec.bytes_left();
-}
-
-std::string DebugAnnotationValueTypeName::SerializeAsString() const {
- ::protozero::internal::gen_helpers::MessageSerializer msg;
- Serialize(msg.get());
- return msg.SerializeAsString();
-}
-std::vector<uint8_t> DebugAnnotationValueTypeName::SerializeAsArray() const {
- ::protozero::internal::gen_helpers::MessageSerializer msg;
- Serialize(msg.get());
- return msg.SerializeAsArray();
-}
+ // Field 8: disable_chunk_usage_histograms
+ if (_has_field_[8]) {
+ ::protozero::internal::gen_helpers::SerializeTinyVarInt(8, disable_chunk_usage_histograms_, msg);
+ }
-void DebugAnnotationValueTypeName::Serialize(::protozero::Message* msg) const {
- // Field 1: iid
- if (_has_field_[1]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(1, iid_, msg);
+ // Field 9: disable_extension_descriptors
+ if (_has_field_[9]) {
+ ::protozero::internal::gen_helpers::SerializeTinyVarInt(9, disable_extension_descriptors_, msg);
}
- // Field 2: name
- if (_has_field_[2]) {
- ::protozero::internal::gen_helpers::SerializeString(2, name_, msg);
+ // Field 10: enable_concurrent_session_events
+ if (_has_field_[10]) {
+ ::protozero::internal::gen_helpers::SerializeTinyVarInt(10, enable_concurrent_session_events_, msg);
}
protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
}
-DebugAnnotationName::DebugAnnotationName() = default;
-DebugAnnotationName::~DebugAnnotationName() = default;
-DebugAnnotationName::DebugAnnotationName(const DebugAnnotationName&) = default;
-DebugAnnotationName& DebugAnnotationName::operator=(const DebugAnnotationName&) = default;
-DebugAnnotationName::DebugAnnotationName(DebugAnnotationName&&) noexcept = default;
-DebugAnnotationName& DebugAnnotationName::operator=(DebugAnnotationName&&) = default;
+TraceConfig_DataSource::TraceConfig_DataSource() = default;
+TraceConfig_DataSource::~TraceConfig_DataSource() = default;
+TraceConfig_DataSource::TraceConfig_DataSource(const TraceConfig_DataSource&) = default;
+TraceConfig_DataSource& TraceConfig_DataSource::operator=(const TraceConfig_DataSource&) = default;
+TraceConfig_DataSource::TraceConfig_DataSource(TraceConfig_DataSource&&) noexcept = default;
+TraceConfig_DataSource& TraceConfig_DataSource::operator=(TraceConfig_DataSource&&) = default;
-bool DebugAnnotationName::operator==(const DebugAnnotationName& other) const {
+bool TraceConfig_DataSource::operator==(const TraceConfig_DataSource& other) const {
return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
- && ::protozero::internal::gen_helpers::EqualsField(iid_, other.iid_)
- && ::protozero::internal::gen_helpers::EqualsField(name_, other.name_);
+ && ::protozero::internal::gen_helpers::EqualsField(config_, other.config_)
+ && ::protozero::internal::gen_helpers::EqualsField(producer_name_filter_, other.producer_name_filter_)
+ && ::protozero::internal::gen_helpers::EqualsField(producer_name_regex_filter_, other.producer_name_regex_filter_)
+ && ::protozero::internal::gen_helpers::EqualsField(machine_name_filter_, other.machine_name_filter_);
}
-bool DebugAnnotationName::ParseFromArray(const void* raw, size_t size) {
+bool TraceConfig_DataSource::ParseFromArray(const void* raw, size_t size) {
+ producer_name_filter_.clear();
+ producer_name_regex_filter_.clear();
+ machine_name_filter_.clear();
unknown_fields_.clear();
bool packed_error = false;
@@ -35598,11 +35385,20 @@ bool DebugAnnotationName::ParseFromArray(const void* raw, size_t size) {
_has_field_.set(field.id());
}
switch (field.id()) {
- case 1 /* iid */:
- field.get(&iid_);
+ case 1 /* config */:
+ (*config_).ParseFromArray(field.data(), field.size());
break;
- case 2 /* name */:
- ::protozero::internal::gen_helpers::DeserializeString(field, &name_);
+ case 2 /* producer_name_filter */:
+ producer_name_filter_.emplace_back();
+ ::protozero::internal::gen_helpers::DeserializeString(field, &producer_name_filter_.back());
+ break;
+ case 3 /* producer_name_regex_filter */:
+ producer_name_regex_filter_.emplace_back();
+ ::protozero::internal::gen_helpers::DeserializeString(field, &producer_name_regex_filter_.back());
+ break;
+ case 4 /* machine_name_filter */:
+ machine_name_filter_.emplace_back();
+ ::protozero::internal::gen_helpers::DeserializeString(field, &machine_name_filter_.back());
break;
default:
field.SerializeAndAppendTo(&unknown_fields_);
@@ -35612,69 +35408,61 @@ bool DebugAnnotationName::ParseFromArray(const void* raw, size_t size) {
return !packed_error && !dec.bytes_left();
}
-std::string DebugAnnotationName::SerializeAsString() const {
+std::string TraceConfig_DataSource::SerializeAsString() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsString();
}
-std::vector<uint8_t> DebugAnnotationName::SerializeAsArray() const {
+std::vector<uint8_t> TraceConfig_DataSource::SerializeAsArray() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsArray();
}
-void DebugAnnotationName::Serialize(::protozero::Message* msg) const {
- // Field 1: iid
+void TraceConfig_DataSource::Serialize(::protozero::Message* msg) const {
+ // Field 1: config
if (_has_field_[1]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(1, iid_, msg);
+ (*config_).Serialize(msg->BeginNestedMessage<::protozero::Message>(1));
}
- // Field 2: name
- if (_has_field_[2]) {
- ::protozero::internal::gen_helpers::SerializeString(2, name_, msg);
+ // Field 2: producer_name_filter
+ for (auto& it : producer_name_filter_) {
+ ::protozero::internal::gen_helpers::SerializeString(2, it, msg);
+ }
+
+ // Field 3: producer_name_regex_filter
+ for (auto& it : producer_name_regex_filter_) {
+ ::protozero::internal::gen_helpers::SerializeString(3, it, msg);
+ }
+
+ // Field 4: machine_name_filter
+ for (auto& it : machine_name_filter_) {
+ ::protozero::internal::gen_helpers::SerializeString(4, it, msg);
}
protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
}
-DebugAnnotation::DebugAnnotation() = default;
-DebugAnnotation::~DebugAnnotation() = default;
-DebugAnnotation::DebugAnnotation(const DebugAnnotation&) = default;
-DebugAnnotation& DebugAnnotation::operator=(const DebugAnnotation&) = default;
-DebugAnnotation::DebugAnnotation(DebugAnnotation&&) noexcept = default;
-DebugAnnotation& DebugAnnotation::operator=(DebugAnnotation&&) = default;
+TraceConfig_BufferConfig::TraceConfig_BufferConfig() = default;
+TraceConfig_BufferConfig::~TraceConfig_BufferConfig() = default;
+TraceConfig_BufferConfig::TraceConfig_BufferConfig(const TraceConfig_BufferConfig&) = default;
+TraceConfig_BufferConfig& TraceConfig_BufferConfig::operator=(const TraceConfig_BufferConfig&) = default;
+TraceConfig_BufferConfig::TraceConfig_BufferConfig(TraceConfig_BufferConfig&&) noexcept = default;
+TraceConfig_BufferConfig& TraceConfig_BufferConfig::operator=(TraceConfig_BufferConfig&&) = default;
-bool DebugAnnotation::operator==(const DebugAnnotation& other) const {
+bool TraceConfig_BufferConfig::operator==(const TraceConfig_BufferConfig& other) const {
return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
- && ::protozero::internal::gen_helpers::EqualsField(name_iid_, other.name_iid_)
+ && ::protozero::internal::gen_helpers::EqualsField(size_kb_, other.size_kb_)
+ && ::protozero::internal::gen_helpers::EqualsField(fill_policy_, other.fill_policy_)
+ && ::protozero::internal::gen_helpers::EqualsField(transfer_on_clone_, other.transfer_on_clone_)
+ && ::protozero::internal::gen_helpers::EqualsField(clear_before_clone_, other.clear_before_clone_)
&& ::protozero::internal::gen_helpers::EqualsField(name_, other.name_)
- && ::protozero::internal::gen_helpers::EqualsField(bool_value_, other.bool_value_)
- && ::protozero::internal::gen_helpers::EqualsField(uint_value_, other.uint_value_)
- && ::protozero::internal::gen_helpers::EqualsField(int_value_, other.int_value_)
- && ::protozero::internal::gen_helpers::EqualsField(double_value_, other.double_value_)
- && ::protozero::internal::gen_helpers::EqualsField(pointer_value_, other.pointer_value_)
- && ::protozero::internal::gen_helpers::EqualsField(nested_value_, other.nested_value_)
- && ::protozero::internal::gen_helpers::EqualsField(legacy_json_value_, other.legacy_json_value_)
- && ::protozero::internal::gen_helpers::EqualsField(string_value_, other.string_value_)
- && ::protozero::internal::gen_helpers::EqualsField(string_value_iid_, other.string_value_iid_)
- && ::protozero::internal::gen_helpers::EqualsField(proto_type_name_, other.proto_type_name_)
- && ::protozero::internal::gen_helpers::EqualsField(proto_type_name_iid_, other.proto_type_name_iid_)
- && ::protozero::internal::gen_helpers::EqualsField(proto_value_, other.proto_value_)
- && ::protozero::internal::gen_helpers::EqualsField(dict_entries_, other.dict_entries_)
- && ::protozero::internal::gen_helpers::EqualsField(array_values_, other.array_values_);
+ && ::protozero::internal::gen_helpers::EqualsField(experimental_mode_, other.experimental_mode_);
}
-int DebugAnnotation::dict_entries_size() const { return static_cast<int>(dict_entries_.size()); }
-void DebugAnnotation::clear_dict_entries() { dict_entries_.clear(); }
-DebugAnnotation* DebugAnnotation::add_dict_entries() { dict_entries_.emplace_back(); return &dict_entries_.back(); }
-int DebugAnnotation::array_values_size() const { return static_cast<int>(array_values_.size()); }
-void DebugAnnotation::clear_array_values() { array_values_.clear(); }
-DebugAnnotation* DebugAnnotation::add_array_values() { array_values_.emplace_back(); return &array_values_.back(); }
-bool DebugAnnotation::ParseFromArray(const void* raw, size_t size) {
- dict_entries_.clear();
- array_values_.clear();
+bool TraceConfig_BufferConfig::ParseFromArray(const void* raw, size_t size) {
unknown_fields_.clear();
bool packed_error = false;
@@ -35684,55 +35472,23 @@ bool DebugAnnotation::ParseFromArray(const void* raw, size_t size) {
_has_field_.set(field.id());
}
switch (field.id()) {
- case 1 /* name_iid */:
- field.get(&name_iid_);
- break;
- case 10 /* name */:
- ::protozero::internal::gen_helpers::DeserializeString(field, &name_);
- break;
- case 2 /* bool_value */:
- field.get(&bool_value_);
- break;
- case 3 /* uint_value */:
- field.get(&uint_value_);
- break;
- case 4 /* int_value */:
- field.get(&int_value_);
- break;
- case 5 /* double_value */:
- field.get(&double_value_);
- break;
- case 7 /* pointer_value */:
- field.get(&pointer_value_);
- break;
- case 8 /* nested_value */:
- (*nested_value_).ParseFromArray(field.data(), field.size());
- break;
- case 9 /* legacy_json_value */:
- ::protozero::internal::gen_helpers::DeserializeString(field, &legacy_json_value_);
- break;
- case 6 /* string_value */:
- ::protozero::internal::gen_helpers::DeserializeString(field, &string_value_);
- break;
- case 17 /* string_value_iid */:
- field.get(&string_value_iid_);
+ case 1 /* size_kb */:
+ field.get(&size_kb_);
break;
- case 16 /* proto_type_name */:
- ::protozero::internal::gen_helpers::DeserializeString(field, &proto_type_name_);
+ case 4 /* fill_policy */:
+ field.get(&fill_policy_);
break;
- case 13 /* proto_type_name_iid */:
- field.get(&proto_type_name_iid_);
+ case 5 /* transfer_on_clone */:
+ field.get(&transfer_on_clone_);
break;
- case 14 /* proto_value */:
- field.get(&proto_value_);
+ case 6 /* clear_before_clone */:
+ field.get(&clear_before_clone_);
break;
- case 11 /* dict_entries */:
- dict_entries_.emplace_back();
- dict_entries_.back().ParseFromArray(field.data(), field.size());
+ case 7 /* name */:
+ ::protozero::internal::gen_helpers::DeserializeString(field, &name_);
break;
- case 12 /* array_values */:
- array_values_.emplace_back();
- array_values_.back().ParseFromArray(field.data(), field.size());
+ case 8 /* experimental_mode */:
+ field.get(&experimental_mode_);
break;
default:
field.SerializeAndAppendTo(&unknown_fields_);
@@ -35742,227 +35498,47 @@ bool DebugAnnotation::ParseFromArray(const void* raw, size_t size) {
return !packed_error && !dec.bytes_left();
}
-std::string DebugAnnotation::SerializeAsString() const {
+std::string TraceConfig_BufferConfig::SerializeAsString() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsString();
}
-std::vector<uint8_t> DebugAnnotation::SerializeAsArray() const {
+std::vector<uint8_t> TraceConfig_BufferConfig::SerializeAsArray() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsArray();
}
-void DebugAnnotation::Serialize(::protozero::Message* msg) const {
- // Field 1: name_iid
+void TraceConfig_BufferConfig::Serialize(::protozero::Message* msg) const {
+ // Field 1: size_kb
if (_has_field_[1]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(1, name_iid_, msg);
- }
-
- // Field 10: name
- if (_has_field_[10]) {
- ::protozero::internal::gen_helpers::SerializeString(10, name_, msg);
- }
-
- // Field 2: bool_value
- if (_has_field_[2]) {
- ::protozero::internal::gen_helpers::SerializeTinyVarInt(2, bool_value_, msg);
- }
-
- // Field 3: uint_value
- if (_has_field_[3]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(3, uint_value_, msg);
+ ::protozero::internal::gen_helpers::SerializeVarInt(1, size_kb_, msg);
}
- // Field 4: int_value
+ // Field 4: fill_policy
if (_has_field_[4]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(4, int_value_, msg);
+ ::protozero::internal::gen_helpers::SerializeVarInt(4, fill_policy_, msg);
}
- // Field 5: double_value
+ // Field 5: transfer_on_clone
if (_has_field_[5]) {
- ::protozero::internal::gen_helpers::SerializeFixed(5, double_value_, msg);
- }
-
- // Field 7: pointer_value
- if (_has_field_[7]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(7, pointer_value_, msg);
- }
-
- // Field 8: nested_value
- if (_has_field_[8]) {
- (*nested_value_).Serialize(msg->BeginNestedMessage<::protozero::Message>(8));
- }
-
- // Field 9: legacy_json_value
- if (_has_field_[9]) {
- ::protozero::internal::gen_helpers::SerializeString(9, legacy_json_value_, msg);
+ ::protozero::internal::gen_helpers::SerializeTinyVarInt(5, transfer_on_clone_, msg);
}
- // Field 6: string_value
+ // Field 6: clear_before_clone
if (_has_field_[6]) {
- ::protozero::internal::gen_helpers::SerializeString(6, string_value_, msg);
- }
-
- // Field 17: string_value_iid
- if (_has_field_[17]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(17, string_value_iid_, msg);
- }
-
- // Field 16: proto_type_name
- if (_has_field_[16]) {
- ::protozero::internal::gen_helpers::SerializeString(16, proto_type_name_, msg);
- }
-
- // Field 13: proto_type_name_iid
- if (_has_field_[13]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(13, proto_type_name_iid_, msg);
- }
-
- // Field 14: proto_value
- if (_has_field_[14]) {
- ::protozero::internal::gen_helpers::SerializeString(14, proto_value_, msg);
+ ::protozero::internal::gen_helpers::SerializeTinyVarInt(6, clear_before_clone_, msg);
}
- // Field 11: dict_entries
- for (auto& it : dict_entries_) {
- it.Serialize(msg->BeginNestedMessage<::protozero::Message>(11));
+ // Field 7: name
+ if (_has_field_[7]) {
+ ::protozero::internal::gen_helpers::SerializeString(7, name_, msg);
}
- // Field 12: array_values
- for (auto& it : array_values_) {
- it.Serialize(msg->BeginNestedMessage<::protozero::Message>(12));
- }
-
- protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
-}
-
-
-DebugAnnotation_NestedValue::DebugAnnotation_NestedValue() = default;
-DebugAnnotation_NestedValue::~DebugAnnotation_NestedValue() = default;
-DebugAnnotation_NestedValue::DebugAnnotation_NestedValue(const DebugAnnotation_NestedValue&) = default;
-DebugAnnotation_NestedValue& DebugAnnotation_NestedValue::operator=(const DebugAnnotation_NestedValue&) = default;
-DebugAnnotation_NestedValue::DebugAnnotation_NestedValue(DebugAnnotation_NestedValue&&) noexcept = default;
-DebugAnnotation_NestedValue& DebugAnnotation_NestedValue::operator=(DebugAnnotation_NestedValue&&) = default;
-
-bool DebugAnnotation_NestedValue::operator==(const DebugAnnotation_NestedValue& other) const {
- return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
- && ::protozero::internal::gen_helpers::EqualsField(nested_type_, other.nested_type_)
- && ::protozero::internal::gen_helpers::EqualsField(dict_keys_, other.dict_keys_)
- && ::protozero::internal::gen_helpers::EqualsField(dict_values_, other.dict_values_)
- && ::protozero::internal::gen_helpers::EqualsField(array_values_, other.array_values_)
- && ::protozero::internal::gen_helpers::EqualsField(int_value_, other.int_value_)
- && ::protozero::internal::gen_helpers::EqualsField(double_value_, other.double_value_)
- && ::protozero::internal::gen_helpers::EqualsField(bool_value_, other.bool_value_)
- && ::protozero::internal::gen_helpers::EqualsField(string_value_, other.string_value_);
-}
-
-int DebugAnnotation_NestedValue::dict_values_size() const { return static_cast<int>(dict_values_.size()); }
-void DebugAnnotation_NestedValue::clear_dict_values() { dict_values_.clear(); }
-DebugAnnotation_NestedValue* DebugAnnotation_NestedValue::add_dict_values() { dict_values_.emplace_back(); return &dict_values_.back(); }
-int DebugAnnotation_NestedValue::array_values_size() const { return static_cast<int>(array_values_.size()); }
-void DebugAnnotation_NestedValue::clear_array_values() { array_values_.clear(); }
-DebugAnnotation_NestedValue* DebugAnnotation_NestedValue::add_array_values() { array_values_.emplace_back(); return &array_values_.back(); }
-bool DebugAnnotation_NestedValue::ParseFromArray(const void* raw, size_t size) {
- dict_keys_.clear();
- dict_values_.clear();
- array_values_.clear();
- unknown_fields_.clear();
- bool packed_error = false;
-
- ::protozero::ProtoDecoder dec(raw, size);
- for (auto field = dec.ReadField(); field.valid(); field = dec.ReadField()) {
- if (field.id() < _has_field_.size()) {
- _has_field_.set(field.id());
- }
- switch (field.id()) {
- case 1 /* nested_type */:
- field.get(&nested_type_);
- break;
- case 2 /* dict_keys */:
- dict_keys_.emplace_back();
- ::protozero::internal::gen_helpers::DeserializeString(field, &dict_keys_.back());
- break;
- case 3 /* dict_values */:
- dict_values_.emplace_back();
- dict_values_.back().ParseFromArray(field.data(), field.size());
- break;
- case 4 /* array_values */:
- array_values_.emplace_back();
- array_values_.back().ParseFromArray(field.data(), field.size());
- break;
- case 5 /* int_value */:
- field.get(&int_value_);
- break;
- case 6 /* double_value */:
- field.get(&double_value_);
- break;
- case 7 /* bool_value */:
- field.get(&bool_value_);
- break;
- case 8 /* string_value */:
- ::protozero::internal::gen_helpers::DeserializeString(field, &string_value_);
- break;
- default:
- field.SerializeAndAppendTo(&unknown_fields_);
- break;
- }
- }
- return !packed_error && !dec.bytes_left();
-}
-
-std::string DebugAnnotation_NestedValue::SerializeAsString() const {
- ::protozero::internal::gen_helpers::MessageSerializer msg;
- Serialize(msg.get());
- return msg.SerializeAsString();
-}
-
-std::vector<uint8_t> DebugAnnotation_NestedValue::SerializeAsArray() const {
- ::protozero::internal::gen_helpers::MessageSerializer msg;
- Serialize(msg.get());
- return msg.SerializeAsArray();
-}
-
-void DebugAnnotation_NestedValue::Serialize(::protozero::Message* msg) const {
- // Field 1: nested_type
- if (_has_field_[1]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(1, nested_type_, msg);
- }
-
- // Field 2: dict_keys
- for (auto& it : dict_keys_) {
- ::protozero::internal::gen_helpers::SerializeString(2, it, msg);
- }
-
- // Field 3: dict_values
- for (auto& it : dict_values_) {
- it.Serialize(msg->BeginNestedMessage<::protozero::Message>(3));
- }
-
- // Field 4: array_values
- for (auto& it : array_values_) {
- it.Serialize(msg->BeginNestedMessage<::protozero::Message>(4));
- }
-
- // Field 5: int_value
- if (_has_field_[5]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(5, int_value_, msg);
- }
-
- // Field 6: double_value
- if (_has_field_[6]) {
- ::protozero::internal::gen_helpers::SerializeFixed(6, double_value_, msg);
- }
-
- // Field 7: bool_value
- if (_has_field_[7]) {
- ::protozero::internal::gen_helpers::SerializeTinyVarInt(7, bool_value_, msg);
- }
-
- // Field 8: string_value
- if (_has_field_[8]) {
- ::protozero::internal::gen_helpers::SerializeString(8, string_value_, msg);
+ // Field 8: experimental_mode
+ if (_has_field_[8]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(8, experimental_mode_, msg);
}
protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
@@ -35974,7 +35550,163 @@ void DebugAnnotation_NestedValue::Serialize(::protozero::Message* msg) const {
#if defined(__GNUC__) || defined(__clang__)
#pragma GCC diagnostic pop
#endif
-// gen_amalgamated begin source: gen/protos/perfetto/trace/track_event/log_message.gen.cc
+// gen_amalgamated begin source: gen/protos/perfetto/protovm/vm_program.pbzero.cc
+// Intentionally empty (crbug.com/998165)
+// gen_amalgamated begin source: gen/protos/perfetto/common/android_energy_consumer_descriptor.pbzero.cc
+// Intentionally empty (crbug.com/998165)
+// gen_amalgamated begin source: gen/protos/perfetto/common/android_log_constants.pbzero.cc
+// Intentionally empty (crbug.com/998165)
+// gen_amalgamated begin source: gen/protos/perfetto/common/builtin_clock.pbzero.cc
+// Intentionally empty (crbug.com/998165)
+// gen_amalgamated begin source: gen/protos/perfetto/common/commit_data_request.pbzero.cc
+// Intentionally empty (crbug.com/998165)
+// gen_amalgamated begin source: gen/protos/perfetto/common/data_source_descriptor.pbzero.cc
+// Intentionally empty (crbug.com/998165)
+// gen_amalgamated begin source: gen/protos/perfetto/common/descriptor.pbzero.cc
+// Intentionally empty (crbug.com/998165)
+// gen_amalgamated begin source: gen/protos/perfetto/common/ftrace_descriptor.pbzero.cc
+// Intentionally empty (crbug.com/998165)
+// gen_amalgamated begin source: gen/protos/perfetto/common/gpu_counter_descriptor.pbzero.cc
+// Intentionally empty (crbug.com/998165)
+// gen_amalgamated begin source: gen/protos/perfetto/common/interceptor_descriptor.pbzero.cc
+// Intentionally empty (crbug.com/998165)
+// gen_amalgamated begin source: gen/protos/perfetto/common/observable_events.pbzero.cc
+// Intentionally empty (crbug.com/998165)
+// gen_amalgamated begin source: gen/protos/perfetto/common/perf_events.pbzero.cc
+// Intentionally empty (crbug.com/998165)
+// gen_amalgamated begin source: gen/protos/perfetto/common/sys_stats_counters.pbzero.cc
+// Intentionally empty (crbug.com/998165)
+// gen_amalgamated begin source: gen/protos/perfetto/common/system_info.pbzero.cc
+// Intentionally empty (crbug.com/998165)
+// gen_amalgamated begin source: gen/protos/perfetto/common/trace_attributes.pbzero.cc
+// Intentionally empty (crbug.com/998165)
+// gen_amalgamated begin source: gen/protos/perfetto/common/trace_stats.pbzero.cc
+// Intentionally empty (crbug.com/998165)
+// gen_amalgamated begin source: gen/protos/perfetto/common/tracing_service_capabilities.pbzero.cc
+// Intentionally empty (crbug.com/998165)
+// gen_amalgamated begin source: gen/protos/perfetto/common/tracing_service_state.pbzero.cc
+// Intentionally empty (crbug.com/998165)
+// gen_amalgamated begin source: gen/protos/perfetto/common/track_event_descriptor.pbzero.cc
+// Intentionally empty (crbug.com/998165)
+// gen_amalgamated begin source: gen/protos/perfetto/trace/android/android_aflags.pbzero.cc
+// Intentionally empty (crbug.com/998165)
+// gen_amalgamated begin source: gen/protos/perfetto/trace/android/android_game_intervention_list.pbzero.cc
+// Intentionally empty (crbug.com/998165)
+// gen_amalgamated begin source: gen/protos/perfetto/trace/android/android_log.pbzero.cc
+// Intentionally empty (crbug.com/998165)
+// gen_amalgamated begin source: gen/protos/perfetto/trace/android/android_system_property.pbzero.cc
+// Intentionally empty (crbug.com/998165)
+// gen_amalgamated begin source: gen/protos/perfetto/trace/android/cpu_per_uid_data.pbzero.cc
+// Intentionally empty (crbug.com/998165)
+// gen_amalgamated begin source: gen/protos/perfetto/trace/android/graphics_frame_event.pbzero.cc
+// Intentionally empty (crbug.com/998165)
+// gen_amalgamated begin source: gen/protos/perfetto/trace/android/initial_display_state.pbzero.cc
+// Intentionally empty (crbug.com/998165)
+// gen_amalgamated begin source: gen/protos/perfetto/trace/android/kernel_wakelock_data.pbzero.cc
+// Intentionally empty (crbug.com/998165)
+// gen_amalgamated begin source: gen/protos/perfetto/trace/android/packages_list.pbzero.cc
+// Intentionally empty (crbug.com/998165)
+// gen_amalgamated begin source: gen/protos/perfetto/trace/android/pixel_modem_events.pbzero.cc
+// Intentionally empty (crbug.com/998165)
+// gen_amalgamated begin source: gen/protos/perfetto/trace/android/recovered_trace_info.pbzero.cc
+// Intentionally empty (crbug.com/998165)
+// gen_amalgamated begin source: gen/protos/perfetto/trace/android/user_list.pbzero.cc
+// Intentionally empty (crbug.com/998165)
+// gen_amalgamated begin source: gen/protos/perfetto/trace/chrome/chrome_benchmark_metadata.pbzero.cc
+// Intentionally empty (crbug.com/998165)
+// gen_amalgamated begin source: gen/protos/perfetto/trace/chrome/chrome_metadata.pbzero.cc
+// Intentionally empty (crbug.com/998165)
+// gen_amalgamated begin source: gen/protos/perfetto/trace/chrome/chrome_trace_event.pbzero.cc
+// Intentionally empty (crbug.com/998165)
+// gen_amalgamated begin source: gen/protos/perfetto/trace/chrome/chrome_trigger.pbzero.cc
+// Intentionally empty (crbug.com/998165)
+// gen_amalgamated begin source: gen/protos/perfetto/trace/chrome/v8.pbzero.cc
+// Intentionally empty (crbug.com/998165)
+// gen_amalgamated begin source: gen/protos/perfetto/trace/gpu/gpu_counter_event.pbzero.cc
+// Intentionally empty (crbug.com/998165)
+// gen_amalgamated begin source: gen/protos/perfetto/trace/gpu/gpu_log.pbzero.cc
+// Intentionally empty (crbug.com/998165)
+// gen_amalgamated begin source: gen/protos/perfetto/trace/gpu/gpu_mem_event.pbzero.cc
+// Intentionally empty (crbug.com/998165)
+// gen_amalgamated begin source: gen/protos/perfetto/trace/gpu/gpu_render_stage_event.pbzero.cc
+// Intentionally empty (crbug.com/998165)
+// gen_amalgamated begin source: gen/protos/perfetto/trace/gpu/vulkan_api_event.pbzero.cc
+// Intentionally empty (crbug.com/998165)
+// gen_amalgamated begin source: gen/protos/perfetto/trace/gpu/vulkan_memory_event.pbzero.cc
+// Intentionally empty (crbug.com/998165)
+// gen_amalgamated begin source: gen/protos/perfetto/trace/profiling/inline_callstack.pbzero.cc
+// Intentionally empty (crbug.com/998165)
+// gen_amalgamated begin source: gen/protos/perfetto/trace/profiling/art_process_metadata.pbzero.cc
+// Intentionally empty (crbug.com/998165)
+// gen_amalgamated begin source: gen/protos/perfetto/trace/profiling/deobfuscation.pbzero.cc
+// Intentionally empty (crbug.com/998165)
+// gen_amalgamated begin source: gen/protos/perfetto/trace/profiling/profile_common.pbzero.cc
+// Intentionally empty (crbug.com/998165)
+// gen_amalgamated begin source: gen/protos/perfetto/trace/profiling/profile_packet.pbzero.cc
+// Intentionally empty (crbug.com/998165)
+// gen_amalgamated begin source: gen/protos/perfetto/trace/profiling/smaps.pbzero.cc
+// Intentionally empty (crbug.com/998165)
+// gen_amalgamated begin source: gen/protos/perfetto/trace/profiling/stack_sample.pbzero.cc
+// Intentionally empty (crbug.com/998165)
+// gen_amalgamated begin source: gen/protos/perfetto/trace/track_event/chrome_active_processes.pbzero.cc
+// Intentionally empty (crbug.com/998165)
+// gen_amalgamated begin source: gen/protos/perfetto/trace/track_event/chrome_application_state_info.pbzero.cc
+// Intentionally empty (crbug.com/998165)
+// gen_amalgamated begin source: gen/protos/perfetto/trace/track_event/chrome_compositor_scheduler_state.pbzero.cc
+// Intentionally empty (crbug.com/998165)
+// gen_amalgamated begin source: gen/protos/perfetto/trace/track_event/chrome_content_settings_event_info.pbzero.cc
+// Intentionally empty (crbug.com/998165)
+// gen_amalgamated begin source: gen/protos/perfetto/trace/track_event/chrome_frame_reporter.pbzero.cc
+// Intentionally empty (crbug.com/998165)
+// gen_amalgamated begin source: gen/protos/perfetto/trace/track_event/chrome_histogram_sample.pbzero.cc
+// Intentionally empty (crbug.com/998165)
+// gen_amalgamated begin source: gen/protos/perfetto/trace/track_event/chrome_keyed_service.pbzero.cc
+// Intentionally empty (crbug.com/998165)
+// gen_amalgamated begin source: gen/protos/perfetto/trace/track_event/chrome_latency_info.pbzero.cc
+// Intentionally empty (crbug.com/998165)
+// gen_amalgamated begin source: gen/protos/perfetto/trace/track_event/chrome_legacy_ipc.pbzero.cc
+// Intentionally empty (crbug.com/998165)
+// gen_amalgamated begin source: gen/protos/perfetto/trace/track_event/chrome_message_pump.pbzero.cc
+// Intentionally empty (crbug.com/998165)
+// gen_amalgamated begin source: gen/protos/perfetto/trace/track_event/chrome_mojo_event_info.pbzero.cc
+// Intentionally empty (crbug.com/998165)
+// gen_amalgamated begin source: gen/protos/perfetto/trace/track_event/chrome_process_descriptor.pbzero.cc
+// Intentionally empty (crbug.com/998165)
+// gen_amalgamated begin source: gen/protos/perfetto/trace/track_event/chrome_renderer_scheduler_state.pbzero.cc
+// Intentionally empty (crbug.com/998165)
+// gen_amalgamated begin source: gen/protos/perfetto/trace/track_event/chrome_thread_descriptor.pbzero.cc
+// Intentionally empty (crbug.com/998165)
+// gen_amalgamated begin source: gen/protos/perfetto/trace/track_event/chrome_user_event.pbzero.cc
+// Intentionally empty (crbug.com/998165)
+// gen_amalgamated begin source: gen/protos/perfetto/trace/track_event/chrome_window_handle_event_info.pbzero.cc
+// Intentionally empty (crbug.com/998165)
+// gen_amalgamated begin source: gen/protos/perfetto/trace/track_event/counter_descriptor.pbzero.cc
+// Intentionally empty (crbug.com/998165)
+// gen_amalgamated begin source: gen/protos/perfetto/trace/track_event/debug_annotation.pbzero.cc
+// Intentionally empty (crbug.com/998165)
+// gen_amalgamated begin source: gen/protos/perfetto/trace/track_event/log_message.pbzero.cc
+// Intentionally empty (crbug.com/998165)
+// gen_amalgamated begin source: gen/protos/perfetto/trace/track_event/process_descriptor.pbzero.cc
+// Intentionally empty (crbug.com/998165)
+// gen_amalgamated begin source: gen/protos/perfetto/trace/track_event/range_of_interest.pbzero.cc
+// Intentionally empty (crbug.com/998165)
+// gen_amalgamated begin source: gen/protos/perfetto/trace/track_event/screenshot.pbzero.cc
+// Intentionally empty (crbug.com/998165)
+// gen_amalgamated begin source: gen/protos/perfetto/trace/track_event/source_location.pbzero.cc
+// Intentionally empty (crbug.com/998165)
+// gen_amalgamated begin source: gen/protos/perfetto/trace/track_event/state_descriptor.pbzero.cc
+// Intentionally empty (crbug.com/998165)
+// gen_amalgamated begin source: gen/protos/perfetto/trace/track_event/task_execution.pbzero.cc
+// Intentionally empty (crbug.com/998165)
+// gen_amalgamated begin source: gen/protos/perfetto/trace/track_event/thread_descriptor.pbzero.cc
+// Intentionally empty (crbug.com/998165)
+// gen_amalgamated begin source: gen/protos/perfetto/trace/track_event/track_descriptor.pbzero.cc
+// Intentionally empty (crbug.com/998165)
+// gen_amalgamated begin source: gen/protos/perfetto/trace/track_event/track_event.pbzero.cc
+// Intentionally empty (crbug.com/998165)
+// gen_amalgamated begin source: gen/protos/perfetto/trace/interned_data/interned_data.pbzero.cc
+// Intentionally empty (crbug.com/998165)
+// gen_amalgamated begin source: gen/protos/perfetto/trace/track_event/chrome_active_processes.gen.cc
// gen_amalgamated expanded: #include "perfetto/protozero/gen_field_helpers.h"
// gen_amalgamated expanded: #include "perfetto/protozero/message.h"
// gen_amalgamated expanded: #include "perfetto/protozero/packed_repeated_fields.h"
@@ -35985,26 +35717,26 @@ void DebugAnnotation_NestedValue::Serialize(::protozero::Message* msg) const {
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wfloat-equal"
#endif
-// gen_amalgamated expanded: #include "protos/perfetto/trace/track_event/log_message.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/trace/track_event/chrome_active_processes.gen.h"
namespace perfetto {
namespace protos {
namespace gen {
-LogMessageBody::LogMessageBody() = default;
-LogMessageBody::~LogMessageBody() = default;
-LogMessageBody::LogMessageBody(const LogMessageBody&) = default;
-LogMessageBody& LogMessageBody::operator=(const LogMessageBody&) = default;
-LogMessageBody::LogMessageBody(LogMessageBody&&) noexcept = default;
-LogMessageBody& LogMessageBody::operator=(LogMessageBody&&) = default;
+ChromeActiveProcesses::ChromeActiveProcesses() = default;
+ChromeActiveProcesses::~ChromeActiveProcesses() = default;
+ChromeActiveProcesses::ChromeActiveProcesses(const ChromeActiveProcesses&) = default;
+ChromeActiveProcesses& ChromeActiveProcesses::operator=(const ChromeActiveProcesses&) = default;
+ChromeActiveProcesses::ChromeActiveProcesses(ChromeActiveProcesses&&) noexcept = default;
+ChromeActiveProcesses& ChromeActiveProcesses::operator=(ChromeActiveProcesses&&) = default;
-bool LogMessageBody::operator==(const LogMessageBody& other) const {
+bool ChromeActiveProcesses::operator==(const ChromeActiveProcesses& other) const {
return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
- && ::protozero::internal::gen_helpers::EqualsField(iid_, other.iid_)
- && ::protozero::internal::gen_helpers::EqualsField(body_, other.body_);
+ && ::protozero::internal::gen_helpers::EqualsField(pid_, other.pid_);
}
-bool LogMessageBody::ParseFromArray(const void* raw, size_t size) {
+bool ChromeActiveProcesses::ParseFromArray(const void* raw, size_t size) {
+ pid_.clear();
unknown_fields_.clear();
bool packed_error = false;
@@ -36014,11 +35746,9 @@ bool LogMessageBody::ParseFromArray(const void* raw, size_t size) {
_has_field_.set(field.id());
}
switch (field.id()) {
- case 1 /* iid */:
- field.get(&iid_);
- break;
- case 2 /* body */:
- ::protozero::internal::gen_helpers::DeserializeString(field, &body_);
+ case 1 /* pid */:
+ pid_.emplace_back();
+ field.get(&pid_.back());
break;
default:
field.SerializeAndAppendTo(&unknown_fields_);
@@ -36028,48 +35758,63 @@ bool LogMessageBody::ParseFromArray(const void* raw, size_t size) {
return !packed_error && !dec.bytes_left();
}
-std::string LogMessageBody::SerializeAsString() const {
+std::string ChromeActiveProcesses::SerializeAsString() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsString();
}
-std::vector<uint8_t> LogMessageBody::SerializeAsArray() const {
+std::vector<uint8_t> ChromeActiveProcesses::SerializeAsArray() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsArray();
}
-void LogMessageBody::Serialize(::protozero::Message* msg) const {
- // Field 1: iid
- if (_has_field_[1]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(1, iid_, msg);
- }
-
- // Field 2: body
- if (_has_field_[2]) {
- ::protozero::internal::gen_helpers::SerializeString(2, body_, msg);
+void ChromeActiveProcesses::Serialize(::protozero::Message* msg) const {
+ // Field 1: pid
+ for (auto& it : pid_) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(1, it, msg);
}
protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
}
+} // namespace perfetto
+} // namespace protos
+} // namespace gen
+#if defined(__GNUC__) || defined(__clang__)
+#pragma GCC diagnostic pop
+#endif
+// gen_amalgamated begin source: gen/protos/perfetto/trace/track_event/chrome_application_state_info.gen.cc
+// gen_amalgamated expanded: #include "perfetto/protozero/gen_field_helpers.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/message.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/packed_repeated_fields.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/proto_decoder.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/scattered_heap_buffer.h"
+// DO NOT EDIT. Autogenerated by Perfetto cppgen_plugin
+#if defined(__GNUC__) || defined(__clang__)
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wfloat-equal"
+#endif
+// gen_amalgamated expanded: #include "protos/perfetto/trace/track_event/chrome_application_state_info.gen.h"
-LogMessage::LogMessage() = default;
-LogMessage::~LogMessage() = default;
-LogMessage::LogMessage(const LogMessage&) = default;
-LogMessage& LogMessage::operator=(const LogMessage&) = default;
-LogMessage::LogMessage(LogMessage&&) noexcept = default;
-LogMessage& LogMessage::operator=(LogMessage&&) = default;
+namespace perfetto {
+namespace protos {
+namespace gen {
-bool LogMessage::operator==(const LogMessage& other) const {
+ChromeApplicationStateInfo::ChromeApplicationStateInfo() = default;
+ChromeApplicationStateInfo::~ChromeApplicationStateInfo() = default;
+ChromeApplicationStateInfo::ChromeApplicationStateInfo(const ChromeApplicationStateInfo&) = default;
+ChromeApplicationStateInfo& ChromeApplicationStateInfo::operator=(const ChromeApplicationStateInfo&) = default;
+ChromeApplicationStateInfo::ChromeApplicationStateInfo(ChromeApplicationStateInfo&&) noexcept = default;
+ChromeApplicationStateInfo& ChromeApplicationStateInfo::operator=(ChromeApplicationStateInfo&&) = default;
+
+bool ChromeApplicationStateInfo::operator==(const ChromeApplicationStateInfo& other) const {
return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
- && ::protozero::internal::gen_helpers::EqualsField(source_location_iid_, other.source_location_iid_)
- && ::protozero::internal::gen_helpers::EqualsField(body_iid_, other.body_iid_)
- && ::protozero::internal::gen_helpers::EqualsField(prio_, other.prio_);
+ && ::protozero::internal::gen_helpers::EqualsField(application_state_, other.application_state_);
}
-bool LogMessage::ParseFromArray(const void* raw, size_t size) {
+bool ChromeApplicationStateInfo::ParseFromArray(const void* raw, size_t size) {
unknown_fields_.clear();
bool packed_error = false;
@@ -36079,14 +35824,8 @@ bool LogMessage::ParseFromArray(const void* raw, size_t size) {
_has_field_.set(field.id());
}
switch (field.id()) {
- case 1 /* source_location_iid */:
- field.get(&source_location_iid_);
- break;
- case 2 /* body_iid */:
- field.get(&body_iid_);
- break;
- case 3 /* prio */:
- field.get(&prio_);
+ case 1 /* application_state */:
+ field.get(&application_state_);
break;
default:
field.SerializeAndAppendTo(&unknown_fields_);
@@ -36096,32 +35835,22 @@ bool LogMessage::ParseFromArray(const void* raw, size_t size) {
return !packed_error && !dec.bytes_left();
}
-std::string LogMessage::SerializeAsString() const {
+std::string ChromeApplicationStateInfo::SerializeAsString() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsString();
}
-std::vector<uint8_t> LogMessage::SerializeAsArray() const {
+std::vector<uint8_t> ChromeApplicationStateInfo::SerializeAsArray() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsArray();
}
-void LogMessage::Serialize(::protozero::Message* msg) const {
- // Field 1: source_location_iid
+void ChromeApplicationStateInfo::Serialize(::protozero::Message* msg) const {
+ // Field 1: application_state
if (_has_field_[1]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(1, source_location_iid_, msg);
- }
-
- // Field 2: body_iid
- if (_has_field_[2]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(2, body_iid_, msg);
- }
-
- // Field 3: prio
- if (_has_field_[3]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(3, prio_, msg);
+ ::protozero::internal::gen_helpers::SerializeVarInt(1, application_state_, msg);
}
protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
@@ -36133,7 +35862,7 @@ void LogMessage::Serialize(::protozero::Message* msg) const {
#if defined(__GNUC__) || defined(__clang__)
#pragma GCC diagnostic pop
#endif
-// gen_amalgamated begin source: gen/protos/perfetto/trace/track_event/process_descriptor.gen.cc
+// gen_amalgamated begin source: gen/protos/perfetto/trace/track_event/chrome_compositor_scheduler_state.gen.cc
// gen_amalgamated expanded: #include "perfetto/protozero/gen_field_helpers.h"
// gen_amalgamated expanded: #include "perfetto/protozero/message.h"
// gen_amalgamated expanded: #include "perfetto/protozero/packed_repeated_fields.h"
@@ -36144,34 +35873,32 @@ void LogMessage::Serialize(::protozero::Message* msg) const {
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wfloat-equal"
#endif
-// gen_amalgamated expanded: #include "protos/perfetto/trace/track_event/process_descriptor.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/trace/track_event/chrome_compositor_scheduler_state.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/trace/track_event/source_location.gen.h"
namespace perfetto {
namespace protos {
namespace gen {
-ProcessDescriptor::ProcessDescriptor() = default;
-ProcessDescriptor::~ProcessDescriptor() = default;
-ProcessDescriptor::ProcessDescriptor(const ProcessDescriptor&) = default;
-ProcessDescriptor& ProcessDescriptor::operator=(const ProcessDescriptor&) = default;
-ProcessDescriptor::ProcessDescriptor(ProcessDescriptor&&) noexcept = default;
-ProcessDescriptor& ProcessDescriptor::operator=(ProcessDescriptor&&) = default;
+CompositorTimingHistory::CompositorTimingHistory() = default;
+CompositorTimingHistory::~CompositorTimingHistory() = default;
+CompositorTimingHistory::CompositorTimingHistory(const CompositorTimingHistory&) = default;
+CompositorTimingHistory& CompositorTimingHistory::operator=(const CompositorTimingHistory&) = default;
+CompositorTimingHistory::CompositorTimingHistory(CompositorTimingHistory&&) noexcept = default;
+CompositorTimingHistory& CompositorTimingHistory::operator=(CompositorTimingHistory&&) = default;
-bool ProcessDescriptor::operator==(const ProcessDescriptor& other) const {
+bool CompositorTimingHistory::operator==(const CompositorTimingHistory& other) const {
return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
- && ::protozero::internal::gen_helpers::EqualsField(pid_, other.pid_)
- && ::protozero::internal::gen_helpers::EqualsField(cmdline_, other.cmdline_)
- && ::protozero::internal::gen_helpers::EqualsField(process_name_, other.process_name_)
- && ::protozero::internal::gen_helpers::EqualsField(process_priority_, other.process_priority_)
- && ::protozero::internal::gen_helpers::EqualsField(start_timestamp_ns_, other.start_timestamp_ns_)
- && ::protozero::internal::gen_helpers::EqualsField(chrome_process_type_, other.chrome_process_type_)
- && ::protozero::internal::gen_helpers::EqualsField(legacy_sort_index_, other.legacy_sort_index_)
- && ::protozero::internal::gen_helpers::EqualsField(process_labels_, other.process_labels_);
+ && ::protozero::internal::gen_helpers::EqualsField(begin_main_frame_queue_critical_estimate_delta_us_, other.begin_main_frame_queue_critical_estimate_delta_us_)
+ && ::protozero::internal::gen_helpers::EqualsField(begin_main_frame_queue_not_critical_estimate_delta_us_, other.begin_main_frame_queue_not_critical_estimate_delta_us_)
+ && ::protozero::internal::gen_helpers::EqualsField(begin_main_frame_start_to_ready_to_commit_estimate_delta_us_, other.begin_main_frame_start_to_ready_to_commit_estimate_delta_us_)
+ && ::protozero::internal::gen_helpers::EqualsField(commit_to_ready_to_activate_estimate_delta_us_, other.commit_to_ready_to_activate_estimate_delta_us_)
+ && ::protozero::internal::gen_helpers::EqualsField(prepare_tiles_estimate_delta_us_, other.prepare_tiles_estimate_delta_us_)
+ && ::protozero::internal::gen_helpers::EqualsField(activate_estimate_delta_us_, other.activate_estimate_delta_us_)
+ && ::protozero::internal::gen_helpers::EqualsField(draw_estimate_delta_us_, other.draw_estimate_delta_us_);
}
-bool ProcessDescriptor::ParseFromArray(const void* raw, size_t size) {
- cmdline_.clear();
- process_labels_.clear();
+bool CompositorTimingHistory::ParseFromArray(const void* raw, size_t size) {
unknown_fields_.clear();
bool packed_error = false;
@@ -36181,31 +35908,26 @@ bool ProcessDescriptor::ParseFromArray(const void* raw, size_t size) {
_has_field_.set(field.id());
}
switch (field.id()) {
- case 1 /* pid */:
- field.get(&pid_);
- break;
- case 2 /* cmdline */:
- cmdline_.emplace_back();
- ::protozero::internal::gen_helpers::DeserializeString(field, &cmdline_.back());
+ case 1 /* begin_main_frame_queue_critical_estimate_delta_us */:
+ field.get(&begin_main_frame_queue_critical_estimate_delta_us_);
break;
- case 6 /* process_name */:
- ::protozero::internal::gen_helpers::DeserializeString(field, &process_name_);
+ case 2 /* begin_main_frame_queue_not_critical_estimate_delta_us */:
+ field.get(&begin_main_frame_queue_not_critical_estimate_delta_us_);
break;
- case 5 /* process_priority */:
- field.get(&process_priority_);
+ case 3 /* begin_main_frame_start_to_ready_to_commit_estimate_delta_us */:
+ field.get(&begin_main_frame_start_to_ready_to_commit_estimate_delta_us_);
break;
- case 7 /* start_timestamp_ns */:
- field.get(&start_timestamp_ns_);
+ case 4 /* commit_to_ready_to_activate_estimate_delta_us */:
+ field.get(&commit_to_ready_to_activate_estimate_delta_us_);
break;
- case 4 /* chrome_process_type */:
- field.get(&chrome_process_type_);
+ case 5 /* prepare_tiles_estimate_delta_us */:
+ field.get(&prepare_tiles_estimate_delta_us_);
break;
- case 3 /* legacy_sort_index */:
- field.get(&legacy_sort_index_);
+ case 6 /* activate_estimate_delta_us */:
+ field.get(&activate_estimate_delta_us_);
break;
- case 8 /* process_labels */:
- process_labels_.emplace_back();
- ::protozero::internal::gen_helpers::DeserializeString(field, &process_labels_.back());
+ case 7 /* draw_estimate_delta_us */:
+ field.get(&draw_estimate_delta_us_);
break;
default:
field.SerializeAndAppendTo(&unknown_fields_);
@@ -36215,98 +35937,74 @@ bool ProcessDescriptor::ParseFromArray(const void* raw, size_t size) {
return !packed_error && !dec.bytes_left();
}
-std::string ProcessDescriptor::SerializeAsString() const {
+std::string CompositorTimingHistory::SerializeAsString() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsString();
}
-std::vector<uint8_t> ProcessDescriptor::SerializeAsArray() const {
+std::vector<uint8_t> CompositorTimingHistory::SerializeAsArray() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsArray();
}
-void ProcessDescriptor::Serialize(::protozero::Message* msg) const {
- // Field 1: pid
+void CompositorTimingHistory::Serialize(::protozero::Message* msg) const {
+ // Field 1: begin_main_frame_queue_critical_estimate_delta_us
if (_has_field_[1]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(1, pid_, msg);
- }
-
- // Field 2: cmdline
- for (auto& it : cmdline_) {
- ::protozero::internal::gen_helpers::SerializeString(2, it, msg);
+ ::protozero::internal::gen_helpers::SerializeVarInt(1, begin_main_frame_queue_critical_estimate_delta_us_, msg);
}
- // Field 6: process_name
- if (_has_field_[6]) {
- ::protozero::internal::gen_helpers::SerializeString(6, process_name_, msg);
+ // Field 2: begin_main_frame_queue_not_critical_estimate_delta_us
+ if (_has_field_[2]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(2, begin_main_frame_queue_not_critical_estimate_delta_us_, msg);
}
- // Field 5: process_priority
- if (_has_field_[5]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(5, process_priority_, msg);
+ // Field 3: begin_main_frame_start_to_ready_to_commit_estimate_delta_us
+ if (_has_field_[3]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(3, begin_main_frame_start_to_ready_to_commit_estimate_delta_us_, msg);
}
- // Field 7: start_timestamp_ns
- if (_has_field_[7]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(7, start_timestamp_ns_, msg);
+ // Field 4: commit_to_ready_to_activate_estimate_delta_us
+ if (_has_field_[4]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(4, commit_to_ready_to_activate_estimate_delta_us_, msg);
}
- // Field 4: chrome_process_type
- if (_has_field_[4]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(4, chrome_process_type_, msg);
+ // Field 5: prepare_tiles_estimate_delta_us
+ if (_has_field_[5]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(5, prepare_tiles_estimate_delta_us_, msg);
}
- // Field 3: legacy_sort_index
- if (_has_field_[3]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(3, legacy_sort_index_, msg);
+ // Field 6: activate_estimate_delta_us
+ if (_has_field_[6]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(6, activate_estimate_delta_us_, msg);
}
- // Field 8: process_labels
- for (auto& it : process_labels_) {
- ::protozero::internal::gen_helpers::SerializeString(8, it, msg);
+ // Field 7: draw_estimate_delta_us
+ if (_has_field_[7]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(7, draw_estimate_delta_us_, msg);
}
protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
}
-} // namespace perfetto
-} // namespace protos
-} // namespace gen
-#if defined(__GNUC__) || defined(__clang__)
-#pragma GCC diagnostic pop
-#endif
-// gen_amalgamated begin source: gen/protos/perfetto/trace/track_event/range_of_interest.gen.cc
-// gen_amalgamated expanded: #include "perfetto/protozero/gen_field_helpers.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/message.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/packed_repeated_fields.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/proto_decoder.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/scattered_heap_buffer.h"
-// DO NOT EDIT. Autogenerated by Perfetto cppgen_plugin
-#if defined(__GNUC__) || defined(__clang__)
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wfloat-equal"
-#endif
-// gen_amalgamated expanded: #include "protos/perfetto/trace/track_event/range_of_interest.gen.h"
-
-namespace perfetto {
-namespace protos {
-namespace gen {
-TrackEventRangeOfInterest::TrackEventRangeOfInterest() = default;
-TrackEventRangeOfInterest::~TrackEventRangeOfInterest() = default;
-TrackEventRangeOfInterest::TrackEventRangeOfInterest(const TrackEventRangeOfInterest&) = default;
-TrackEventRangeOfInterest& TrackEventRangeOfInterest::operator=(const TrackEventRangeOfInterest&) = default;
-TrackEventRangeOfInterest::TrackEventRangeOfInterest(TrackEventRangeOfInterest&&) noexcept = default;
-TrackEventRangeOfInterest& TrackEventRangeOfInterest::operator=(TrackEventRangeOfInterest&&) = default;
+BeginFrameSourceState::BeginFrameSourceState() = default;
+BeginFrameSourceState::~BeginFrameSourceState() = default;
+BeginFrameSourceState::BeginFrameSourceState(const BeginFrameSourceState&) = default;
+BeginFrameSourceState& BeginFrameSourceState::operator=(const BeginFrameSourceState&) = default;
+BeginFrameSourceState::BeginFrameSourceState(BeginFrameSourceState&&) noexcept = default;
+BeginFrameSourceState& BeginFrameSourceState::operator=(BeginFrameSourceState&&) = default;
-bool TrackEventRangeOfInterest::operator==(const TrackEventRangeOfInterest& other) const {
+bool BeginFrameSourceState::operator==(const BeginFrameSourceState& other) const {
return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
- && ::protozero::internal::gen_helpers::EqualsField(start_us_, other.start_us_);
+ && ::protozero::internal::gen_helpers::EqualsField(source_id_, other.source_id_)
+ && ::protozero::internal::gen_helpers::EqualsField(paused_, other.paused_)
+ && ::protozero::internal::gen_helpers::EqualsField(num_observers_, other.num_observers_)
+ && ::protozero::internal::gen_helpers::EqualsField(last_begin_frame_args_, other.last_begin_frame_args_);
}
-bool TrackEventRangeOfInterest::ParseFromArray(const void* raw, size_t size) {
+bool BeginFrameSourceState::ParseFromArray(const void* raw, size_t size) {
unknown_fields_.clear();
bool packed_error = false;
@@ -36316,8 +36014,17 @@ bool TrackEventRangeOfInterest::ParseFromArray(const void* raw, size_t size) {
_has_field_.set(field.id());
}
switch (field.id()) {
- case 1 /* start_us */:
- field.get(&start_us_);
+ case 1 /* source_id */:
+ field.get(&source_id_);
+ break;
+ case 2 /* paused */:
+ field.get(&paused_);
+ break;
+ case 3 /* num_observers */:
+ field.get(&num_observers_);
+ break;
+ case 4 /* last_begin_frame_args */:
+ (*last_begin_frame_args_).ParseFromArray(field.data(), field.size());
break;
default:
field.SerializeAndAppendTo(&unknown_fields_);
@@ -36327,65 +36034,66 @@ bool TrackEventRangeOfInterest::ParseFromArray(const void* raw, size_t size) {
return !packed_error && !dec.bytes_left();
}
-std::string TrackEventRangeOfInterest::SerializeAsString() const {
+std::string BeginFrameSourceState::SerializeAsString() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsString();
}
-std::vector<uint8_t> TrackEventRangeOfInterest::SerializeAsArray() const {
+std::vector<uint8_t> BeginFrameSourceState::SerializeAsArray() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsArray();
}
-void TrackEventRangeOfInterest::Serialize(::protozero::Message* msg) const {
- // Field 1: start_us
+void BeginFrameSourceState::Serialize(::protozero::Message* msg) const {
+ // Field 1: source_id
if (_has_field_[1]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(1, start_us_, msg);
+ ::protozero::internal::gen_helpers::SerializeVarInt(1, source_id_, msg);
+ }
+
+ // Field 2: paused
+ if (_has_field_[2]) {
+ ::protozero::internal::gen_helpers::SerializeTinyVarInt(2, paused_, msg);
+ }
+
+ // Field 3: num_observers
+ if (_has_field_[3]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(3, num_observers_, msg);
+ }
+
+ // Field 4: last_begin_frame_args
+ if (_has_field_[4]) {
+ (*last_begin_frame_args_).Serialize(msg->BeginNestedMessage<::protozero::Message>(4));
}
protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
}
-} // namespace perfetto
-} // namespace protos
-} // namespace gen
-#if defined(__GNUC__) || defined(__clang__)
-#pragma GCC diagnostic pop
-#endif
-// gen_amalgamated begin source: gen/protos/perfetto/trace/track_event/screenshot.gen.cc
-// gen_amalgamated expanded: #include "perfetto/protozero/gen_field_helpers.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/message.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/packed_repeated_fields.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/proto_decoder.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/scattered_heap_buffer.h"
-// DO NOT EDIT. Autogenerated by Perfetto cppgen_plugin
-#if defined(__GNUC__) || defined(__clang__)
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wfloat-equal"
-#endif
-// gen_amalgamated expanded: #include "protos/perfetto/trace/track_event/screenshot.gen.h"
-
-namespace perfetto {
-namespace protos {
-namespace gen {
-Screenshot::Screenshot() = default;
-Screenshot::~Screenshot() = default;
-Screenshot::Screenshot(const Screenshot&) = default;
-Screenshot& Screenshot::operator=(const Screenshot&) = default;
-Screenshot::Screenshot(Screenshot&&) noexcept = default;
-Screenshot& Screenshot::operator=(Screenshot&&) = default;
+BeginFrameArgs::BeginFrameArgs() = default;
+BeginFrameArgs::~BeginFrameArgs() = default;
+BeginFrameArgs::BeginFrameArgs(const BeginFrameArgs&) = default;
+BeginFrameArgs& BeginFrameArgs::operator=(const BeginFrameArgs&) = default;
+BeginFrameArgs::BeginFrameArgs(BeginFrameArgs&&) noexcept = default;
+BeginFrameArgs& BeginFrameArgs::operator=(BeginFrameArgs&&) = default;
-bool Screenshot::operator==(const Screenshot& other) const {
+bool BeginFrameArgs::operator==(const BeginFrameArgs& other) const {
return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
- && ::protozero::internal::gen_helpers::EqualsField(jpg_image_, other.jpg_image_)
- && ::protozero::internal::gen_helpers::EqualsField(pam_image_, other.pam_image_)
- && ::protozero::internal::gen_helpers::EqualsField(ppm_image_, other.ppm_image_);
+ && ::protozero::internal::gen_helpers::EqualsField(type_, other.type_)
+ && ::protozero::internal::gen_helpers::EqualsField(source_id_, other.source_id_)
+ && ::protozero::internal::gen_helpers::EqualsField(sequence_number_, other.sequence_number_)
+ && ::protozero::internal::gen_helpers::EqualsField(frame_time_us_, other.frame_time_us_)
+ && ::protozero::internal::gen_helpers::EqualsField(deadline_us_, other.deadline_us_)
+ && ::protozero::internal::gen_helpers::EqualsField(interval_delta_us_, other.interval_delta_us_)
+ && ::protozero::internal::gen_helpers::EqualsField(on_critical_path_, other.on_critical_path_)
+ && ::protozero::internal::gen_helpers::EqualsField(animate_only_, other.animate_only_)
+ && ::protozero::internal::gen_helpers::EqualsField(source_location_iid_, other.source_location_iid_)
+ && ::protozero::internal::gen_helpers::EqualsField(source_location_, other.source_location_)
+ && ::protozero::internal::gen_helpers::EqualsField(frames_throttled_since_last_, other.frames_throttled_since_last_);
}
-bool Screenshot::ParseFromArray(const void* raw, size_t size) {
+bool BeginFrameArgs::ParseFromArray(const void* raw, size_t size) {
unknown_fields_.clear();
bool packed_error = false;
@@ -36395,14 +36103,38 @@ bool Screenshot::ParseFromArray(const void* raw, size_t size) {
_has_field_.set(field.id());
}
switch (field.id()) {
- case 1 /* jpg_image */:
- field.get(&jpg_image_);
+ case 1 /* type */:
+ field.get(&type_);
break;
- case 2 /* pam_image */:
- field.get(&pam_image_);
+ case 2 /* source_id */:
+ field.get(&source_id_);
break;
- case 3 /* ppm_image */:
- field.get(&ppm_image_);
+ case 3 /* sequence_number */:
+ field.get(&sequence_number_);
+ break;
+ case 4 /* frame_time_us */:
+ field.get(&frame_time_us_);
+ break;
+ case 5 /* deadline_us */:
+ field.get(&deadline_us_);
+ break;
+ case 6 /* interval_delta_us */:
+ field.get(&interval_delta_us_);
+ break;
+ case 7 /* on_critical_path */:
+ field.get(&on_critical_path_);
+ break;
+ case 8 /* animate_only */:
+ field.get(&animate_only_);
+ break;
+ case 9 /* source_location_iid */:
+ field.get(&source_location_iid_);
+ break;
+ case 10 /* source_location */:
+ (*source_location_).ParseFromArray(field.data(), field.size());
+ break;
+ case 12 /* frames_throttled_since_last */:
+ field.get(&frames_throttled_since_last_);
break;
default:
field.SerializeAndAppendTo(&unknown_fields_);
@@ -36412,76 +36144,92 @@ bool Screenshot::ParseFromArray(const void* raw, size_t size) {
return !packed_error && !dec.bytes_left();
}
-std::string Screenshot::SerializeAsString() const {
+std::string BeginFrameArgs::SerializeAsString() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsString();
}
-std::vector<uint8_t> Screenshot::SerializeAsArray() const {
+std::vector<uint8_t> BeginFrameArgs::SerializeAsArray() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsArray();
}
-void Screenshot::Serialize(::protozero::Message* msg) const {
- // Field 1: jpg_image
+void BeginFrameArgs::Serialize(::protozero::Message* msg) const {
+ // Field 1: type
if (_has_field_[1]) {
- ::protozero::internal::gen_helpers::SerializeString(1, jpg_image_, msg);
+ ::protozero::internal::gen_helpers::SerializeVarInt(1, type_, msg);
}
- // Field 2: pam_image
+ // Field 2: source_id
if (_has_field_[2]) {
- ::protozero::internal::gen_helpers::SerializeString(2, pam_image_, msg);
+ ::protozero::internal::gen_helpers::SerializeVarInt(2, source_id_, msg);
}
- // Field 3: ppm_image
+ // Field 3: sequence_number
if (_has_field_[3]) {
- ::protozero::internal::gen_helpers::SerializeString(3, ppm_image_, msg);
+ ::protozero::internal::gen_helpers::SerializeVarInt(3, sequence_number_, msg);
+ }
+
+ // Field 4: frame_time_us
+ if (_has_field_[4]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(4, frame_time_us_, msg);
+ }
+
+ // Field 5: deadline_us
+ if (_has_field_[5]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(5, deadline_us_, msg);
+ }
+
+ // Field 6: interval_delta_us
+ if (_has_field_[6]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(6, interval_delta_us_, msg);
+ }
+
+ // Field 7: on_critical_path
+ if (_has_field_[7]) {
+ ::protozero::internal::gen_helpers::SerializeTinyVarInt(7, on_critical_path_, msg);
+ }
+
+ // Field 8: animate_only
+ if (_has_field_[8]) {
+ ::protozero::internal::gen_helpers::SerializeTinyVarInt(8, animate_only_, msg);
+ }
+
+ // Field 9: source_location_iid
+ if (_has_field_[9]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(9, source_location_iid_, msg);
+ }
+
+ // Field 10: source_location
+ if (_has_field_[10]) {
+ (*source_location_).Serialize(msg->BeginNestedMessage<::protozero::Message>(10));
+ }
+
+ // Field 12: frames_throttled_since_last
+ if (_has_field_[12]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(12, frames_throttled_since_last_, msg);
}
protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
}
-} // namespace perfetto
-} // namespace protos
-} // namespace gen
-#if defined(__GNUC__) || defined(__clang__)
-#pragma GCC diagnostic pop
-#endif
-// gen_amalgamated begin source: gen/protos/perfetto/trace/track_event/source_location.gen.cc
-// gen_amalgamated expanded: #include "perfetto/protozero/gen_field_helpers.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/message.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/packed_repeated_fields.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/proto_decoder.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/scattered_heap_buffer.h"
-// DO NOT EDIT. Autogenerated by Perfetto cppgen_plugin
-#if defined(__GNUC__) || defined(__clang__)
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wfloat-equal"
-#endif
-// gen_amalgamated expanded: #include "protos/perfetto/trace/track_event/source_location.gen.h"
-
-namespace perfetto {
-namespace protos {
-namespace gen {
-SourceLocation::SourceLocation() = default;
-SourceLocation::~SourceLocation() = default;
-SourceLocation::SourceLocation(const SourceLocation&) = default;
-SourceLocation& SourceLocation::operator=(const SourceLocation&) = default;
-SourceLocation::SourceLocation(SourceLocation&&) noexcept = default;
-SourceLocation& SourceLocation::operator=(SourceLocation&&) = default;
+BeginFrameObserverState::BeginFrameObserverState() = default;
+BeginFrameObserverState::~BeginFrameObserverState() = default;
+BeginFrameObserverState::BeginFrameObserverState(const BeginFrameObserverState&) = default;
+BeginFrameObserverState& BeginFrameObserverState::operator=(const BeginFrameObserverState&) = default;
+BeginFrameObserverState::BeginFrameObserverState(BeginFrameObserverState&&) noexcept = default;
+BeginFrameObserverState& BeginFrameObserverState::operator=(BeginFrameObserverState&&) = default;
-bool SourceLocation::operator==(const SourceLocation& other) const {
+bool BeginFrameObserverState::operator==(const BeginFrameObserverState& other) const {
return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
- && ::protozero::internal::gen_helpers::EqualsField(iid_, other.iid_)
- && ::protozero::internal::gen_helpers::EqualsField(file_name_, other.file_name_)
- && ::protozero::internal::gen_helpers::EqualsField(function_name_, other.function_name_)
- && ::protozero::internal::gen_helpers::EqualsField(line_number_, other.line_number_);
+ && ::protozero::internal::gen_helpers::EqualsField(dropped_begin_frame_args_, other.dropped_begin_frame_args_)
+ && ::protozero::internal::gen_helpers::EqualsField(last_begin_frame_args_, other.last_begin_frame_args_);
}
-bool SourceLocation::ParseFromArray(const void* raw, size_t size) {
+bool BeginFrameObserverState::ParseFromArray(const void* raw, size_t size) {
unknown_fields_.clear();
bool packed_error = false;
@@ -36491,17 +36239,11 @@ bool SourceLocation::ParseFromArray(const void* raw, size_t size) {
_has_field_.set(field.id());
}
switch (field.id()) {
- case 1 /* iid */:
- field.get(&iid_);
- break;
- case 2 /* file_name */:
- ::protozero::internal::gen_helpers::DeserializeString(field, &file_name_);
- break;
- case 3 /* function_name */:
- ::protozero::internal::gen_helpers::DeserializeString(field, &function_name_);
+ case 1 /* dropped_begin_frame_args */:
+ field.get(&dropped_begin_frame_args_);
break;
- case 4 /* line_number */:
- field.get(&line_number_);
+ case 2 /* last_begin_frame_args */:
+ (*last_begin_frame_args_).ParseFromArray(field.data(), field.size());
break;
default:
field.SerializeAndAppendTo(&unknown_fields_);
@@ -36511,58 +36253,51 @@ bool SourceLocation::ParseFromArray(const void* raw, size_t size) {
return !packed_error && !dec.bytes_left();
}
-std::string SourceLocation::SerializeAsString() const {
+std::string BeginFrameObserverState::SerializeAsString() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsString();
}
-std::vector<uint8_t> SourceLocation::SerializeAsArray() const {
+std::vector<uint8_t> BeginFrameObserverState::SerializeAsArray() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsArray();
}
-void SourceLocation::Serialize(::protozero::Message* msg) const {
- // Field 1: iid
+void BeginFrameObserverState::Serialize(::protozero::Message* msg) const {
+ // Field 1: dropped_begin_frame_args
if (_has_field_[1]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(1, iid_, msg);
+ ::protozero::internal::gen_helpers::SerializeVarInt(1, dropped_begin_frame_args_, msg);
}
- // Field 2: file_name
+ // Field 2: last_begin_frame_args
if (_has_field_[2]) {
- ::protozero::internal::gen_helpers::SerializeString(2, file_name_, msg);
- }
-
- // Field 3: function_name
- if (_has_field_[3]) {
- ::protozero::internal::gen_helpers::SerializeString(3, function_name_, msg);
- }
-
- // Field 4: line_number
- if (_has_field_[4]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(4, line_number_, msg);
+ (*last_begin_frame_args_).Serialize(msg->BeginNestedMessage<::protozero::Message>(2));
}
protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
}
-UnsymbolizedSourceLocation::UnsymbolizedSourceLocation() = default;
-UnsymbolizedSourceLocation::~UnsymbolizedSourceLocation() = default;
-UnsymbolizedSourceLocation::UnsymbolizedSourceLocation(const UnsymbolizedSourceLocation&) = default;
-UnsymbolizedSourceLocation& UnsymbolizedSourceLocation::operator=(const UnsymbolizedSourceLocation&) = default;
-UnsymbolizedSourceLocation::UnsymbolizedSourceLocation(UnsymbolizedSourceLocation&&) noexcept = default;
-UnsymbolizedSourceLocation& UnsymbolizedSourceLocation::operator=(UnsymbolizedSourceLocation&&) = default;
+BeginImplFrameArgs::BeginImplFrameArgs() = default;
+BeginImplFrameArgs::~BeginImplFrameArgs() = default;
+BeginImplFrameArgs::BeginImplFrameArgs(const BeginImplFrameArgs&) = default;
+BeginImplFrameArgs& BeginImplFrameArgs::operator=(const BeginImplFrameArgs&) = default;
+BeginImplFrameArgs::BeginImplFrameArgs(BeginImplFrameArgs&&) noexcept = default;
+BeginImplFrameArgs& BeginImplFrameArgs::operator=(BeginImplFrameArgs&&) = default;
-bool UnsymbolizedSourceLocation::operator==(const UnsymbolizedSourceLocation& other) const {
+bool BeginImplFrameArgs::operator==(const BeginImplFrameArgs& other) const {
return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
- && ::protozero::internal::gen_helpers::EqualsField(iid_, other.iid_)
- && ::protozero::internal::gen_helpers::EqualsField(mapping_id_, other.mapping_id_)
- && ::protozero::internal::gen_helpers::EqualsField(rel_pc_, other.rel_pc_);
+ && ::protozero::internal::gen_helpers::EqualsField(updated_at_us_, other.updated_at_us_)
+ && ::protozero::internal::gen_helpers::EqualsField(finished_at_us_, other.finished_at_us_)
+ && ::protozero::internal::gen_helpers::EqualsField(state_, other.state_)
+ && ::protozero::internal::gen_helpers::EqualsField(current_args_, other.current_args_)
+ && ::protozero::internal::gen_helpers::EqualsField(last_args_, other.last_args_)
+ && ::protozero::internal::gen_helpers::EqualsField(timestamps_in_us_, other.timestamps_in_us_);
}
-bool UnsymbolizedSourceLocation::ParseFromArray(const void* raw, size_t size) {
+bool BeginImplFrameArgs::ParseFromArray(const void* raw, size_t size) {
unknown_fields_.clear();
bool packed_error = false;
@@ -36572,14 +36307,23 @@ bool UnsymbolizedSourceLocation::ParseFromArray(const void* raw, size_t size) {
_has_field_.set(field.id());
}
switch (field.id()) {
- case 1 /* iid */:
- field.get(&iid_);
+ case 1 /* updated_at_us */:
+ field.get(&updated_at_us_);
break;
- case 2 /* mapping_id */:
- field.get(&mapping_id_);
+ case 2 /* finished_at_us */:
+ field.get(&finished_at_us_);
break;
- case 3 /* rel_pc */:
- field.get(&rel_pc_);
+ case 3 /* state */:
+ field.get(&state_);
+ break;
+ case 4 /* current_args */:
+ (*current_args_).ParseFromArray(field.data(), field.size());
+ break;
+ case 5 /* last_args */:
+ (*last_args_).ParseFromArray(field.data(), field.size());
+ break;
+ case 6 /* timestamps_in_us */:
+ (*timestamps_in_us_).ParseFromArray(field.data(), field.size());
break;
default:
field.SerializeAndAppendTo(&unknown_fields_);
@@ -36589,72 +36333,72 @@ bool UnsymbolizedSourceLocation::ParseFromArray(const void* raw, size_t size) {
return !packed_error && !dec.bytes_left();
}
-std::string UnsymbolizedSourceLocation::SerializeAsString() const {
+std::string BeginImplFrameArgs::SerializeAsString() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsString();
}
-std::vector<uint8_t> UnsymbolizedSourceLocation::SerializeAsArray() const {
+std::vector<uint8_t> BeginImplFrameArgs::SerializeAsArray() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsArray();
}
-void UnsymbolizedSourceLocation::Serialize(::protozero::Message* msg) const {
- // Field 1: iid
+void BeginImplFrameArgs::Serialize(::protozero::Message* msg) const {
+ // Field 1: updated_at_us
if (_has_field_[1]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(1, iid_, msg);
+ ::protozero::internal::gen_helpers::SerializeVarInt(1, updated_at_us_, msg);
}
- // Field 2: mapping_id
+ // Field 2: finished_at_us
if (_has_field_[2]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(2, mapping_id_, msg);
+ ::protozero::internal::gen_helpers::SerializeVarInt(2, finished_at_us_, msg);
}
- // Field 3: rel_pc
+ // Field 3: state
if (_has_field_[3]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(3, rel_pc_, msg);
+ ::protozero::internal::gen_helpers::SerializeVarInt(3, state_, msg);
+ }
+
+ // Field 4: current_args
+ if (_has_field_[4]) {
+ (*current_args_).Serialize(msg->BeginNestedMessage<::protozero::Message>(4));
+ }
+
+ // Field 5: last_args
+ if (_has_field_[5]) {
+ (*last_args_).Serialize(msg->BeginNestedMessage<::protozero::Message>(5));
+ }
+
+ // Field 6: timestamps_in_us
+ if (_has_field_[6]) {
+ (*timestamps_in_us_).Serialize(msg->BeginNestedMessage<::protozero::Message>(6));
}
protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
}
-} // namespace perfetto
-} // namespace protos
-} // namespace gen
-#if defined(__GNUC__) || defined(__clang__)
-#pragma GCC diagnostic pop
-#endif
-// gen_amalgamated begin source: gen/protos/perfetto/trace/track_event/state_descriptor.gen.cc
-// gen_amalgamated expanded: #include "perfetto/protozero/gen_field_helpers.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/message.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/packed_repeated_fields.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/proto_decoder.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/scattered_heap_buffer.h"
-// DO NOT EDIT. Autogenerated by Perfetto cppgen_plugin
-#if defined(__GNUC__) || defined(__clang__)
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wfloat-equal"
-#endif
-// gen_amalgamated expanded: #include "protos/perfetto/trace/track_event/state_descriptor.gen.h"
-
-namespace perfetto {
-namespace protos {
-namespace gen {
-StateDescriptor::StateDescriptor() = default;
-StateDescriptor::~StateDescriptor() = default;
-StateDescriptor::StateDescriptor(const StateDescriptor&) = default;
-StateDescriptor& StateDescriptor::operator=(const StateDescriptor&) = default;
-StateDescriptor::StateDescriptor(StateDescriptor&&) noexcept = default;
-StateDescriptor& StateDescriptor::operator=(StateDescriptor&&) = default;
+BeginImplFrameArgs_TimestampsInUs::BeginImplFrameArgs_TimestampsInUs() = default;
+BeginImplFrameArgs_TimestampsInUs::~BeginImplFrameArgs_TimestampsInUs() = default;
+BeginImplFrameArgs_TimestampsInUs::BeginImplFrameArgs_TimestampsInUs(const BeginImplFrameArgs_TimestampsInUs&) = default;
+BeginImplFrameArgs_TimestampsInUs& BeginImplFrameArgs_TimestampsInUs::operator=(const BeginImplFrameArgs_TimestampsInUs&) = default;
+BeginImplFrameArgs_TimestampsInUs::BeginImplFrameArgs_TimestampsInUs(BeginImplFrameArgs_TimestampsInUs&&) noexcept = default;
+BeginImplFrameArgs_TimestampsInUs& BeginImplFrameArgs_TimestampsInUs::operator=(BeginImplFrameArgs_TimestampsInUs&&) = default;
-bool StateDescriptor::operator==(const StateDescriptor& other) const {
- return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_);
+bool BeginImplFrameArgs_TimestampsInUs::operator==(const BeginImplFrameArgs_TimestampsInUs& other) const {
+ return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
+ && ::protozero::internal::gen_helpers::EqualsField(interval_delta_, other.interval_delta_)
+ && ::protozero::internal::gen_helpers::EqualsField(now_to_deadline_delta_, other.now_to_deadline_delta_)
+ && ::protozero::internal::gen_helpers::EqualsField(frame_time_to_now_delta_, other.frame_time_to_now_delta_)
+ && ::protozero::internal::gen_helpers::EqualsField(frame_time_to_deadline_delta_, other.frame_time_to_deadline_delta_)
+ && ::protozero::internal::gen_helpers::EqualsField(now_, other.now_)
+ && ::protozero::internal::gen_helpers::EqualsField(frame_time_, other.frame_time_)
+ && ::protozero::internal::gen_helpers::EqualsField(deadline_, other.deadline_);
}
-bool StateDescriptor::ParseFromArray(const void* raw, size_t size) {
+bool BeginImplFrameArgs_TimestampsInUs::ParseFromArray(const void* raw, size_t size) {
unknown_fields_.clear();
bool packed_error = false;
@@ -36664,6 +36408,27 @@ bool StateDescriptor::ParseFromArray(const void* raw, size_t size) {
_has_field_.set(field.id());
}
switch (field.id()) {
+ case 1 /* interval_delta */:
+ field.get(&interval_delta_);
+ break;
+ case 2 /* now_to_deadline_delta */:
+ field.get(&now_to_deadline_delta_);
+ break;
+ case 3 /* frame_time_to_now_delta */:
+ field.get(&frame_time_to_now_delta_);
+ break;
+ case 4 /* frame_time_to_deadline_delta */:
+ field.get(&frame_time_to_deadline_delta_);
+ break;
+ case 5 /* now */:
+ field.get(&now_);
+ break;
+ case 6 /* frame_time */:
+ field.get(&frame_time_);
+ break;
+ case 7 /* deadline */:
+ field.get(&deadline_);
+ break;
default:
field.SerializeAndAppendTo(&unknown_fields_);
break;
@@ -36672,58 +36437,72 @@ bool StateDescriptor::ParseFromArray(const void* raw, size_t size) {
return !packed_error && !dec.bytes_left();
}
-std::string StateDescriptor::SerializeAsString() const {
+std::string BeginImplFrameArgs_TimestampsInUs::SerializeAsString() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsString();
}
-std::vector<uint8_t> StateDescriptor::SerializeAsArray() const {
+std::vector<uint8_t> BeginImplFrameArgs_TimestampsInUs::SerializeAsArray() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsArray();
}
-void StateDescriptor::Serialize(::protozero::Message* msg) const {
+void BeginImplFrameArgs_TimestampsInUs::Serialize(::protozero::Message* msg) const {
+ // Field 1: interval_delta
+ if (_has_field_[1]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(1, interval_delta_, msg);
+ }
+
+ // Field 2: now_to_deadline_delta
+ if (_has_field_[2]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(2, now_to_deadline_delta_, msg);
+ }
+
+ // Field 3: frame_time_to_now_delta
+ if (_has_field_[3]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(3, frame_time_to_now_delta_, msg);
+ }
+
+ // Field 4: frame_time_to_deadline_delta
+ if (_has_field_[4]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(4, frame_time_to_deadline_delta_, msg);
+ }
+
+ // Field 5: now
+ if (_has_field_[5]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(5, now_, msg);
+ }
+
+ // Field 6: frame_time
+ if (_has_field_[6]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(6, frame_time_, msg);
+ }
+
+ // Field 7: deadline
+ if (_has_field_[7]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(7, deadline_, msg);
+ }
+
protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
}
-} // namespace perfetto
-} // namespace protos
-} // namespace gen
-#if defined(__GNUC__) || defined(__clang__)
-#pragma GCC diagnostic pop
-#endif
-// gen_amalgamated begin source: gen/protos/perfetto/trace/track_event/task_execution.gen.cc
-// gen_amalgamated expanded: #include "perfetto/protozero/gen_field_helpers.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/message.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/packed_repeated_fields.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/proto_decoder.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/scattered_heap_buffer.h"
-// DO NOT EDIT. Autogenerated by Perfetto cppgen_plugin
-#if defined(__GNUC__) || defined(__clang__)
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wfloat-equal"
-#endif
-// gen_amalgamated expanded: #include "protos/perfetto/trace/track_event/task_execution.gen.h"
-
-namespace perfetto {
-namespace protos {
-namespace gen {
-TaskExecution::TaskExecution() = default;
-TaskExecution::~TaskExecution() = default;
-TaskExecution::TaskExecution(const TaskExecution&) = default;
-TaskExecution& TaskExecution::operator=(const TaskExecution&) = default;
-TaskExecution::TaskExecution(TaskExecution&&) noexcept = default;
-TaskExecution& TaskExecution::operator=(TaskExecution&&) = default;
+ChromeCompositorStateMachine::ChromeCompositorStateMachine() = default;
+ChromeCompositorStateMachine::~ChromeCompositorStateMachine() = default;
+ChromeCompositorStateMachine::ChromeCompositorStateMachine(const ChromeCompositorStateMachine&) = default;
+ChromeCompositorStateMachine& ChromeCompositorStateMachine::operator=(const ChromeCompositorStateMachine&) = default;
+ChromeCompositorStateMachine::ChromeCompositorStateMachine(ChromeCompositorStateMachine&&) noexcept = default;
+ChromeCompositorStateMachine& ChromeCompositorStateMachine::operator=(ChromeCompositorStateMachine&&) = default;
-bool TaskExecution::operator==(const TaskExecution& other) const {
+bool ChromeCompositorStateMachine::operator==(const ChromeCompositorStateMachine& other) const {
return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
- && ::protozero::internal::gen_helpers::EqualsField(posted_from_iid_, other.posted_from_iid_);
+ && ::protozero::internal::gen_helpers::EqualsField(major_state_, other.major_state_)
+ && ::protozero::internal::gen_helpers::EqualsField(minor_state_, other.minor_state_);
}
-bool TaskExecution::ParseFromArray(const void* raw, size_t size) {
+bool ChromeCompositorStateMachine::ParseFromArray(const void* raw, size_t size) {
unknown_fields_.clear();
bool packed_error = false;
@@ -36733,8 +36512,11 @@ bool TaskExecution::ParseFromArray(const void* raw, size_t size) {
_has_field_.set(field.id());
}
switch (field.id()) {
- case 1 /* posted_from_iid */:
- field.get(&posted_from_iid_);
+ case 1 /* major_state */:
+ (*major_state_).ParseFromArray(field.data(), field.size());
+ break;
+ case 2 /* minor_state */:
+ (*minor_state_).ParseFromArray(field.data(), field.size());
break;
default:
field.SerializeAndAppendTo(&unknown_fields_);
@@ -36744,70 +36526,90 @@ bool TaskExecution::ParseFromArray(const void* raw, size_t size) {
return !packed_error && !dec.bytes_left();
}
-std::string TaskExecution::SerializeAsString() const {
+std::string ChromeCompositorStateMachine::SerializeAsString() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsString();
}
-std::vector<uint8_t> TaskExecution::SerializeAsArray() const {
+std::vector<uint8_t> ChromeCompositorStateMachine::SerializeAsArray() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsArray();
}
-void TaskExecution::Serialize(::protozero::Message* msg) const {
- // Field 1: posted_from_iid
+void ChromeCompositorStateMachine::Serialize(::protozero::Message* msg) const {
+ // Field 1: major_state
if (_has_field_[1]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(1, posted_from_iid_, msg);
+ (*major_state_).Serialize(msg->BeginNestedMessage<::protozero::Message>(1));
+ }
+
+ // Field 2: minor_state
+ if (_has_field_[2]) {
+ (*minor_state_).Serialize(msg->BeginNestedMessage<::protozero::Message>(2));
}
protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
}
-} // namespace perfetto
-} // namespace protos
-} // namespace gen
-#if defined(__GNUC__) || defined(__clang__)
-#pragma GCC diagnostic pop
-#endif
-// gen_amalgamated begin source: gen/protos/perfetto/trace/track_event/thread_descriptor.gen.cc
-// gen_amalgamated expanded: #include "perfetto/protozero/gen_field_helpers.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/message.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/packed_repeated_fields.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/proto_decoder.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/scattered_heap_buffer.h"
-// DO NOT EDIT. Autogenerated by Perfetto cppgen_plugin
-#if defined(__GNUC__) || defined(__clang__)
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wfloat-equal"
-#endif
-// gen_amalgamated expanded: #include "protos/perfetto/trace/track_event/thread_descriptor.gen.h"
-
-namespace perfetto {
-namespace protos {
-namespace gen {
-ThreadDescriptor::ThreadDescriptor() = default;
-ThreadDescriptor::~ThreadDescriptor() = default;
-ThreadDescriptor::ThreadDescriptor(const ThreadDescriptor&) = default;
-ThreadDescriptor& ThreadDescriptor::operator=(const ThreadDescriptor&) = default;
-ThreadDescriptor::ThreadDescriptor(ThreadDescriptor&&) noexcept = default;
-ThreadDescriptor& ThreadDescriptor::operator=(ThreadDescriptor&&) = default;
+ChromeCompositorStateMachine_MinorState::ChromeCompositorStateMachine_MinorState() = default;
+ChromeCompositorStateMachine_MinorState::~ChromeCompositorStateMachine_MinorState() = default;
+ChromeCompositorStateMachine_MinorState::ChromeCompositorStateMachine_MinorState(const ChromeCompositorStateMachine_MinorState&) = default;
+ChromeCompositorStateMachine_MinorState& ChromeCompositorStateMachine_MinorState::operator=(const ChromeCompositorStateMachine_MinorState&) = default;
+ChromeCompositorStateMachine_MinorState::ChromeCompositorStateMachine_MinorState(ChromeCompositorStateMachine_MinorState&&) noexcept = default;
+ChromeCompositorStateMachine_MinorState& ChromeCompositorStateMachine_MinorState::operator=(ChromeCompositorStateMachine_MinorState&&) = default;
-bool ThreadDescriptor::operator==(const ThreadDescriptor& other) const {
+bool ChromeCompositorStateMachine_MinorState::operator==(const ChromeCompositorStateMachine_MinorState& other) const {
return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
- && ::protozero::internal::gen_helpers::EqualsField(pid_, other.pid_)
- && ::protozero::internal::gen_helpers::EqualsField(tid_, other.tid_)
- && ::protozero::internal::gen_helpers::EqualsField(thread_name_, other.thread_name_)
- && ::protozero::internal::gen_helpers::EqualsField(chrome_thread_type_, other.chrome_thread_type_)
- && ::protozero::internal::gen_helpers::EqualsField(reference_timestamp_us_, other.reference_timestamp_us_)
- && ::protozero::internal::gen_helpers::EqualsField(reference_thread_time_us_, other.reference_thread_time_us_)
- && ::protozero::internal::gen_helpers::EqualsField(reference_thread_instruction_count_, other.reference_thread_instruction_count_)
- && ::protozero::internal::gen_helpers::EqualsField(legacy_sort_index_, other.legacy_sort_index_);
+ && ::protozero::internal::gen_helpers::EqualsField(commit_count_, other.commit_count_)
+ && ::protozero::internal::gen_helpers::EqualsField(current_frame_number_, other.current_frame_number_)
+ && ::protozero::internal::gen_helpers::EqualsField(last_frame_number_submit_performed_, other.last_frame_number_submit_performed_)
+ && ::protozero::internal::gen_helpers::EqualsField(last_frame_number_draw_performed_, other.last_frame_number_draw_performed_)
+ && ::protozero::internal::gen_helpers::EqualsField(last_frame_number_begin_main_frame_sent_, other.last_frame_number_begin_main_frame_sent_)
+ && ::protozero::internal::gen_helpers::EqualsField(did_draw_, other.did_draw_)
+ && ::protozero::internal::gen_helpers::EqualsField(did_send_begin_main_frame_for_current_frame_, other.did_send_begin_main_frame_for_current_frame_)
+ && ::protozero::internal::gen_helpers::EqualsField(did_notify_begin_main_frame_not_expected_until_, other.did_notify_begin_main_frame_not_expected_until_)
+ && ::protozero::internal::gen_helpers::EqualsField(did_notify_begin_main_frame_not_expected_soon_, other.did_notify_begin_main_frame_not_expected_soon_)
+ && ::protozero::internal::gen_helpers::EqualsField(wants_begin_main_frame_not_expected_, other.wants_begin_main_frame_not_expected_)
+ && ::protozero::internal::gen_helpers::EqualsField(did_commit_during_frame_, other.did_commit_during_frame_)
+ && ::protozero::internal::gen_helpers::EqualsField(did_invalidate_layer_tree_frame_sink_, other.did_invalidate_layer_tree_frame_sink_)
+ && ::protozero::internal::gen_helpers::EqualsField(did_perform_impl_side_invalidaion_, other.did_perform_impl_side_invalidaion_)
+ && ::protozero::internal::gen_helpers::EqualsField(did_prepare_tiles_, other.did_prepare_tiles_)
+ && ::protozero::internal::gen_helpers::EqualsField(consecutive_checkerboard_animations_, other.consecutive_checkerboard_animations_)
+ && ::protozero::internal::gen_helpers::EqualsField(pending_submit_frames_, other.pending_submit_frames_)
+ && ::protozero::internal::gen_helpers::EqualsField(submit_frames_with_current_layer_tree_frame_sink_, other.submit_frames_with_current_layer_tree_frame_sink_)
+ && ::protozero::internal::gen_helpers::EqualsField(needs_redraw_, other.needs_redraw_)
+ && ::protozero::internal::gen_helpers::EqualsField(needs_prepare_tiles_, other.needs_prepare_tiles_)
+ && ::protozero::internal::gen_helpers::EqualsField(needs_begin_main_frame_, other.needs_begin_main_frame_)
+ && ::protozero::internal::gen_helpers::EqualsField(needs_one_begin_impl_frame_, other.needs_one_begin_impl_frame_)
+ && ::protozero::internal::gen_helpers::EqualsField(visible_, other.visible_)
+ && ::protozero::internal::gen_helpers::EqualsField(begin_frame_source_paused_, other.begin_frame_source_paused_)
+ && ::protozero::internal::gen_helpers::EqualsField(can_draw_, other.can_draw_)
+ && ::protozero::internal::gen_helpers::EqualsField(resourceless_draw_, other.resourceless_draw_)
+ && ::protozero::internal::gen_helpers::EqualsField(has_pending_tree_, other.has_pending_tree_)
+ && ::protozero::internal::gen_helpers::EqualsField(pending_tree_is_ready_for_activation_, other.pending_tree_is_ready_for_activation_)
+ && ::protozero::internal::gen_helpers::EqualsField(active_tree_needs_first_draw_, other.active_tree_needs_first_draw_)
+ && ::protozero::internal::gen_helpers::EqualsField(active_tree_is_ready_to_draw_, other.active_tree_is_ready_to_draw_)
+ && ::protozero::internal::gen_helpers::EqualsField(did_create_and_initialize_first_layer_tree_frame_sink_, other.did_create_and_initialize_first_layer_tree_frame_sink_)
+ && ::protozero::internal::gen_helpers::EqualsField(tree_priority_, other.tree_priority_)
+ && ::protozero::internal::gen_helpers::EqualsField(scroll_handler_state_, other.scroll_handler_state_)
+ && ::protozero::internal::gen_helpers::EqualsField(critical_begin_main_frame_to_activate_is_fast_, other.critical_begin_main_frame_to_activate_is_fast_)
+ && ::protozero::internal::gen_helpers::EqualsField(main_thread_missed_last_deadline_, other.main_thread_missed_last_deadline_)
+ && ::protozero::internal::gen_helpers::EqualsField(video_needs_begin_frames_, other.video_needs_begin_frames_)
+ && ::protozero::internal::gen_helpers::EqualsField(defer_begin_main_frame_, other.defer_begin_main_frame_)
+ && ::protozero::internal::gen_helpers::EqualsField(last_commit_had_no_updates_, other.last_commit_had_no_updates_)
+ && ::protozero::internal::gen_helpers::EqualsField(did_draw_in_last_frame_, other.did_draw_in_last_frame_)
+ && ::protozero::internal::gen_helpers::EqualsField(did_submit_in_last_frame_, other.did_submit_in_last_frame_)
+ && ::protozero::internal::gen_helpers::EqualsField(needs_impl_side_invalidation_, other.needs_impl_side_invalidation_)
+ && ::protozero::internal::gen_helpers::EqualsField(current_pending_tree_is_impl_side_, other.current_pending_tree_is_impl_side_)
+ && ::protozero::internal::gen_helpers::EqualsField(previous_pending_tree_was_impl_side_, other.previous_pending_tree_was_impl_side_)
+ && ::protozero::internal::gen_helpers::EqualsField(processing_animation_worklets_for_active_tree_, other.processing_animation_worklets_for_active_tree_)
+ && ::protozero::internal::gen_helpers::EqualsField(processing_animation_worklets_for_pending_tree_, other.processing_animation_worklets_for_pending_tree_)
+ && ::protozero::internal::gen_helpers::EqualsField(processing_paint_worklets_for_pending_tree_, other.processing_paint_worklets_for_pending_tree_);
}
-bool ThreadDescriptor::ParseFromArray(const void* raw, size_t size) {
+bool ChromeCompositorStateMachine_MinorState::ParseFromArray(const void* raw, size_t size) {
unknown_fields_.clear();
bool packed_error = false;
@@ -36817,223 +36619,140 @@ bool ThreadDescriptor::ParseFromArray(const void* raw, size_t size) {
_has_field_.set(field.id());
}
switch (field.id()) {
- case 1 /* pid */:
- field.get(&pid_);
+ case 1 /* commit_count */:
+ field.get(&commit_count_);
break;
- case 2 /* tid */:
- field.get(&tid_);
+ case 2 /* current_frame_number */:
+ field.get(¤t_frame_number_);
break;
- case 5 /* thread_name */:
- ::protozero::internal::gen_helpers::DeserializeString(field, &thread_name_);
+ case 3 /* last_frame_number_submit_performed */:
+ field.get(&last_frame_number_submit_performed_);
break;
- case 4 /* chrome_thread_type */:
- field.get(&chrome_thread_type_);
+ case 4 /* last_frame_number_draw_performed */:
+ field.get(&last_frame_number_draw_performed_);
break;
- case 6 /* reference_timestamp_us */:
- field.get(&reference_timestamp_us_);
+ case 5 /* last_frame_number_begin_main_frame_sent */:
+ field.get(&last_frame_number_begin_main_frame_sent_);
break;
- case 7 /* reference_thread_time_us */:
- field.get(&reference_thread_time_us_);
+ case 6 /* did_draw */:
+ field.get(&did_draw_);
break;
- case 8 /* reference_thread_instruction_count */:
- field.get(&reference_thread_instruction_count_);
+ case 7 /* did_send_begin_main_frame_for_current_frame */:
+ field.get(&did_send_begin_main_frame_for_current_frame_);
break;
- case 3 /* legacy_sort_index */:
- field.get(&legacy_sort_index_);
+ case 8 /* did_notify_begin_main_frame_not_expected_until */:
+ field.get(&did_notify_begin_main_frame_not_expected_until_);
break;
- default:
- field.SerializeAndAppendTo(&unknown_fields_);
+ case 9 /* did_notify_begin_main_frame_not_expected_soon */:
+ field.get(&did_notify_begin_main_frame_not_expected_soon_);
break;
- }
- }
- return !packed_error && !dec.bytes_left();
-}
-
-std::string ThreadDescriptor::SerializeAsString() const {
- ::protozero::internal::gen_helpers::MessageSerializer msg;
- Serialize(msg.get());
- return msg.SerializeAsString();
-}
-
-std::vector<uint8_t> ThreadDescriptor::SerializeAsArray() const {
- ::protozero::internal::gen_helpers::MessageSerializer msg;
- Serialize(msg.get());
- return msg.SerializeAsArray();
-}
-
-void ThreadDescriptor::Serialize(::protozero::Message* msg) const {
- // Field 1: pid
- if (_has_field_[1]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(1, pid_, msg);
- }
-
- // Field 2: tid
- if (_has_field_[2]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(2, tid_, msg);
- }
-
- // Field 5: thread_name
- if (_has_field_[5]) {
- ::protozero::internal::gen_helpers::SerializeString(5, thread_name_, msg);
- }
-
- // Field 4: chrome_thread_type
- if (_has_field_[4]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(4, chrome_thread_type_, msg);
- }
-
- // Field 6: reference_timestamp_us
- if (_has_field_[6]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(6, reference_timestamp_us_, msg);
- }
-
- // Field 7: reference_thread_time_us
- if (_has_field_[7]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(7, reference_thread_time_us_, msg);
- }
-
- // Field 8: reference_thread_instruction_count
- if (_has_field_[8]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(8, reference_thread_instruction_count_, msg);
- }
-
- // Field 3: legacy_sort_index
- if (_has_field_[3]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(3, legacy_sort_index_, msg);
- }
-
- protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
-}
-
-} // namespace perfetto
-} // namespace protos
-} // namespace gen
-#if defined(__GNUC__) || defined(__clang__)
-#pragma GCC diagnostic pop
-#endif
-// gen_amalgamated begin source: gen/protos/perfetto/trace/track_event/track_descriptor.gen.cc
-// gen_amalgamated expanded: #include "perfetto/protozero/gen_field_helpers.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/message.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/packed_repeated_fields.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/proto_decoder.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/scattered_heap_buffer.h"
-// DO NOT EDIT. Autogenerated by Perfetto cppgen_plugin
-#if defined(__GNUC__) || defined(__clang__)
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wfloat-equal"
-#endif
-// gen_amalgamated expanded: #include "protos/perfetto/trace/track_event/track_descriptor.gen.h"
-// gen_amalgamated expanded: #include "protos/perfetto/trace/track_event/state_descriptor.gen.h"
-// gen_amalgamated expanded: #include "protos/perfetto/trace/track_event/counter_descriptor.gen.h"
-// gen_amalgamated expanded: #include "protos/perfetto/trace/track_event/thread_descriptor.gen.h"
-// gen_amalgamated expanded: #include "protos/perfetto/trace/track_event/process_descriptor.gen.h"
-// gen_amalgamated expanded: #include "protos/perfetto/trace/track_event/chrome_thread_descriptor.gen.h"
-// gen_amalgamated expanded: #include "protos/perfetto/trace/track_event/chrome_process_descriptor.gen.h"
-
-namespace perfetto {
-namespace protos {
-namespace gen {
-
-TrackDescriptor::TrackDescriptor() = default;
-TrackDescriptor::~TrackDescriptor() = default;
-TrackDescriptor::TrackDescriptor(const TrackDescriptor&) = default;
-TrackDescriptor& TrackDescriptor::operator=(const TrackDescriptor&) = default;
-TrackDescriptor::TrackDescriptor(TrackDescriptor&&) noexcept = default;
-TrackDescriptor& TrackDescriptor::operator=(TrackDescriptor&&) = default;
-
-bool TrackDescriptor::operator==(const TrackDescriptor& other) const {
- return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
- && ::protozero::internal::gen_helpers::EqualsField(uuid_, other.uuid_)
- && ::protozero::internal::gen_helpers::EqualsField(parent_uuid_, other.parent_uuid_)
- && ::protozero::internal::gen_helpers::EqualsField(name_, other.name_)
- && ::protozero::internal::gen_helpers::EqualsField(static_name_, other.static_name_)
- && ::protozero::internal::gen_helpers::EqualsField(atrace_name_, other.atrace_name_)
- && ::protozero::internal::gen_helpers::EqualsField(description_, other.description_)
- && ::protozero::internal::gen_helpers::EqualsField(process_, other.process_)
- && ::protozero::internal::gen_helpers::EqualsField(chrome_process_, other.chrome_process_)
- && ::protozero::internal::gen_helpers::EqualsField(thread_, other.thread_)
- && ::protozero::internal::gen_helpers::EqualsField(chrome_thread_, other.chrome_thread_)
- && ::protozero::internal::gen_helpers::EqualsField(counter_, other.counter_)
- && ::protozero::internal::gen_helpers::EqualsField(state_, other.state_)
- && ::protozero::internal::gen_helpers::EqualsField(disallow_merging_with_system_tracks_, other.disallow_merging_with_system_tracks_)
- && ::protozero::internal::gen_helpers::EqualsField(child_ordering_, other.child_ordering_)
- && ::protozero::internal::gen_helpers::EqualsField(sibling_order_rank_, other.sibling_order_rank_)
- && ::protozero::internal::gen_helpers::EqualsField(sibling_merge_behavior_, other.sibling_merge_behavior_)
- && ::protozero::internal::gen_helpers::EqualsField(sibling_merge_key_, other.sibling_merge_key_)
- && ::protozero::internal::gen_helpers::EqualsField(sibling_merge_key_int_, other.sibling_merge_key_int_)
- && ::protozero::internal::gen_helpers::EqualsField(process_ordering_, other.process_ordering_)
- && ::protozero::internal::gen_helpers::EqualsField(thread_ordering_, other.thread_ordering_);
-}
-
-bool TrackDescriptor::ParseFromArray(const void* raw, size_t size) {
- unknown_fields_.clear();
- bool packed_error = false;
-
- ::protozero::ProtoDecoder dec(raw, size);
- for (auto field = dec.ReadField(); field.valid(); field = dec.ReadField()) {
- if (field.id() < _has_field_.size()) {
- _has_field_.set(field.id());
- }
- switch (field.id()) {
- case 1 /* uuid */:
- field.get(&uuid_);
+ case 10 /* wants_begin_main_frame_not_expected */:
+ field.get(&wants_begin_main_frame_not_expected_);
break;
- case 5 /* parent_uuid */:
- field.get(&parent_uuid_);
+ case 11 /* did_commit_during_frame */:
+ field.get(&did_commit_during_frame_);
break;
- case 2 /* name */:
- ::protozero::internal::gen_helpers::DeserializeString(field, &name_);
+ case 12 /* did_invalidate_layer_tree_frame_sink */:
+ field.get(&did_invalidate_layer_tree_frame_sink_);
break;
- case 10 /* static_name */:
- ::protozero::internal::gen_helpers::DeserializeString(field, &static_name_);
+ case 13 /* did_perform_impl_side_invalidaion */:
+ field.get(&did_perform_impl_side_invalidaion_);
break;
- case 13 /* atrace_name */:
- ::protozero::internal::gen_helpers::DeserializeString(field, &atrace_name_);
+ case 14 /* did_prepare_tiles */:
+ field.get(&did_prepare_tiles_);
break;
- case 14 /* description */:
- ::protozero::internal::gen_helpers::DeserializeString(field, &description_);
+ case 15 /* consecutive_checkerboard_animations */:
+ field.get(&consecutive_checkerboard_animations_);
break;
- case 3 /* process */:
- (*process_).ParseFromArray(field.data(), field.size());
+ case 16 /* pending_submit_frames */:
+ field.get(&pending_submit_frames_);
break;
- case 6 /* chrome_process */:
- (*chrome_process_).ParseFromArray(field.data(), field.size());
+ case 17 /* submit_frames_with_current_layer_tree_frame_sink */:
+ field.get(&submit_frames_with_current_layer_tree_frame_sink_);
break;
- case 4 /* thread */:
- (*thread_).ParseFromArray(field.data(), field.size());
+ case 18 /* needs_redraw */:
+ field.get(&needs_redraw_);
break;
- case 7 /* chrome_thread */:
- (*chrome_thread_).ParseFromArray(field.data(), field.size());
+ case 19 /* needs_prepare_tiles */:
+ field.get(&needs_prepare_tiles_);
break;
- case 8 /* counter */:
- (*counter_).ParseFromArray(field.data(), field.size());
+ case 20 /* needs_begin_main_frame */:
+ field.get(&needs_begin_main_frame_);
break;
- case 18 /* state */:
- (*state_).ParseFromArray(field.data(), field.size());
+ case 21 /* needs_one_begin_impl_frame */:
+ field.get(&needs_one_begin_impl_frame_);
break;
- case 9 /* disallow_merging_with_system_tracks */:
- field.get(&disallow_merging_with_system_tracks_);
+ case 22 /* visible */:
+ field.get(&visible_);
break;
- case 11 /* child_ordering */:
- field.get(&child_ordering_);
+ case 23 /* begin_frame_source_paused */:
+ field.get(&begin_frame_source_paused_);
break;
- case 12 /* sibling_order_rank */:
- field.get(&sibling_order_rank_);
+ case 24 /* can_draw */:
+ field.get(&can_draw_);
break;
- case 15 /* sibling_merge_behavior */:
- field.get(&sibling_merge_behavior_);
+ case 25 /* resourceless_draw */:
+ field.get(&resourceless_draw_);
break;
- case 16 /* sibling_merge_key */:
- ::protozero::internal::gen_helpers::DeserializeString(field, &sibling_merge_key_);
+ case 26 /* has_pending_tree */:
+ field.get(&has_pending_tree_);
break;
- case 17 /* sibling_merge_key_int */:
- field.get(&sibling_merge_key_int_);
+ case 27 /* pending_tree_is_ready_for_activation */:
+ field.get(&pending_tree_is_ready_for_activation_);
break;
- case 19 /* process_ordering */:
- field.get(&process_ordering_);
+ case 28 /* active_tree_needs_first_draw */:
+ field.get(&active_tree_needs_first_draw_);
break;
- case 20 /* thread_ordering */:
- field.get(&thread_ordering_);
+ case 29 /* active_tree_is_ready_to_draw */:
+ field.get(&active_tree_is_ready_to_draw_);
+ break;
+ case 30 /* did_create_and_initialize_first_layer_tree_frame_sink */:
+ field.get(&did_create_and_initialize_first_layer_tree_frame_sink_);
+ break;
+ case 31 /* tree_priority */:
+ field.get(&tree_priority_);
+ break;
+ case 32 /* scroll_handler_state */:
+ field.get(&scroll_handler_state_);
+ break;
+ case 33 /* critical_begin_main_frame_to_activate_is_fast */:
+ field.get(&critical_begin_main_frame_to_activate_is_fast_);
+ break;
+ case 34 /* main_thread_missed_last_deadline */:
+ field.get(&main_thread_missed_last_deadline_);
+ break;
+ case 36 /* video_needs_begin_frames */:
+ field.get(&video_needs_begin_frames_);
+ break;
+ case 37 /* defer_begin_main_frame */:
+ field.get(&defer_begin_main_frame_);
+ break;
+ case 38 /* last_commit_had_no_updates */:
+ field.get(&last_commit_had_no_updates_);
+ break;
+ case 39 /* did_draw_in_last_frame */:
+ field.get(&did_draw_in_last_frame_);
+ break;
+ case 40 /* did_submit_in_last_frame */:
+ field.get(&did_submit_in_last_frame_);
+ break;
+ case 41 /* needs_impl_side_invalidation */:
+ field.get(&needs_impl_side_invalidation_);
+ break;
+ case 42 /* current_pending_tree_is_impl_side */:
+ field.get(¤t_pending_tree_is_impl_side_);
+ break;
+ case 43 /* previous_pending_tree_was_impl_side */:
+ field.get(&previous_pending_tree_was_impl_side_);
+ break;
+ case 44 /* processing_animation_worklets_for_active_tree */:
+ field.get(&processing_animation_worklets_for_active_tree_);
+ break;
+ case 45 /* processing_animation_worklets_for_pending_tree */:
+ field.get(&processing_animation_worklets_for_pending_tree_);
+ break;
+ case 46 /* processing_paint_worklets_for_pending_tree */:
+ field.get(&processing_paint_worklets_for_pending_tree_);
break;
default:
field.SerializeAndAppendTo(&unknown_fields_);
@@ -37043,178 +36762,265 @@ bool TrackDescriptor::ParseFromArray(const void* raw, size_t size) {
return !packed_error && !dec.bytes_left();
}
-std::string TrackDescriptor::SerializeAsString() const {
+std::string ChromeCompositorStateMachine_MinorState::SerializeAsString() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsString();
}
-std::vector<uint8_t> TrackDescriptor::SerializeAsArray() const {
+std::vector<uint8_t> ChromeCompositorStateMachine_MinorState::SerializeAsArray() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsArray();
}
-void TrackDescriptor::Serialize(::protozero::Message* msg) const {
- // Field 1: uuid
+void ChromeCompositorStateMachine_MinorState::Serialize(::protozero::Message* msg) const {
+ // Field 1: commit_count
if (_has_field_[1]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(1, uuid_, msg);
- }
-
- // Field 5: parent_uuid
- if (_has_field_[5]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(5, parent_uuid_, msg);
+ ::protozero::internal::gen_helpers::SerializeVarInt(1, commit_count_, msg);
}
- // Field 2: name
+ // Field 2: current_frame_number
if (_has_field_[2]) {
- ::protozero::internal::gen_helpers::SerializeString(2, name_, msg);
- }
-
- // Field 10: static_name
- if (_has_field_[10]) {
- ::protozero::internal::gen_helpers::SerializeString(10, static_name_, msg);
+ ::protozero::internal::gen_helpers::SerializeVarInt(2, current_frame_number_, msg);
}
- // Field 13: atrace_name
- if (_has_field_[13]) {
- ::protozero::internal::gen_helpers::SerializeString(13, atrace_name_, msg);
+ // Field 3: last_frame_number_submit_performed
+ if (_has_field_[3]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(3, last_frame_number_submit_performed_, msg);
}
- // Field 14: description
- if (_has_field_[14]) {
- ::protozero::internal::gen_helpers::SerializeString(14, description_, msg);
+ // Field 4: last_frame_number_draw_performed
+ if (_has_field_[4]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(4, last_frame_number_draw_performed_, msg);
}
- // Field 3: process
- if (_has_field_[3]) {
- (*process_).Serialize(msg->BeginNestedMessage<::protozero::Message>(3));
+ // Field 5: last_frame_number_begin_main_frame_sent
+ if (_has_field_[5]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(5, last_frame_number_begin_main_frame_sent_, msg);
}
- // Field 6: chrome_process
+ // Field 6: did_draw
if (_has_field_[6]) {
- (*chrome_process_).Serialize(msg->BeginNestedMessage<::protozero::Message>(6));
- }
-
- // Field 4: thread
- if (_has_field_[4]) {
- (*thread_).Serialize(msg->BeginNestedMessage<::protozero::Message>(4));
+ ::protozero::internal::gen_helpers::SerializeTinyVarInt(6, did_draw_, msg);
}
- // Field 7: chrome_thread
+ // Field 7: did_send_begin_main_frame_for_current_frame
if (_has_field_[7]) {
- (*chrome_thread_).Serialize(msg->BeginNestedMessage<::protozero::Message>(7));
+ ::protozero::internal::gen_helpers::SerializeTinyVarInt(7, did_send_begin_main_frame_for_current_frame_, msg);
}
- // Field 8: counter
+ // Field 8: did_notify_begin_main_frame_not_expected_until
if (_has_field_[8]) {
- (*counter_).Serialize(msg->BeginNestedMessage<::protozero::Message>(8));
+ ::protozero::internal::gen_helpers::SerializeTinyVarInt(8, did_notify_begin_main_frame_not_expected_until_, msg);
}
- // Field 18: state
- if (_has_field_[18]) {
- (*state_).Serialize(msg->BeginNestedMessage<::protozero::Message>(18));
+ // Field 9: did_notify_begin_main_frame_not_expected_soon
+ if (_has_field_[9]) {
+ ::protozero::internal::gen_helpers::SerializeTinyVarInt(9, did_notify_begin_main_frame_not_expected_soon_, msg);
}
- // Field 9: disallow_merging_with_system_tracks
- if (_has_field_[9]) {
- ::protozero::internal::gen_helpers::SerializeTinyVarInt(9, disallow_merging_with_system_tracks_, msg);
+ // Field 10: wants_begin_main_frame_not_expected
+ if (_has_field_[10]) {
+ ::protozero::internal::gen_helpers::SerializeTinyVarInt(10, wants_begin_main_frame_not_expected_, msg);
}
- // Field 11: child_ordering
+ // Field 11: did_commit_during_frame
if (_has_field_[11]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(11, child_ordering_, msg);
+ ::protozero::internal::gen_helpers::SerializeTinyVarInt(11, did_commit_during_frame_, msg);
}
- // Field 12: sibling_order_rank
+ // Field 12: did_invalidate_layer_tree_frame_sink
if (_has_field_[12]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(12, sibling_order_rank_, msg);
+ ::protozero::internal::gen_helpers::SerializeTinyVarInt(12, did_invalidate_layer_tree_frame_sink_, msg);
}
- // Field 15: sibling_merge_behavior
+ // Field 13: did_perform_impl_side_invalidaion
+ if (_has_field_[13]) {
+ ::protozero::internal::gen_helpers::SerializeTinyVarInt(13, did_perform_impl_side_invalidaion_, msg);
+ }
+
+ // Field 14: did_prepare_tiles
+ if (_has_field_[14]) {
+ ::protozero::internal::gen_helpers::SerializeTinyVarInt(14, did_prepare_tiles_, msg);
+ }
+
+ // Field 15: consecutive_checkerboard_animations
if (_has_field_[15]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(15, sibling_merge_behavior_, msg);
+ ::protozero::internal::gen_helpers::SerializeVarInt(15, consecutive_checkerboard_animations_, msg);
}
- // Field 16: sibling_merge_key
+ // Field 16: pending_submit_frames
if (_has_field_[16]) {
- ::protozero::internal::gen_helpers::SerializeString(16, sibling_merge_key_, msg);
+ ::protozero::internal::gen_helpers::SerializeVarInt(16, pending_submit_frames_, msg);
}
- // Field 17: sibling_merge_key_int
+ // Field 17: submit_frames_with_current_layer_tree_frame_sink
if (_has_field_[17]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(17, sibling_merge_key_int_, msg);
+ ::protozero::internal::gen_helpers::SerializeVarInt(17, submit_frames_with_current_layer_tree_frame_sink_, msg);
}
- // Field 19: process_ordering
+ // Field 18: needs_redraw
+ if (_has_field_[18]) {
+ ::protozero::internal::gen_helpers::SerializeTinyVarInt(18, needs_redraw_, msg);
+ }
+
+ // Field 19: needs_prepare_tiles
if (_has_field_[19]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(19, process_ordering_, msg);
+ ::protozero::internal::gen_helpers::SerializeTinyVarInt(19, needs_prepare_tiles_, msg);
}
- // Field 20: thread_ordering
+ // Field 20: needs_begin_main_frame
if (_has_field_[20]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(20, thread_ordering_, msg);
+ ::protozero::internal::gen_helpers::SerializeTinyVarInt(20, needs_begin_main_frame_, msg);
}
- protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
-}
+ // Field 21: needs_one_begin_impl_frame
+ if (_has_field_[21]) {
+ ::protozero::internal::gen_helpers::SerializeTinyVarInt(21, needs_one_begin_impl_frame_, msg);
+ }
-} // namespace perfetto
-} // namespace protos
-} // namespace gen
-#if defined(__GNUC__) || defined(__clang__)
-#pragma GCC diagnostic pop
-#endif
-// gen_amalgamated begin source: gen/protos/perfetto/trace/track_event/track_event.gen.cc
-// gen_amalgamated expanded: #include "perfetto/protozero/gen_field_helpers.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/message.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/packed_repeated_fields.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/proto_decoder.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/scattered_heap_buffer.h"
-// DO NOT EDIT. Autogenerated by Perfetto cppgen_plugin
-#if defined(__GNUC__) || defined(__clang__)
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wfloat-equal"
-#endif
-// gen_amalgamated expanded: #include "protos/perfetto/trace/track_event/track_event.gen.h"
-// gen_amalgamated expanded: #include "protos/perfetto/trace/track_event/source_location.gen.h"
-// gen_amalgamated expanded: #include "protos/perfetto/trace/track_event/screenshot.gen.h"
-// gen_amalgamated expanded: #include "protos/perfetto/trace/track_event/chrome_window_handle_event_info.gen.h"
-// gen_amalgamated expanded: #include "protos/perfetto/trace/track_event/chrome_user_event.gen.h"
-// gen_amalgamated expanded: #include "protos/perfetto/trace/track_event/chrome_renderer_scheduler_state.gen.h"
-// gen_amalgamated expanded: #include "protos/perfetto/trace/track_event/chrome_mojo_event_info.gen.h"
-// gen_amalgamated expanded: #include "protos/perfetto/trace/track_event/chrome_message_pump.gen.h"
-// gen_amalgamated expanded: #include "protos/perfetto/trace/track_event/chrome_legacy_ipc.gen.h"
-// gen_amalgamated expanded: #include "protos/perfetto/trace/track_event/chrome_latency_info.gen.h"
-// gen_amalgamated expanded: #include "protos/perfetto/trace/track_event/chrome_keyed_service.gen.h"
-// gen_amalgamated expanded: #include "protos/perfetto/trace/track_event/chrome_histogram_sample.gen.h"
-// gen_amalgamated expanded: #include "protos/perfetto/trace/track_event/chrome_frame_reporter.gen.h"
-// gen_amalgamated expanded: #include "protos/perfetto/trace/track_event/chrome_content_settings_event_info.gen.h"
-// gen_amalgamated expanded: #include "protos/perfetto/trace/track_event/chrome_compositor_scheduler_state.gen.h"
-// gen_amalgamated expanded: #include "protos/perfetto/trace/track_event/chrome_application_state_info.gen.h"
-// gen_amalgamated expanded: #include "protos/perfetto/trace/track_event/chrome_active_processes.gen.h"
-// gen_amalgamated expanded: #include "protos/perfetto/trace/track_event/task_execution.gen.h"
-// gen_amalgamated expanded: #include "protos/perfetto/trace/track_event/log_message.gen.h"
-// gen_amalgamated expanded: #include "protos/perfetto/trace/track_event/debug_annotation.gen.h"
+ // Field 22: visible
+ if (_has_field_[22]) {
+ ::protozero::internal::gen_helpers::SerializeTinyVarInt(22, visible_, msg);
+ }
-namespace perfetto {
-namespace protos {
-namespace gen {
+ // Field 23: begin_frame_source_paused
+ if (_has_field_[23]) {
+ ::protozero::internal::gen_helpers::SerializeTinyVarInt(23, begin_frame_source_paused_, msg);
+ }
-EventName::EventName() = default;
-EventName::~EventName() = default;
-EventName::EventName(const EventName&) = default;
-EventName& EventName::operator=(const EventName&) = default;
-EventName::EventName(EventName&&) noexcept = default;
-EventName& EventName::operator=(EventName&&) = default;
+ // Field 24: can_draw
+ if (_has_field_[24]) {
+ ::protozero::internal::gen_helpers::SerializeTinyVarInt(24, can_draw_, msg);
+ }
-bool EventName::operator==(const EventName& other) const {
+ // Field 25: resourceless_draw
+ if (_has_field_[25]) {
+ ::protozero::internal::gen_helpers::SerializeTinyVarInt(25, resourceless_draw_, msg);
+ }
+
+ // Field 26: has_pending_tree
+ if (_has_field_[26]) {
+ ::protozero::internal::gen_helpers::SerializeTinyVarInt(26, has_pending_tree_, msg);
+ }
+
+ // Field 27: pending_tree_is_ready_for_activation
+ if (_has_field_[27]) {
+ ::protozero::internal::gen_helpers::SerializeTinyVarInt(27, pending_tree_is_ready_for_activation_, msg);
+ }
+
+ // Field 28: active_tree_needs_first_draw
+ if (_has_field_[28]) {
+ ::protozero::internal::gen_helpers::SerializeTinyVarInt(28, active_tree_needs_first_draw_, msg);
+ }
+
+ // Field 29: active_tree_is_ready_to_draw
+ if (_has_field_[29]) {
+ ::protozero::internal::gen_helpers::SerializeTinyVarInt(29, active_tree_is_ready_to_draw_, msg);
+ }
+
+ // Field 30: did_create_and_initialize_first_layer_tree_frame_sink
+ if (_has_field_[30]) {
+ ::protozero::internal::gen_helpers::SerializeTinyVarInt(30, did_create_and_initialize_first_layer_tree_frame_sink_, msg);
+ }
+
+ // Field 31: tree_priority
+ if (_has_field_[31]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(31, tree_priority_, msg);
+ }
+
+ // Field 32: scroll_handler_state
+ if (_has_field_[32]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(32, scroll_handler_state_, msg);
+ }
+
+ // Field 33: critical_begin_main_frame_to_activate_is_fast
+ if (_has_field_[33]) {
+ ::protozero::internal::gen_helpers::SerializeTinyVarInt(33, critical_begin_main_frame_to_activate_is_fast_, msg);
+ }
+
+ // Field 34: main_thread_missed_last_deadline
+ if (_has_field_[34]) {
+ ::protozero::internal::gen_helpers::SerializeTinyVarInt(34, main_thread_missed_last_deadline_, msg);
+ }
+
+ // Field 36: video_needs_begin_frames
+ if (_has_field_[36]) {
+ ::protozero::internal::gen_helpers::SerializeTinyVarInt(36, video_needs_begin_frames_, msg);
+ }
+
+ // Field 37: defer_begin_main_frame
+ if (_has_field_[37]) {
+ ::protozero::internal::gen_helpers::SerializeTinyVarInt(37, defer_begin_main_frame_, msg);
+ }
+
+ // Field 38: last_commit_had_no_updates
+ if (_has_field_[38]) {
+ ::protozero::internal::gen_helpers::SerializeTinyVarInt(38, last_commit_had_no_updates_, msg);
+ }
+
+ // Field 39: did_draw_in_last_frame
+ if (_has_field_[39]) {
+ ::protozero::internal::gen_helpers::SerializeTinyVarInt(39, did_draw_in_last_frame_, msg);
+ }
+
+ // Field 40: did_submit_in_last_frame
+ if (_has_field_[40]) {
+ ::protozero::internal::gen_helpers::SerializeTinyVarInt(40, did_submit_in_last_frame_, msg);
+ }
+
+ // Field 41: needs_impl_side_invalidation
+ if (_has_field_[41]) {
+ ::protozero::internal::gen_helpers::SerializeTinyVarInt(41, needs_impl_side_invalidation_, msg);
+ }
+
+ // Field 42: current_pending_tree_is_impl_side
+ if (_has_field_[42]) {
+ ::protozero::internal::gen_helpers::SerializeTinyVarInt(42, current_pending_tree_is_impl_side_, msg);
+ }
+
+ // Field 43: previous_pending_tree_was_impl_side
+ if (_has_field_[43]) {
+ ::protozero::internal::gen_helpers::SerializeTinyVarInt(43, previous_pending_tree_was_impl_side_, msg);
+ }
+
+ // Field 44: processing_animation_worklets_for_active_tree
+ if (_has_field_[44]) {
+ ::protozero::internal::gen_helpers::SerializeTinyVarInt(44, processing_animation_worklets_for_active_tree_, msg);
+ }
+
+ // Field 45: processing_animation_worklets_for_pending_tree
+ if (_has_field_[45]) {
+ ::protozero::internal::gen_helpers::SerializeTinyVarInt(45, processing_animation_worklets_for_pending_tree_, msg);
+ }
+
+ // Field 46: processing_paint_worklets_for_pending_tree
+ if (_has_field_[46]) {
+ ::protozero::internal::gen_helpers::SerializeTinyVarInt(46, processing_paint_worklets_for_pending_tree_, msg);
+ }
+
+ protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
+}
+
+
+ChromeCompositorStateMachine_MajorState::ChromeCompositorStateMachine_MajorState() = default;
+ChromeCompositorStateMachine_MajorState::~ChromeCompositorStateMachine_MajorState() = default;
+ChromeCompositorStateMachine_MajorState::ChromeCompositorStateMachine_MajorState(const ChromeCompositorStateMachine_MajorState&) = default;
+ChromeCompositorStateMachine_MajorState& ChromeCompositorStateMachine_MajorState::operator=(const ChromeCompositorStateMachine_MajorState&) = default;
+ChromeCompositorStateMachine_MajorState::ChromeCompositorStateMachine_MajorState(ChromeCompositorStateMachine_MajorState&&) noexcept = default;
+ChromeCompositorStateMachine_MajorState& ChromeCompositorStateMachine_MajorState::operator=(ChromeCompositorStateMachine_MajorState&&) = default;
+
+bool ChromeCompositorStateMachine_MajorState::operator==(const ChromeCompositorStateMachine_MajorState& other) const {
return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
- && ::protozero::internal::gen_helpers::EqualsField(iid_, other.iid_)
- && ::protozero::internal::gen_helpers::EqualsField(name_, other.name_);
+ && ::protozero::internal::gen_helpers::EqualsField(next_action_, other.next_action_)
+ && ::protozero::internal::gen_helpers::EqualsField(begin_impl_frame_state_, other.begin_impl_frame_state_)
+ && ::protozero::internal::gen_helpers::EqualsField(begin_main_frame_state_, other.begin_main_frame_state_)
+ && ::protozero::internal::gen_helpers::EqualsField(layer_tree_frame_sink_state_, other.layer_tree_frame_sink_state_)
+ && ::protozero::internal::gen_helpers::EqualsField(forced_redraw_state_, other.forced_redraw_state_);
}
-bool EventName::ParseFromArray(const void* raw, size_t size) {
+bool ChromeCompositorStateMachine_MajorState::ParseFromArray(const void* raw, size_t size) {
unknown_fields_.clear();
bool packed_error = false;
@@ -37224,11 +37030,20 @@ bool EventName::ParseFromArray(const void* raw, size_t size) {
_has_field_.set(field.id());
}
switch (field.id()) {
- case 1 /* iid */:
- field.get(&iid_);
+ case 1 /* next_action */:
+ field.get(&next_action_);
break;
- case 2 /* name */:
- ::protozero::internal::gen_helpers::DeserializeString(field, &name_);
+ case 2 /* begin_impl_frame_state */:
+ field.get(&begin_impl_frame_state_);
+ break;
+ case 3 /* begin_main_frame_state */:
+ field.get(&begin_main_frame_state_);
+ break;
+ case 4 /* layer_tree_frame_sink_state */:
+ field.get(&layer_tree_frame_sink_state_);
+ break;
+ case 5 /* forced_redraw_state */:
+ field.get(&forced_redraw_state_);
break;
default:
field.SerializeAndAppendTo(&unknown_fields_);
@@ -37238,47 +37053,76 @@ bool EventName::ParseFromArray(const void* raw, size_t size) {
return !packed_error && !dec.bytes_left();
}
-std::string EventName::SerializeAsString() const {
+std::string ChromeCompositorStateMachine_MajorState::SerializeAsString() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsString();
}
-std::vector<uint8_t> EventName::SerializeAsArray() const {
+std::vector<uint8_t> ChromeCompositorStateMachine_MajorState::SerializeAsArray() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsArray();
}
-void EventName::Serialize(::protozero::Message* msg) const {
- // Field 1: iid
+void ChromeCompositorStateMachine_MajorState::Serialize(::protozero::Message* msg) const {
+ // Field 1: next_action
if (_has_field_[1]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(1, iid_, msg);
+ ::protozero::internal::gen_helpers::SerializeVarInt(1, next_action_, msg);
}
- // Field 2: name
+ // Field 2: begin_impl_frame_state
if (_has_field_[2]) {
- ::protozero::internal::gen_helpers::SerializeString(2, name_, msg);
+ ::protozero::internal::gen_helpers::SerializeVarInt(2, begin_impl_frame_state_, msg);
+ }
+
+ // Field 3: begin_main_frame_state
+ if (_has_field_[3]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(3, begin_main_frame_state_, msg);
+ }
+
+ // Field 4: layer_tree_frame_sink_state
+ if (_has_field_[4]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(4, layer_tree_frame_sink_state_, msg);
+ }
+
+ // Field 5: forced_redraw_state
+ if (_has_field_[5]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(5, forced_redraw_state_, msg);
}
protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
}
-EventCategory::EventCategory() = default;
-EventCategory::~EventCategory() = default;
-EventCategory::EventCategory(const EventCategory&) = default;
-EventCategory& EventCategory::operator=(const EventCategory&) = default;
-EventCategory::EventCategory(EventCategory&&) noexcept = default;
-EventCategory& EventCategory::operator=(EventCategory&&) = default;
+ChromeCompositorSchedulerState::ChromeCompositorSchedulerState() = default;
+ChromeCompositorSchedulerState::~ChromeCompositorSchedulerState() = default;
+ChromeCompositorSchedulerState::ChromeCompositorSchedulerState(const ChromeCompositorSchedulerState&) = default;
+ChromeCompositorSchedulerState& ChromeCompositorSchedulerState::operator=(const ChromeCompositorSchedulerState&) = default;
+ChromeCompositorSchedulerState::ChromeCompositorSchedulerState(ChromeCompositorSchedulerState&&) noexcept = default;
+ChromeCompositorSchedulerState& ChromeCompositorSchedulerState::operator=(ChromeCompositorSchedulerState&&) = default;
-bool EventCategory::operator==(const EventCategory& other) const {
+bool ChromeCompositorSchedulerState::operator==(const ChromeCompositorSchedulerState& other) const {
return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
- && ::protozero::internal::gen_helpers::EqualsField(iid_, other.iid_)
- && ::protozero::internal::gen_helpers::EqualsField(name_, other.name_);
+ && ::protozero::internal::gen_helpers::EqualsField(state_machine_, other.state_machine_)
+ && ::protozero::internal::gen_helpers::EqualsField(observing_begin_frame_source_, other.observing_begin_frame_source_)
+ && ::protozero::internal::gen_helpers::EqualsField(begin_impl_frame_deadline_task_, other.begin_impl_frame_deadline_task_)
+ && ::protozero::internal::gen_helpers::EqualsField(pending_begin_frame_task_, other.pending_begin_frame_task_)
+ && ::protozero::internal::gen_helpers::EqualsField(skipped_last_frame_missed_exceeded_deadline_, other.skipped_last_frame_missed_exceeded_deadline_)
+ && ::protozero::internal::gen_helpers::EqualsField(inside_action_, other.inside_action_)
+ && ::protozero::internal::gen_helpers::EqualsField(deadline_mode_, other.deadline_mode_)
+ && ::protozero::internal::gen_helpers::EqualsField(deadline_us_, other.deadline_us_)
+ && ::protozero::internal::gen_helpers::EqualsField(deadline_scheduled_at_us_, other.deadline_scheduled_at_us_)
+ && ::protozero::internal::gen_helpers::EqualsField(now_us_, other.now_us_)
+ && ::protozero::internal::gen_helpers::EqualsField(now_to_deadline_delta_us_, other.now_to_deadline_delta_us_)
+ && ::protozero::internal::gen_helpers::EqualsField(now_to_deadline_scheduled_at_delta_us_, other.now_to_deadline_scheduled_at_delta_us_)
+ && ::protozero::internal::gen_helpers::EqualsField(begin_impl_frame_args_, other.begin_impl_frame_args_)
+ && ::protozero::internal::gen_helpers::EqualsField(begin_frame_observer_state_, other.begin_frame_observer_state_)
+ && ::protozero::internal::gen_helpers::EqualsField(begin_frame_source_state_, other.begin_frame_source_state_)
+ && ::protozero::internal::gen_helpers::EqualsField(compositor_timing_history_, other.compositor_timing_history_);
}
-bool EventCategory::ParseFromArray(const void* raw, size_t size) {
+bool ChromeCompositorSchedulerState::ParseFromArray(const void* raw, size_t size) {
unknown_fields_.clear();
bool packed_error = false;
@@ -37288,11 +37132,53 @@ bool EventCategory::ParseFromArray(const void* raw, size_t size) {
_has_field_.set(field.id());
}
switch (field.id()) {
- case 1 /* iid */:
- field.get(&iid_);
+ case 1 /* state_machine */:
+ (*state_machine_).ParseFromArray(field.data(), field.size());
break;
- case 2 /* name */:
- ::protozero::internal::gen_helpers::DeserializeString(field, &name_);
+ case 2 /* observing_begin_frame_source */:
+ field.get(&observing_begin_frame_source_);
+ break;
+ case 3 /* begin_impl_frame_deadline_task */:
+ field.get(&begin_impl_frame_deadline_task_);
+ break;
+ case 4 /* pending_begin_frame_task */:
+ field.get(&pending_begin_frame_task_);
+ break;
+ case 5 /* skipped_last_frame_missed_exceeded_deadline */:
+ field.get(&skipped_last_frame_missed_exceeded_deadline_);
+ break;
+ case 7 /* inside_action */:
+ field.get(&inside_action_);
+ break;
+ case 8 /* deadline_mode */:
+ field.get(&deadline_mode_);
+ break;
+ case 9 /* deadline_us */:
+ field.get(&deadline_us_);
+ break;
+ case 10 /* deadline_scheduled_at_us */:
+ field.get(&deadline_scheduled_at_us_);
+ break;
+ case 11 /* now_us */:
+ field.get(&now_us_);
+ break;
+ case 12 /* now_to_deadline_delta_us */:
+ field.get(&now_to_deadline_delta_us_);
+ break;
+ case 13 /* now_to_deadline_scheduled_at_delta_us */:
+ field.get(&now_to_deadline_scheduled_at_delta_us_);
+ break;
+ case 14 /* begin_impl_frame_args */:
+ (*begin_impl_frame_args_).ParseFromArray(field.data(), field.size());
+ break;
+ case 15 /* begin_frame_observer_state */:
+ (*begin_frame_observer_state_).ParseFromArray(field.data(), field.size());
+ break;
+ case 16 /* begin_frame_source_state */:
+ (*begin_frame_source_state_).ParseFromArray(field.data(), field.size());
+ break;
+ case 17 /* compositor_timing_history */:
+ (*compositor_timing_history_).ParseFromArray(field.data(), field.size());
break;
default:
field.SerializeAndAppendTo(&unknown_fields_);
@@ -37302,50 +37188,138 @@ bool EventCategory::ParseFromArray(const void* raw, size_t size) {
return !packed_error && !dec.bytes_left();
}
-std::string EventCategory::SerializeAsString() const {
+std::string ChromeCompositorSchedulerState::SerializeAsString() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsString();
}
-std::vector<uint8_t> EventCategory::SerializeAsArray() const {
+std::vector<uint8_t> ChromeCompositorSchedulerState::SerializeAsArray() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsArray();
}
-void EventCategory::Serialize(::protozero::Message* msg) const {
- // Field 1: iid
+void ChromeCompositorSchedulerState::Serialize(::protozero::Message* msg) const {
+ // Field 1: state_machine
if (_has_field_[1]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(1, iid_, msg);
+ (*state_machine_).Serialize(msg->BeginNestedMessage<::protozero::Message>(1));
}
- // Field 2: name
+ // Field 2: observing_begin_frame_source
if (_has_field_[2]) {
- ::protozero::internal::gen_helpers::SerializeString(2, name_, msg);
+ ::protozero::internal::gen_helpers::SerializeTinyVarInt(2, observing_begin_frame_source_, msg);
+ }
+
+ // Field 3: begin_impl_frame_deadline_task
+ if (_has_field_[3]) {
+ ::protozero::internal::gen_helpers::SerializeTinyVarInt(3, begin_impl_frame_deadline_task_, msg);
+ }
+
+ // Field 4: pending_begin_frame_task
+ if (_has_field_[4]) {
+ ::protozero::internal::gen_helpers::SerializeTinyVarInt(4, pending_begin_frame_task_, msg);
+ }
+
+ // Field 5: skipped_last_frame_missed_exceeded_deadline
+ if (_has_field_[5]) {
+ ::protozero::internal::gen_helpers::SerializeTinyVarInt(5, skipped_last_frame_missed_exceeded_deadline_, msg);
+ }
+
+ // Field 7: inside_action
+ if (_has_field_[7]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(7, inside_action_, msg);
+ }
+
+ // Field 8: deadline_mode
+ if (_has_field_[8]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(8, deadline_mode_, msg);
+ }
+
+ // Field 9: deadline_us
+ if (_has_field_[9]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(9, deadline_us_, msg);
+ }
+
+ // Field 10: deadline_scheduled_at_us
+ if (_has_field_[10]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(10, deadline_scheduled_at_us_, msg);
+ }
+
+ // Field 11: now_us
+ if (_has_field_[11]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(11, now_us_, msg);
+ }
+
+ // Field 12: now_to_deadline_delta_us
+ if (_has_field_[12]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(12, now_to_deadline_delta_us_, msg);
+ }
+
+ // Field 13: now_to_deadline_scheduled_at_delta_us
+ if (_has_field_[13]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(13, now_to_deadline_scheduled_at_delta_us_, msg);
+ }
+
+ // Field 14: begin_impl_frame_args
+ if (_has_field_[14]) {
+ (*begin_impl_frame_args_).Serialize(msg->BeginNestedMessage<::protozero::Message>(14));
+ }
+
+ // Field 15: begin_frame_observer_state
+ if (_has_field_[15]) {
+ (*begin_frame_observer_state_).Serialize(msg->BeginNestedMessage<::protozero::Message>(15));
+ }
+
+ // Field 16: begin_frame_source_state
+ if (_has_field_[16]) {
+ (*begin_frame_source_state_).Serialize(msg->BeginNestedMessage<::protozero::Message>(16));
+ }
+
+ // Field 17: compositor_timing_history
+ if (_has_field_[17]) {
+ (*compositor_timing_history_).Serialize(msg->BeginNestedMessage<::protozero::Message>(17));
}
protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
}
+} // namespace perfetto
+} // namespace protos
+} // namespace gen
+#if defined(__GNUC__) || defined(__clang__)
+#pragma GCC diagnostic pop
+#endif
+// gen_amalgamated begin source: gen/protos/perfetto/trace/track_event/chrome_content_settings_event_info.gen.cc
+// gen_amalgamated expanded: #include "perfetto/protozero/gen_field_helpers.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/message.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/packed_repeated_fields.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/proto_decoder.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/scattered_heap_buffer.h"
+// DO NOT EDIT. Autogenerated by Perfetto cppgen_plugin
+#if defined(__GNUC__) || defined(__clang__)
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wfloat-equal"
+#endif
+// gen_amalgamated expanded: #include "protos/perfetto/trace/track_event/chrome_content_settings_event_info.gen.h"
-TrackEventDefaults::TrackEventDefaults() = default;
-TrackEventDefaults::~TrackEventDefaults() = default;
-TrackEventDefaults::TrackEventDefaults(const TrackEventDefaults&) = default;
-TrackEventDefaults& TrackEventDefaults::operator=(const TrackEventDefaults&) = default;
-TrackEventDefaults::TrackEventDefaults(TrackEventDefaults&&) noexcept = default;
-TrackEventDefaults& TrackEventDefaults::operator=(TrackEventDefaults&&) = default;
+namespace perfetto {
+namespace protos {
+namespace gen {
-bool TrackEventDefaults::operator==(const TrackEventDefaults& other) const {
+ChromeContentSettingsEventInfo::ChromeContentSettingsEventInfo() = default;
+ChromeContentSettingsEventInfo::~ChromeContentSettingsEventInfo() = default;
+ChromeContentSettingsEventInfo::ChromeContentSettingsEventInfo(const ChromeContentSettingsEventInfo&) = default;
+ChromeContentSettingsEventInfo& ChromeContentSettingsEventInfo::operator=(const ChromeContentSettingsEventInfo&) = default;
+ChromeContentSettingsEventInfo::ChromeContentSettingsEventInfo(ChromeContentSettingsEventInfo&&) noexcept = default;
+ChromeContentSettingsEventInfo& ChromeContentSettingsEventInfo::operator=(ChromeContentSettingsEventInfo&&) = default;
+
+bool ChromeContentSettingsEventInfo::operator==(const ChromeContentSettingsEventInfo& other) const {
return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
- && ::protozero::internal::gen_helpers::EqualsField(track_uuid_, other.track_uuid_)
- && ::protozero::internal::gen_helpers::EqualsField(extra_counter_track_uuids_, other.extra_counter_track_uuids_)
- && ::protozero::internal::gen_helpers::EqualsField(extra_double_counter_track_uuids_, other.extra_double_counter_track_uuids_);
+ && ::protozero::internal::gen_helpers::EqualsField(number_of_exceptions_, other.number_of_exceptions_);
}
-bool TrackEventDefaults::ParseFromArray(const void* raw, size_t size) {
- extra_counter_track_uuids_.clear();
- extra_double_counter_track_uuids_.clear();
+bool ChromeContentSettingsEventInfo::ParseFromArray(const void* raw, size_t size) {
unknown_fields_.clear();
bool packed_error = false;
@@ -37355,16 +37329,8 @@ bool TrackEventDefaults::ParseFromArray(const void* raw, size_t size) {
_has_field_.set(field.id());
}
switch (field.id()) {
- case 11 /* track_uuid */:
- field.get(&track_uuid_);
- break;
- case 31 /* extra_counter_track_uuids */:
- extra_counter_track_uuids_.emplace_back();
- field.get(&extra_counter_track_uuids_.back());
- break;
- case 45 /* extra_double_counter_track_uuids */:
- extra_double_counter_track_uuids_.emplace_back();
- field.get(&extra_double_counter_track_uuids_.back());
+ case 1 /* number_of_exceptions */:
+ field.get(&number_of_exceptions_);
break;
default:
field.SerializeAndAppendTo(&unknown_fields_);
@@ -37374,113 +37340,81 @@ bool TrackEventDefaults::ParseFromArray(const void* raw, size_t size) {
return !packed_error && !dec.bytes_left();
}
-std::string TrackEventDefaults::SerializeAsString() const {
+std::string ChromeContentSettingsEventInfo::SerializeAsString() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsString();
}
-std::vector<uint8_t> TrackEventDefaults::SerializeAsArray() const {
+std::vector<uint8_t> ChromeContentSettingsEventInfo::SerializeAsArray() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsArray();
}
-void TrackEventDefaults::Serialize(::protozero::Message* msg) const {
- // Field 11: track_uuid
- if (_has_field_[11]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(11, track_uuid_, msg);
- }
-
- // Field 31: extra_counter_track_uuids
- for (auto& it : extra_counter_track_uuids_) {
- ::protozero::internal::gen_helpers::SerializeVarInt(31, it, msg);
- }
-
- // Field 45: extra_double_counter_track_uuids
- for (auto& it : extra_double_counter_track_uuids_) {
- ::protozero::internal::gen_helpers::SerializeVarInt(45, it, msg);
+void ChromeContentSettingsEventInfo::Serialize(::protozero::Message* msg) const {
+ // Field 1: number_of_exceptions
+ if (_has_field_[1]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(1, number_of_exceptions_, msg);
}
protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
}
+} // namespace perfetto
+} // namespace protos
+} // namespace gen
+#if defined(__GNUC__) || defined(__clang__)
+#pragma GCC diagnostic pop
+#endif
+// gen_amalgamated begin source: gen/protos/perfetto/trace/track_event/chrome_frame_reporter.gen.cc
+// gen_amalgamated expanded: #include "perfetto/protozero/gen_field_helpers.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/message.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/packed_repeated_fields.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/proto_decoder.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/scattered_heap_buffer.h"
+// DO NOT EDIT. Autogenerated by Perfetto cppgen_plugin
+#if defined(__GNUC__) || defined(__clang__)
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wfloat-equal"
+#endif
+// gen_amalgamated expanded: #include "protos/perfetto/trace/track_event/chrome_frame_reporter.gen.h"
+
+namespace perfetto {
+namespace protos {
+namespace gen {
-TrackEvent::TrackEvent() = default;
-TrackEvent::~TrackEvent() = default;
-TrackEvent::TrackEvent(const TrackEvent&) = default;
-TrackEvent& TrackEvent::operator=(const TrackEvent&) = default;
-TrackEvent::TrackEvent(TrackEvent&&) noexcept = default;
-TrackEvent& TrackEvent::operator=(TrackEvent&&) = default;
+ChromeFrameReporter::ChromeFrameReporter() = default;
+ChromeFrameReporter::~ChromeFrameReporter() = default;
+ChromeFrameReporter::ChromeFrameReporter(const ChromeFrameReporter&) = default;
+ChromeFrameReporter& ChromeFrameReporter::operator=(const ChromeFrameReporter&) = default;
+ChromeFrameReporter::ChromeFrameReporter(ChromeFrameReporter&&) noexcept = default;
+ChromeFrameReporter& ChromeFrameReporter::operator=(ChromeFrameReporter&&) = default;
-bool TrackEvent::operator==(const TrackEvent& other) const {
+bool ChromeFrameReporter::operator==(const ChromeFrameReporter& other) const {
return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
- && ::protozero::internal::gen_helpers::EqualsField(category_iids_, other.category_iids_)
- && ::protozero::internal::gen_helpers::EqualsField(categories_, other.categories_)
- && ::protozero::internal::gen_helpers::EqualsField(name_iid_, other.name_iid_)
- && ::protozero::internal::gen_helpers::EqualsField(name_, other.name_)
- && ::protozero::internal::gen_helpers::EqualsField(type_, other.type_)
- && ::protozero::internal::gen_helpers::EqualsField(track_uuid_, other.track_uuid_)
- && ::protozero::internal::gen_helpers::EqualsField(counter_value_, other.counter_value_)
- && ::protozero::internal::gen_helpers::EqualsField(double_counter_value_, other.double_counter_value_)
- && ::protozero::internal::gen_helpers::EqualsField(extra_counter_track_uuids_, other.extra_counter_track_uuids_)
- && ::protozero::internal::gen_helpers::EqualsField(extra_counter_values_, other.extra_counter_values_)
- && ::protozero::internal::gen_helpers::EqualsField(extra_double_counter_track_uuids_, other.extra_double_counter_track_uuids_)
- && ::protozero::internal::gen_helpers::EqualsField(extra_double_counter_values_, other.extra_double_counter_values_)
- && ::protozero::internal::gen_helpers::EqualsField(flow_ids_old_, other.flow_ids_old_)
- && ::protozero::internal::gen_helpers::EqualsField(flow_ids_, other.flow_ids_)
- && ::protozero::internal::gen_helpers::EqualsField(terminating_flow_ids_old_, other.terminating_flow_ids_old_)
- && ::protozero::internal::gen_helpers::EqualsField(terminating_flow_ids_, other.terminating_flow_ids_)
- && ::protozero::internal::gen_helpers::EqualsField(correlation_id_, other.correlation_id_)
- && ::protozero::internal::gen_helpers::EqualsField(correlation_id_str_, other.correlation_id_str_)
- && ::protozero::internal::gen_helpers::EqualsField(correlation_id_str_iid_, other.correlation_id_str_iid_)
- && ::protozero::internal::gen_helpers::EqualsField(callstack_, other.callstack_)
- && ::protozero::internal::gen_helpers::EqualsField(callstack_iid_, other.callstack_iid_)
- && ::protozero::internal::gen_helpers::EqualsField(callstack_weight_, other.callstack_weight_)
- && ::protozero::internal::gen_helpers::EqualsField(debug_annotations_, other.debug_annotations_)
- && ::protozero::internal::gen_helpers::EqualsField(task_execution_, other.task_execution_)
- && ::protozero::internal::gen_helpers::EqualsField(log_message_, other.log_message_)
- && ::protozero::internal::gen_helpers::EqualsField(cc_scheduler_state_, other.cc_scheduler_state_)
- && ::protozero::internal::gen_helpers::EqualsField(chrome_user_event_, other.chrome_user_event_)
- && ::protozero::internal::gen_helpers::EqualsField(chrome_keyed_service_, other.chrome_keyed_service_)
- && ::protozero::internal::gen_helpers::EqualsField(chrome_legacy_ipc_, other.chrome_legacy_ipc_)
- && ::protozero::internal::gen_helpers::EqualsField(chrome_histogram_sample_, other.chrome_histogram_sample_)
- && ::protozero::internal::gen_helpers::EqualsField(chrome_latency_info_, other.chrome_latency_info_)
- && ::protozero::internal::gen_helpers::EqualsField(chrome_frame_reporter_, other.chrome_frame_reporter_)
- && ::protozero::internal::gen_helpers::EqualsField(chrome_application_state_info_, other.chrome_application_state_info_)
- && ::protozero::internal::gen_helpers::EqualsField(chrome_renderer_scheduler_state_, other.chrome_renderer_scheduler_state_)
- && ::protozero::internal::gen_helpers::EqualsField(chrome_window_handle_event_info_, other.chrome_window_handle_event_info_)
- && ::protozero::internal::gen_helpers::EqualsField(chrome_content_settings_event_info_, other.chrome_content_settings_event_info_)
- && ::protozero::internal::gen_helpers::EqualsField(chrome_active_processes_, other.chrome_active_processes_)
- && ::protozero::internal::gen_helpers::EqualsField(screenshot_, other.screenshot_)
- && ::protozero::internal::gen_helpers::EqualsField(source_location_, other.source_location_)
- && ::protozero::internal::gen_helpers::EqualsField(source_location_iid_, other.source_location_iid_)
- && ::protozero::internal::gen_helpers::EqualsField(chrome_message_pump_, other.chrome_message_pump_)
- && ::protozero::internal::gen_helpers::EqualsField(chrome_mojo_event_info_, other.chrome_mojo_event_info_)
- && ::protozero::internal::gen_helpers::EqualsField(timestamp_delta_us_, other.timestamp_delta_us_)
- && ::protozero::internal::gen_helpers::EqualsField(timestamp_absolute_us_, other.timestamp_absolute_us_)
- && ::protozero::internal::gen_helpers::EqualsField(thread_time_delta_us_, other.thread_time_delta_us_)
- && ::protozero::internal::gen_helpers::EqualsField(thread_time_absolute_us_, other.thread_time_absolute_us_)
- && ::protozero::internal::gen_helpers::EqualsField(thread_instruction_count_delta_, other.thread_instruction_count_delta_)
- && ::protozero::internal::gen_helpers::EqualsField(thread_instruction_count_absolute_, other.thread_instruction_count_absolute_)
- && ::protozero::internal::gen_helpers::EqualsField(legacy_event_, other.legacy_event_);
+ && ::protozero::internal::gen_helpers::EqualsField(state_, other.state_)
+ && ::protozero::internal::gen_helpers::EqualsField(reason_, other.reason_)
+ && ::protozero::internal::gen_helpers::EqualsField(frame_source_, other.frame_source_)
+ && ::protozero::internal::gen_helpers::EqualsField(frame_sequence_, other.frame_sequence_)
+ && ::protozero::internal::gen_helpers::EqualsField(affects_smoothness_, other.affects_smoothness_)
+ && ::protozero::internal::gen_helpers::EqualsField(scroll_state_, other.scroll_state_)
+ && ::protozero::internal::gen_helpers::EqualsField(has_main_animation_, other.has_main_animation_)
+ && ::protozero::internal::gen_helpers::EqualsField(has_compositor_animation_, other.has_compositor_animation_)
+ && ::protozero::internal::gen_helpers::EqualsField(has_smooth_input_main_, other.has_smooth_input_main_)
+ && ::protozero::internal::gen_helpers::EqualsField(has_missing_content_, other.has_missing_content_)
+ && ::protozero::internal::gen_helpers::EqualsField(layer_tree_host_id_, other.layer_tree_host_id_)
+ && ::protozero::internal::gen_helpers::EqualsField(has_high_latency_, other.has_high_latency_)
+ && ::protozero::internal::gen_helpers::EqualsField(frame_type_, other.frame_type_)
+ && ::protozero::internal::gen_helpers::EqualsField(high_latency_contribution_stage_, other.high_latency_contribution_stage_)
+ && ::protozero::internal::gen_helpers::EqualsField(checkerboarded_needs_raster_, other.checkerboarded_needs_raster_)
+ && ::protozero::internal::gen_helpers::EqualsField(checkerboarded_needs_record_, other.checkerboarded_needs_record_)
+ && ::protozero::internal::gen_helpers::EqualsField(surface_frame_trace_id_, other.surface_frame_trace_id_)
+ && ::protozero::internal::gen_helpers::EqualsField(display_trace_id_, other.display_trace_id_);
}
-int TrackEvent::debug_annotations_size() const { return static_cast<int>(debug_annotations_.size()); }
-void TrackEvent::clear_debug_annotations() { debug_annotations_.clear(); }
-DebugAnnotation* TrackEvent::add_debug_annotations() { debug_annotations_.emplace_back(); return &debug_annotations_.back(); }
-bool TrackEvent::ParseFromArray(const void* raw, size_t size) {
- category_iids_.clear();
- categories_.clear();
- extra_counter_track_uuids_.clear();
- extra_counter_values_.clear();
- extra_double_counter_track_uuids_.clear();
- extra_double_counter_values_.clear();
- flow_ids_old_.clear();
- flow_ids_.clear();
- terminating_flow_ids_old_.clear();
- terminating_flow_ids_.clear();
- debug_annotations_.clear();
+bool ChromeFrameReporter::ParseFromArray(const void* raw, size_t size) {
+ high_latency_contribution_stage_.clear();
unknown_fields_.clear();
bool packed_error = false;
@@ -37490,163 +37424,60 @@ bool TrackEvent::ParseFromArray(const void* raw, size_t size) {
_has_field_.set(field.id());
}
switch (field.id()) {
- case 3 /* category_iids */:
- category_iids_.emplace_back();
- field.get(&category_iids_.back());
- break;
- case 22 /* categories */:
- categories_.emplace_back();
- ::protozero::internal::gen_helpers::DeserializeString(field, &categories_.back());
- break;
- case 10 /* name_iid */:
- field.get(&name_iid_);
- break;
- case 23 /* name */:
- ::protozero::internal::gen_helpers::DeserializeString(field, &name_);
- break;
- case 9 /* type */:
- field.get(&type_);
- break;
- case 11 /* track_uuid */:
- field.get(&track_uuid_);
- break;
- case 30 /* counter_value */:
- field.get(&counter_value_);
- break;
- case 44 /* double_counter_value */:
- field.get(&double_counter_value_);
- break;
- case 31 /* extra_counter_track_uuids */:
- extra_counter_track_uuids_.emplace_back();
- field.get(&extra_counter_track_uuids_.back());
- break;
- case 12 /* extra_counter_values */:
- extra_counter_values_.emplace_back();
- field.get(&extra_counter_values_.back());
- break;
- case 45 /* extra_double_counter_track_uuids */:
- extra_double_counter_track_uuids_.emplace_back();
- field.get(&extra_double_counter_track_uuids_.back());
- break;
- case 46 /* extra_double_counter_values */:
- extra_double_counter_values_.emplace_back();
- field.get(&extra_double_counter_values_.back());
- break;
- case 36 /* flow_ids_old */:
- flow_ids_old_.emplace_back();
- field.get(&flow_ids_old_.back());
- break;
- case 47 /* flow_ids */:
- flow_ids_.emplace_back();
- field.get(&flow_ids_.back());
- break;
- case 42 /* terminating_flow_ids_old */:
- terminating_flow_ids_old_.emplace_back();
- field.get(&terminating_flow_ids_old_.back());
- break;
- case 48 /* terminating_flow_ids */:
- terminating_flow_ids_.emplace_back();
- field.get(&terminating_flow_ids_.back());
- break;
- case 52 /* correlation_id */:
- field.get(&correlation_id_);
- break;
- case 53 /* correlation_id_str */:
- ::protozero::internal::gen_helpers::DeserializeString(field, &correlation_id_str_);
- break;
- case 54 /* correlation_id_str_iid */:
- field.get(&correlation_id_str_iid_);
- break;
- case 55 /* callstack */:
- (*callstack_).ParseFromArray(field.data(), field.size());
- break;
- case 56 /* callstack_iid */:
- field.get(&callstack_iid_);
- break;
- case 57 /* callstack_weight */:
- field.get(&callstack_weight_);
- break;
- case 4 /* debug_annotations */:
- debug_annotations_.emplace_back();
- debug_annotations_.back().ParseFromArray(field.data(), field.size());
- break;
- case 5 /* task_execution */:
- (*task_execution_).ParseFromArray(field.data(), field.size());
- break;
- case 21 /* log_message */:
- (*log_message_).ParseFromArray(field.data(), field.size());
- break;
- case 24 /* cc_scheduler_state */:
- (*cc_scheduler_state_).ParseFromArray(field.data(), field.size());
- break;
- case 25 /* chrome_user_event */:
- (*chrome_user_event_).ParseFromArray(field.data(), field.size());
- break;
- case 26 /* chrome_keyed_service */:
- (*chrome_keyed_service_).ParseFromArray(field.data(), field.size());
- break;
- case 27 /* chrome_legacy_ipc */:
- (*chrome_legacy_ipc_).ParseFromArray(field.data(), field.size());
- break;
- case 28 /* chrome_histogram_sample */:
- (*chrome_histogram_sample_).ParseFromArray(field.data(), field.size());
- break;
- case 29 /* chrome_latency_info */:
- (*chrome_latency_info_).ParseFromArray(field.data(), field.size());
- break;
- case 32 /* chrome_frame_reporter */:
- (*chrome_frame_reporter_).ParseFromArray(field.data(), field.size());
+ case 1 /* state */:
+ field.get(&state_);
break;
- case 39 /* chrome_application_state_info */:
- (*chrome_application_state_info_).ParseFromArray(field.data(), field.size());
+ case 2 /* reason */:
+ field.get(&reason_);
break;
- case 40 /* chrome_renderer_scheduler_state */:
- (*chrome_renderer_scheduler_state_).ParseFromArray(field.data(), field.size());
+ case 3 /* frame_source */:
+ field.get(&frame_source_);
break;
- case 41 /* chrome_window_handle_event_info */:
- (*chrome_window_handle_event_info_).ParseFromArray(field.data(), field.size());
+ case 4 /* frame_sequence */:
+ field.get(&frame_sequence_);
break;
- case 43 /* chrome_content_settings_event_info */:
- (*chrome_content_settings_event_info_).ParseFromArray(field.data(), field.size());
+ case 5 /* affects_smoothness */:
+ field.get(&affects_smoothness_);
break;
- case 49 /* chrome_active_processes */:
- (*chrome_active_processes_).ParseFromArray(field.data(), field.size());
+ case 6 /* scroll_state */:
+ field.get(&scroll_state_);
break;
- case 50 /* screenshot */:
- (*screenshot_).ParseFromArray(field.data(), field.size());
+ case 7 /* has_main_animation */:
+ field.get(&has_main_animation_);
break;
- case 33 /* source_location */:
- (*source_location_).ParseFromArray(field.data(), field.size());
+ case 8 /* has_compositor_animation */:
+ field.get(&has_compositor_animation_);
break;
- case 34 /* source_location_iid */:
- field.get(&source_location_iid_);
+ case 9 /* has_smooth_input_main */:
+ field.get(&has_smooth_input_main_);
break;
- case 35 /* chrome_message_pump */:
- (*chrome_message_pump_).ParseFromArray(field.data(), field.size());
+ case 10 /* has_missing_content */:
+ field.get(&has_missing_content_);
break;
- case 38 /* chrome_mojo_event_info */:
- (*chrome_mojo_event_info_).ParseFromArray(field.data(), field.size());
+ case 11 /* layer_tree_host_id */:
+ field.get(&layer_tree_host_id_);
break;
- case 1 /* timestamp_delta_us */:
- field.get(×tamp_delta_us_);
+ case 12 /* has_high_latency */:
+ field.get(&has_high_latency_);
break;
- case 16 /* timestamp_absolute_us */:
- field.get(×tamp_absolute_us_);
+ case 13 /* frame_type */:
+ field.get(&frame_type_);
break;
- case 2 /* thread_time_delta_us */:
- field.get(&thread_time_delta_us_);
+ case 14 /* high_latency_contribution_stage */:
+ high_latency_contribution_stage_.emplace_back();
+ ::protozero::internal::gen_helpers::DeserializeString(field, &high_latency_contribution_stage_.back());
break;
- case 17 /* thread_time_absolute_us */:
- field.get(&thread_time_absolute_us_);
+ case 15 /* checkerboarded_needs_raster */:
+ field.get(&checkerboarded_needs_raster_);
break;
- case 8 /* thread_instruction_count_delta */:
- field.get(&thread_instruction_count_delta_);
+ case 16 /* checkerboarded_needs_record */:
+ field.get(&checkerboarded_needs_record_);
break;
- case 20 /* thread_instruction_count_absolute */:
- field.get(&thread_instruction_count_absolute_);
+ case 17 /* surface_frame_trace_id */:
+ field.get(&surface_frame_trace_id_);
break;
- case 6 /* legacy_event */:
- (*legacy_event_).ParseFromArray(field.data(), field.size());
+ case 18 /* display_trace_id */:
+ field.get(&display_trace_id_);
break;
default:
field.SerializeAndAppendTo(&unknown_fields_);
@@ -37656,296 +37487,404 @@ bool TrackEvent::ParseFromArray(const void* raw, size_t size) {
return !packed_error && !dec.bytes_left();
}
-std::string TrackEvent::SerializeAsString() const {
+std::string ChromeFrameReporter::SerializeAsString() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsString();
}
-std::vector<uint8_t> TrackEvent::SerializeAsArray() const {
+std::vector<uint8_t> ChromeFrameReporter::SerializeAsArray() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsArray();
}
-void TrackEvent::Serialize(::protozero::Message* msg) const {
- // Field 3: category_iids
- for (auto& it : category_iids_) {
- ::protozero::internal::gen_helpers::SerializeVarInt(3, it, msg);
- }
-
- // Field 22: categories
- for (auto& it : categories_) {
- ::protozero::internal::gen_helpers::SerializeString(22, it, msg);
- }
-
- // Field 10: name_iid
- if (_has_field_[10]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(10, name_iid_, msg);
+void ChromeFrameReporter::Serialize(::protozero::Message* msg) const {
+ // Field 1: state
+ if (_has_field_[1]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(1, state_, msg);
}
- // Field 23: name
- if (_has_field_[23]) {
- ::protozero::internal::gen_helpers::SerializeString(23, name_, msg);
+ // Field 2: reason
+ if (_has_field_[2]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(2, reason_, msg);
}
- // Field 9: type
- if (_has_field_[9]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(9, type_, msg);
+ // Field 3: frame_source
+ if (_has_field_[3]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(3, frame_source_, msg);
}
- // Field 11: track_uuid
- if (_has_field_[11]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(11, track_uuid_, msg);
+ // Field 4: frame_sequence
+ if (_has_field_[4]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(4, frame_sequence_, msg);
}
- // Field 30: counter_value
- if (_has_field_[30]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(30, counter_value_, msg);
+ // Field 5: affects_smoothness
+ if (_has_field_[5]) {
+ ::protozero::internal::gen_helpers::SerializeTinyVarInt(5, affects_smoothness_, msg);
}
- // Field 44: double_counter_value
- if (_has_field_[44]) {
- ::protozero::internal::gen_helpers::SerializeFixed(44, double_counter_value_, msg);
+ // Field 6: scroll_state
+ if (_has_field_[6]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(6, scroll_state_, msg);
}
- // Field 31: extra_counter_track_uuids
- for (auto& it : extra_counter_track_uuids_) {
- ::protozero::internal::gen_helpers::SerializeVarInt(31, it, msg);
+ // Field 7: has_main_animation
+ if (_has_field_[7]) {
+ ::protozero::internal::gen_helpers::SerializeTinyVarInt(7, has_main_animation_, msg);
}
- // Field 12: extra_counter_values
- for (auto& it : extra_counter_values_) {
- ::protozero::internal::gen_helpers::SerializeVarInt(12, it, msg);
+ // Field 8: has_compositor_animation
+ if (_has_field_[8]) {
+ ::protozero::internal::gen_helpers::SerializeTinyVarInt(8, has_compositor_animation_, msg);
}
- // Field 45: extra_double_counter_track_uuids
- for (auto& it : extra_double_counter_track_uuids_) {
- ::protozero::internal::gen_helpers::SerializeVarInt(45, it, msg);
+ // Field 9: has_smooth_input_main
+ if (_has_field_[9]) {
+ ::protozero::internal::gen_helpers::SerializeTinyVarInt(9, has_smooth_input_main_, msg);
}
- // Field 46: extra_double_counter_values
- for (auto& it : extra_double_counter_values_) {
- ::protozero::internal::gen_helpers::SerializeFixed(46, it, msg);
+ // Field 10: has_missing_content
+ if (_has_field_[10]) {
+ ::protozero::internal::gen_helpers::SerializeTinyVarInt(10, has_missing_content_, msg);
}
- // Field 36: flow_ids_old
- for (auto& it : flow_ids_old_) {
- ::protozero::internal::gen_helpers::SerializeVarInt(36, it, msg);
+ // Field 11: layer_tree_host_id
+ if (_has_field_[11]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(11, layer_tree_host_id_, msg);
}
- // Field 47: flow_ids
- for (auto& it : flow_ids_) {
- ::protozero::internal::gen_helpers::SerializeFixed(47, it, msg);
+ // Field 12: has_high_latency
+ if (_has_field_[12]) {
+ ::protozero::internal::gen_helpers::SerializeTinyVarInt(12, has_high_latency_, msg);
}
- // Field 42: terminating_flow_ids_old
- for (auto& it : terminating_flow_ids_old_) {
- ::protozero::internal::gen_helpers::SerializeVarInt(42, it, msg);
+ // Field 13: frame_type
+ if (_has_field_[13]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(13, frame_type_, msg);
}
- // Field 48: terminating_flow_ids
- for (auto& it : terminating_flow_ids_) {
- ::protozero::internal::gen_helpers::SerializeFixed(48, it, msg);
+ // Field 14: high_latency_contribution_stage
+ for (auto& it : high_latency_contribution_stage_) {
+ ::protozero::internal::gen_helpers::SerializeString(14, it, msg);
}
- // Field 52: correlation_id
- if (_has_field_[52]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(52, correlation_id_, msg);
+ // Field 15: checkerboarded_needs_raster
+ if (_has_field_[15]) {
+ ::protozero::internal::gen_helpers::SerializeTinyVarInt(15, checkerboarded_needs_raster_, msg);
}
- // Field 53: correlation_id_str
- if (_has_field_[53]) {
- ::protozero::internal::gen_helpers::SerializeString(53, correlation_id_str_, msg);
+ // Field 16: checkerboarded_needs_record
+ if (_has_field_[16]) {
+ ::protozero::internal::gen_helpers::SerializeTinyVarInt(16, checkerboarded_needs_record_, msg);
}
- // Field 54: correlation_id_str_iid
- if (_has_field_[54]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(54, correlation_id_str_iid_, msg);
+ // Field 17: surface_frame_trace_id
+ if (_has_field_[17]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(17, surface_frame_trace_id_, msg);
}
- // Field 55: callstack
- if (_has_field_[55]) {
- (*callstack_).Serialize(msg->BeginNestedMessage<::protozero::Message>(55));
+ // Field 18: display_trace_id
+ if (_has_field_[18]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(18, display_trace_id_, msg);
}
- // Field 56: callstack_iid
- if (_has_field_[56]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(56, callstack_iid_, msg);
- }
+ protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
+}
- // Field 57: callstack_weight
- if (_has_field_[57]) {
- ::protozero::internal::gen_helpers::SerializeFixed(57, callstack_weight_, msg);
- }
+} // namespace perfetto
+} // namespace protos
+} // namespace gen
+#if defined(__GNUC__) || defined(__clang__)
+#pragma GCC diagnostic pop
+#endif
+// gen_amalgamated begin source: gen/protos/perfetto/trace/track_event/chrome_histogram_sample.gen.cc
+// gen_amalgamated expanded: #include "perfetto/protozero/gen_field_helpers.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/message.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/packed_repeated_fields.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/proto_decoder.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/scattered_heap_buffer.h"
+// DO NOT EDIT. Autogenerated by Perfetto cppgen_plugin
+#if defined(__GNUC__) || defined(__clang__)
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wfloat-equal"
+#endif
+// gen_amalgamated expanded: #include "protos/perfetto/trace/track_event/chrome_histogram_sample.gen.h"
- // Field 4: debug_annotations
- for (auto& it : debug_annotations_) {
- it.Serialize(msg->BeginNestedMessage<::protozero::Message>(4));
- }
+namespace perfetto {
+namespace protos {
+namespace gen {
- // Field 5: task_execution
- if (_has_field_[5]) {
- (*task_execution_).Serialize(msg->BeginNestedMessage<::protozero::Message>(5));
- }
+ChromeHistogramSample::ChromeHistogramSample() = default;
+ChromeHistogramSample::~ChromeHistogramSample() = default;
+ChromeHistogramSample::ChromeHistogramSample(const ChromeHistogramSample&) = default;
+ChromeHistogramSample& ChromeHistogramSample::operator=(const ChromeHistogramSample&) = default;
+ChromeHistogramSample::ChromeHistogramSample(ChromeHistogramSample&&) noexcept = default;
+ChromeHistogramSample& ChromeHistogramSample::operator=(ChromeHistogramSample&&) = default;
- // Field 21: log_message
- if (_has_field_[21]) {
- (*log_message_).Serialize(msg->BeginNestedMessage<::protozero::Message>(21));
- }
+bool ChromeHistogramSample::operator==(const ChromeHistogramSample& other) const {
+ return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
+ && ::protozero::internal::gen_helpers::EqualsField(name_hash_, other.name_hash_)
+ && ::protozero::internal::gen_helpers::EqualsField(name_, other.name_)
+ && ::protozero::internal::gen_helpers::EqualsField(sample_, other.sample_)
+ && ::protozero::internal::gen_helpers::EqualsField(name_iid_, other.name_iid_);
+}
- // Field 24: cc_scheduler_state
- if (_has_field_[24]) {
- (*cc_scheduler_state_).Serialize(msg->BeginNestedMessage<::protozero::Message>(24));
- }
+bool ChromeHistogramSample::ParseFromArray(const void* raw, size_t size) {
+ unknown_fields_.clear();
+ bool packed_error = false;
- // Field 25: chrome_user_event
- if (_has_field_[25]) {
- (*chrome_user_event_).Serialize(msg->BeginNestedMessage<::protozero::Message>(25));
+ ::protozero::ProtoDecoder dec(raw, size);
+ for (auto field = dec.ReadField(); field.valid(); field = dec.ReadField()) {
+ if (field.id() < _has_field_.size()) {
+ _has_field_.set(field.id());
+ }
+ switch (field.id()) {
+ case 1 /* name_hash */:
+ field.get(&name_hash_);
+ break;
+ case 2 /* name */:
+ ::protozero::internal::gen_helpers::DeserializeString(field, &name_);
+ break;
+ case 3 /* sample */:
+ field.get(&sample_);
+ break;
+ case 4 /* name_iid */:
+ field.get(&name_iid_);
+ break;
+ default:
+ field.SerializeAndAppendTo(&unknown_fields_);
+ break;
+ }
}
+ return !packed_error && !dec.bytes_left();
+}
- // Field 26: chrome_keyed_service
- if (_has_field_[26]) {
- (*chrome_keyed_service_).Serialize(msg->BeginNestedMessage<::protozero::Message>(26));
- }
+std::string ChromeHistogramSample::SerializeAsString() const {
+ ::protozero::internal::gen_helpers::MessageSerializer msg;
+ Serialize(msg.get());
+ return msg.SerializeAsString();
+}
- // Field 27: chrome_legacy_ipc
- if (_has_field_[27]) {
- (*chrome_legacy_ipc_).Serialize(msg->BeginNestedMessage<::protozero::Message>(27));
- }
+std::vector<uint8_t> ChromeHistogramSample::SerializeAsArray() const {
+ ::protozero::internal::gen_helpers::MessageSerializer msg;
+ Serialize(msg.get());
+ return msg.SerializeAsArray();
+}
- // Field 28: chrome_histogram_sample
- if (_has_field_[28]) {
- (*chrome_histogram_sample_).Serialize(msg->BeginNestedMessage<::protozero::Message>(28));
+void ChromeHistogramSample::Serialize(::protozero::Message* msg) const {
+ // Field 1: name_hash
+ if (_has_field_[1]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(1, name_hash_, msg);
}
- // Field 29: chrome_latency_info
- if (_has_field_[29]) {
- (*chrome_latency_info_).Serialize(msg->BeginNestedMessage<::protozero::Message>(29));
+ // Field 2: name
+ if (_has_field_[2]) {
+ ::protozero::internal::gen_helpers::SerializeString(2, name_, msg);
}
- // Field 32: chrome_frame_reporter
- if (_has_field_[32]) {
- (*chrome_frame_reporter_).Serialize(msg->BeginNestedMessage<::protozero::Message>(32));
+ // Field 3: sample
+ if (_has_field_[3]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(3, sample_, msg);
}
- // Field 39: chrome_application_state_info
- if (_has_field_[39]) {
- (*chrome_application_state_info_).Serialize(msg->BeginNestedMessage<::protozero::Message>(39));
+ // Field 4: name_iid
+ if (_has_field_[4]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(4, name_iid_, msg);
}
- // Field 40: chrome_renderer_scheduler_state
- if (_has_field_[40]) {
- (*chrome_renderer_scheduler_state_).Serialize(msg->BeginNestedMessage<::protozero::Message>(40));
- }
+ protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
+}
- // Field 41: chrome_window_handle_event_info
- if (_has_field_[41]) {
- (*chrome_window_handle_event_info_).Serialize(msg->BeginNestedMessage<::protozero::Message>(41));
- }
- // Field 43: chrome_content_settings_event_info
- if (_has_field_[43]) {
- (*chrome_content_settings_event_info_).Serialize(msg->BeginNestedMessage<::protozero::Message>(43));
- }
+HistogramName::HistogramName() = default;
+HistogramName::~HistogramName() = default;
+HistogramName::HistogramName(const HistogramName&) = default;
+HistogramName& HistogramName::operator=(const HistogramName&) = default;
+HistogramName::HistogramName(HistogramName&&) noexcept = default;
+HistogramName& HistogramName::operator=(HistogramName&&) = default;
- // Field 49: chrome_active_processes
- if (_has_field_[49]) {
- (*chrome_active_processes_).Serialize(msg->BeginNestedMessage<::protozero::Message>(49));
- }
+bool HistogramName::operator==(const HistogramName& other) const {
+ return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
+ && ::protozero::internal::gen_helpers::EqualsField(iid_, other.iid_)
+ && ::protozero::internal::gen_helpers::EqualsField(name_, other.name_);
+}
- // Field 50: screenshot
- if (_has_field_[50]) {
- (*screenshot_).Serialize(msg->BeginNestedMessage<::protozero::Message>(50));
- }
+bool HistogramName::ParseFromArray(const void* raw, size_t size) {
+ unknown_fields_.clear();
+ bool packed_error = false;
- // Field 33: source_location
- if (_has_field_[33]) {
- (*source_location_).Serialize(msg->BeginNestedMessage<::protozero::Message>(33));
- }
-
- // Field 34: source_location_iid
- if (_has_field_[34]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(34, source_location_iid_, msg);
+ ::protozero::ProtoDecoder dec(raw, size);
+ for (auto field = dec.ReadField(); field.valid(); field = dec.ReadField()) {
+ if (field.id() < _has_field_.size()) {
+ _has_field_.set(field.id());
+ }
+ switch (field.id()) {
+ case 1 /* iid */:
+ field.get(&iid_);
+ break;
+ case 2 /* name */:
+ ::protozero::internal::gen_helpers::DeserializeString(field, &name_);
+ break;
+ default:
+ field.SerializeAndAppendTo(&unknown_fields_);
+ break;
+ }
}
+ return !packed_error && !dec.bytes_left();
+}
- // Field 35: chrome_message_pump
- if (_has_field_[35]) {
- (*chrome_message_pump_).Serialize(msg->BeginNestedMessage<::protozero::Message>(35));
- }
+std::string HistogramName::SerializeAsString() const {
+ ::protozero::internal::gen_helpers::MessageSerializer msg;
+ Serialize(msg.get());
+ return msg.SerializeAsString();
+}
- // Field 38: chrome_mojo_event_info
- if (_has_field_[38]) {
- (*chrome_mojo_event_info_).Serialize(msg->BeginNestedMessage<::protozero::Message>(38));
- }
+std::vector<uint8_t> HistogramName::SerializeAsArray() const {
+ ::protozero::internal::gen_helpers::MessageSerializer msg;
+ Serialize(msg.get());
+ return msg.SerializeAsArray();
+}
- // Field 1: timestamp_delta_us
+void HistogramName::Serialize(::protozero::Message* msg) const {
+ // Field 1: iid
if (_has_field_[1]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(1, timestamp_delta_us_, msg);
- }
-
- // Field 16: timestamp_absolute_us
- if (_has_field_[16]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(16, timestamp_absolute_us_, msg);
+ ::protozero::internal::gen_helpers::SerializeVarInt(1, iid_, msg);
}
- // Field 2: thread_time_delta_us
+ // Field 2: name
if (_has_field_[2]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(2, thread_time_delta_us_, msg);
+ ::protozero::internal::gen_helpers::SerializeString(2, name_, msg);
}
- // Field 17: thread_time_absolute_us
- if (_has_field_[17]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(17, thread_time_absolute_us_, msg);
- }
+ protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
+}
- // Field 8: thread_instruction_count_delta
- if (_has_field_[8]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(8, thread_instruction_count_delta_, msg);
- }
+} // namespace perfetto
+} // namespace protos
+} // namespace gen
+#if defined(__GNUC__) || defined(__clang__)
+#pragma GCC diagnostic pop
+#endif
+// gen_amalgamated begin source: gen/protos/perfetto/trace/track_event/chrome_keyed_service.gen.cc
+// gen_amalgamated expanded: #include "perfetto/protozero/gen_field_helpers.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/message.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/packed_repeated_fields.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/proto_decoder.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/scattered_heap_buffer.h"
+// DO NOT EDIT. Autogenerated by Perfetto cppgen_plugin
+#if defined(__GNUC__) || defined(__clang__)
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wfloat-equal"
+#endif
+// gen_amalgamated expanded: #include "protos/perfetto/trace/track_event/chrome_keyed_service.gen.h"
- // Field 20: thread_instruction_count_absolute
- if (_has_field_[20]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(20, thread_instruction_count_absolute_, msg);
+namespace perfetto {
+namespace protos {
+namespace gen {
+
+ChromeKeyedService::ChromeKeyedService() = default;
+ChromeKeyedService::~ChromeKeyedService() = default;
+ChromeKeyedService::ChromeKeyedService(const ChromeKeyedService&) = default;
+ChromeKeyedService& ChromeKeyedService::operator=(const ChromeKeyedService&) = default;
+ChromeKeyedService::ChromeKeyedService(ChromeKeyedService&&) noexcept = default;
+ChromeKeyedService& ChromeKeyedService::operator=(ChromeKeyedService&&) = default;
+
+bool ChromeKeyedService::operator==(const ChromeKeyedService& other) const {
+ return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
+ && ::protozero::internal::gen_helpers::EqualsField(name_, other.name_);
+}
+
+bool ChromeKeyedService::ParseFromArray(const void* raw, size_t size) {
+ unknown_fields_.clear();
+ bool packed_error = false;
+
+ ::protozero::ProtoDecoder dec(raw, size);
+ for (auto field = dec.ReadField(); field.valid(); field = dec.ReadField()) {
+ if (field.id() < _has_field_.size()) {
+ _has_field_.set(field.id());
+ }
+ switch (field.id()) {
+ case 1 /* name */:
+ ::protozero::internal::gen_helpers::DeserializeString(field, &name_);
+ break;
+ default:
+ field.SerializeAndAppendTo(&unknown_fields_);
+ break;
+ }
}
+ return !packed_error && !dec.bytes_left();
+}
- // Field 6: legacy_event
- if (_has_field_[6]) {
- (*legacy_event_).Serialize(msg->BeginNestedMessage<::protozero::Message>(6));
+std::string ChromeKeyedService::SerializeAsString() const {
+ ::protozero::internal::gen_helpers::MessageSerializer msg;
+ Serialize(msg.get());
+ return msg.SerializeAsString();
+}
+
+std::vector<uint8_t> ChromeKeyedService::SerializeAsArray() const {
+ ::protozero::internal::gen_helpers::MessageSerializer msg;
+ Serialize(msg.get());
+ return msg.SerializeAsArray();
+}
+
+void ChromeKeyedService::Serialize(::protozero::Message* msg) const {
+ // Field 1: name
+ if (_has_field_[1]) {
+ ::protozero::internal::gen_helpers::SerializeString(1, name_, msg);
}
protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
}
+} // namespace perfetto
+} // namespace protos
+} // namespace gen
+#if defined(__GNUC__) || defined(__clang__)
+#pragma GCC diagnostic pop
+#endif
+// gen_amalgamated begin source: gen/protos/perfetto/trace/track_event/chrome_latency_info.gen.cc
+// gen_amalgamated expanded: #include "perfetto/protozero/gen_field_helpers.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/message.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/packed_repeated_fields.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/proto_decoder.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/scattered_heap_buffer.h"
+// DO NOT EDIT. Autogenerated by Perfetto cppgen_plugin
+#if defined(__GNUC__) || defined(__clang__)
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wfloat-equal"
+#endif
+// gen_amalgamated expanded: #include "protos/perfetto/trace/track_event/chrome_latency_info.gen.h"
+
+namespace perfetto {
+namespace protos {
+namespace gen {
-TrackEvent_LegacyEvent::TrackEvent_LegacyEvent() = default;
-TrackEvent_LegacyEvent::~TrackEvent_LegacyEvent() = default;
-TrackEvent_LegacyEvent::TrackEvent_LegacyEvent(const TrackEvent_LegacyEvent&) = default;
-TrackEvent_LegacyEvent& TrackEvent_LegacyEvent::operator=(const TrackEvent_LegacyEvent&) = default;
-TrackEvent_LegacyEvent::TrackEvent_LegacyEvent(TrackEvent_LegacyEvent&&) noexcept = default;
-TrackEvent_LegacyEvent& TrackEvent_LegacyEvent::operator=(TrackEvent_LegacyEvent&&) = default;
+ChromeLatencyInfo::ChromeLatencyInfo() = default;
+ChromeLatencyInfo::~ChromeLatencyInfo() = default;
+ChromeLatencyInfo::ChromeLatencyInfo(const ChromeLatencyInfo&) = default;
+ChromeLatencyInfo& ChromeLatencyInfo::operator=(const ChromeLatencyInfo&) = default;
+ChromeLatencyInfo::ChromeLatencyInfo(ChromeLatencyInfo&&) noexcept = default;
+ChromeLatencyInfo& ChromeLatencyInfo::operator=(ChromeLatencyInfo&&) = default;
-bool TrackEvent_LegacyEvent::operator==(const TrackEvent_LegacyEvent& other) const {
+bool ChromeLatencyInfo::operator==(const ChromeLatencyInfo& other) const {
return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
- && ::protozero::internal::gen_helpers::EqualsField(name_iid_, other.name_iid_)
- && ::protozero::internal::gen_helpers::EqualsField(phase_, other.phase_)
- && ::protozero::internal::gen_helpers::EqualsField(duration_us_, other.duration_us_)
- && ::protozero::internal::gen_helpers::EqualsField(thread_duration_us_, other.thread_duration_us_)
- && ::protozero::internal::gen_helpers::EqualsField(thread_instruction_delta_, other.thread_instruction_delta_)
- && ::protozero::internal::gen_helpers::EqualsField(unscoped_id_, other.unscoped_id_)
- && ::protozero::internal::gen_helpers::EqualsField(local_id_, other.local_id_)
- && ::protozero::internal::gen_helpers::EqualsField(global_id_, other.global_id_)
- && ::protozero::internal::gen_helpers::EqualsField(id_scope_, other.id_scope_)
- && ::protozero::internal::gen_helpers::EqualsField(use_async_tts_, other.use_async_tts_)
- && ::protozero::internal::gen_helpers::EqualsField(bind_id_, other.bind_id_)
- && ::protozero::internal::gen_helpers::EqualsField(bind_to_enclosing_, other.bind_to_enclosing_)
- && ::protozero::internal::gen_helpers::EqualsField(flow_direction_, other.flow_direction_)
- && ::protozero::internal::gen_helpers::EqualsField(instant_event_scope_, other.instant_event_scope_)
- && ::protozero::internal::gen_helpers::EqualsField(pid_override_, other.pid_override_)
- && ::protozero::internal::gen_helpers::EqualsField(tid_override_, other.tid_override_);
+ && ::protozero::internal::gen_helpers::EqualsField(trace_id_, other.trace_id_)
+ && ::protozero::internal::gen_helpers::EqualsField(step_, other.step_)
+ && ::protozero::internal::gen_helpers::EqualsField(frame_tree_node_id_, other.frame_tree_node_id_)
+ && ::protozero::internal::gen_helpers::EqualsField(component_info_, other.component_info_)
+ && ::protozero::internal::gen_helpers::EqualsField(is_coalesced_, other.is_coalesced_)
+ && ::protozero::internal::gen_helpers::EqualsField(gesture_scroll_id_, other.gesture_scroll_id_)
+ && ::protozero::internal::gen_helpers::EqualsField(touch_id_, other.touch_id_)
+ && ::protozero::internal::gen_helpers::EqualsField(input_type_, other.input_type_);
}
-bool TrackEvent_LegacyEvent::ParseFromArray(const void* raw, size_t size) {
+int ChromeLatencyInfo::component_info_size() const { return static_cast<int>(component_info_.size()); }
+void ChromeLatencyInfo::clear_component_info() { component_info_.clear(); }
+ChromeLatencyInfo_ComponentInfo* ChromeLatencyInfo::add_component_info() { component_info_.emplace_back(); return &component_info_.back(); }
+bool ChromeLatencyInfo::ParseFromArray(const void* raw, size_t size) {
+ component_info_.clear();
unknown_fields_.clear();
bool packed_error = false;
@@ -37955,53 +37894,30 @@ bool TrackEvent_LegacyEvent::ParseFromArray(const void* raw, size_t size) {
_has_field_.set(field.id());
}
switch (field.id()) {
- case 1 /* name_iid */:
- field.get(&name_iid_);
- break;
- case 2 /* phase */:
- field.get(&phase_);
- break;
- case 3 /* duration_us */:
- field.get(&duration_us_);
- break;
- case 4 /* thread_duration_us */:
- field.get(&thread_duration_us_);
- break;
- case 15 /* thread_instruction_delta */:
- field.get(&thread_instruction_delta_);
- break;
- case 6 /* unscoped_id */:
- field.get(&unscoped_id_);
- break;
- case 10 /* local_id */:
- field.get(&local_id_);
- break;
- case 11 /* global_id */:
- field.get(&global_id_);
- break;
- case 7 /* id_scope */:
- ::protozero::internal::gen_helpers::DeserializeString(field, &id_scope_);
+ case 1 /* trace_id */:
+ field.get(&trace_id_);
break;
- case 9 /* use_async_tts */:
- field.get(&use_async_tts_);
+ case 2 /* step */:
+ field.get(&step_);
break;
- case 8 /* bind_id */:
- field.get(&bind_id_);
+ case 3 /* frame_tree_node_id */:
+ field.get(&frame_tree_node_id_);
break;
- case 12 /* bind_to_enclosing */:
- field.get(&bind_to_enclosing_);
+ case 4 /* component_info */:
+ component_info_.emplace_back();
+ component_info_.back().ParseFromArray(field.data(), field.size());
break;
- case 13 /* flow_direction */:
- field.get(&flow_direction_);
+ case 5 /* is_coalesced */:
+ field.get(&is_coalesced_);
break;
- case 14 /* instant_event_scope */:
- field.get(&instant_event_scope_);
+ case 6 /* gesture_scroll_id */:
+ field.get(&gesture_scroll_id_);
break;
- case 18 /* pid_override */:
- field.get(&pid_override_);
+ case 7 /* touch_id */:
+ field.get(&touch_id_);
break;
- case 19 /* tid_override */:
- field.get(&tid_override_);
+ case 8 /* input_type */:
+ field.get(&input_type_);
break;
default:
field.SerializeAndAppendTo(&unknown_fields_);
@@ -38011,120 +37927,77 @@ bool TrackEvent_LegacyEvent::ParseFromArray(const void* raw, size_t size) {
return !packed_error && !dec.bytes_left();
}
-std::string TrackEvent_LegacyEvent::SerializeAsString() const {
+std::string ChromeLatencyInfo::SerializeAsString() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsString();
}
-std::vector<uint8_t> TrackEvent_LegacyEvent::SerializeAsArray() const {
+std::vector<uint8_t> ChromeLatencyInfo::SerializeAsArray() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsArray();
}
-void TrackEvent_LegacyEvent::Serialize(::protozero::Message* msg) const {
- // Field 1: name_iid
+void ChromeLatencyInfo::Serialize(::protozero::Message* msg) const {
+ // Field 1: trace_id
if (_has_field_[1]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(1, name_iid_, msg);
+ ::protozero::internal::gen_helpers::SerializeVarInt(1, trace_id_, msg);
}
- // Field 2: phase
+ // Field 2: step
if (_has_field_[2]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(2, phase_, msg);
+ ::protozero::internal::gen_helpers::SerializeVarInt(2, step_, msg);
}
- // Field 3: duration_us
+ // Field 3: frame_tree_node_id
if (_has_field_[3]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(3, duration_us_, msg);
+ ::protozero::internal::gen_helpers::SerializeVarInt(3, frame_tree_node_id_, msg);
}
- // Field 4: thread_duration_us
- if (_has_field_[4]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(4, thread_duration_us_, msg);
+ // Field 4: component_info
+ for (auto& it : component_info_) {
+ it.Serialize(msg->BeginNestedMessage<::protozero::Message>(4));
}
- // Field 15: thread_instruction_delta
- if (_has_field_[15]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(15, thread_instruction_delta_, msg);
+ // Field 5: is_coalesced
+ if (_has_field_[5]) {
+ ::protozero::internal::gen_helpers::SerializeTinyVarInt(5, is_coalesced_, msg);
}
- // Field 6: unscoped_id
+ // Field 6: gesture_scroll_id
if (_has_field_[6]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(6, unscoped_id_, msg);
- }
-
- // Field 10: local_id
- if (_has_field_[10]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(10, local_id_, msg);
- }
-
- // Field 11: global_id
- if (_has_field_[11]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(11, global_id_, msg);
+ ::protozero::internal::gen_helpers::SerializeVarInt(6, gesture_scroll_id_, msg);
}
- // Field 7: id_scope
+ // Field 7: touch_id
if (_has_field_[7]) {
- ::protozero::internal::gen_helpers::SerializeString(7, id_scope_, msg);
- }
-
- // Field 9: use_async_tts
- if (_has_field_[9]) {
- ::protozero::internal::gen_helpers::SerializeTinyVarInt(9, use_async_tts_, msg);
+ ::protozero::internal::gen_helpers::SerializeVarInt(7, touch_id_, msg);
}
- // Field 8: bind_id
+ // Field 8: input_type
if (_has_field_[8]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(8, bind_id_, msg);
- }
-
- // Field 12: bind_to_enclosing
- if (_has_field_[12]) {
- ::protozero::internal::gen_helpers::SerializeTinyVarInt(12, bind_to_enclosing_, msg);
- }
-
- // Field 13: flow_direction
- if (_has_field_[13]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(13, flow_direction_, msg);
- }
-
- // Field 14: instant_event_scope
- if (_has_field_[14]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(14, instant_event_scope_, msg);
- }
-
- // Field 18: pid_override
- if (_has_field_[18]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(18, pid_override_, msg);
- }
-
- // Field 19: tid_override
- if (_has_field_[19]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(19, tid_override_, msg);
+ ::protozero::internal::gen_helpers::SerializeVarInt(8, input_type_, msg);
}
protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
}
-TrackEvent_InlineCallstack::TrackEvent_InlineCallstack() = default;
-TrackEvent_InlineCallstack::~TrackEvent_InlineCallstack() = default;
-TrackEvent_InlineCallstack::TrackEvent_InlineCallstack(const TrackEvent_InlineCallstack&) = default;
-TrackEvent_InlineCallstack& TrackEvent_InlineCallstack::operator=(const TrackEvent_InlineCallstack&) = default;
-TrackEvent_InlineCallstack::TrackEvent_InlineCallstack(TrackEvent_InlineCallstack&&) noexcept = default;
-TrackEvent_InlineCallstack& TrackEvent_InlineCallstack::operator=(TrackEvent_InlineCallstack&&) = default;
+ChromeLatencyInfo_ComponentInfo::ChromeLatencyInfo_ComponentInfo() = default;
+ChromeLatencyInfo_ComponentInfo::~ChromeLatencyInfo_ComponentInfo() = default;
+ChromeLatencyInfo_ComponentInfo::ChromeLatencyInfo_ComponentInfo(const ChromeLatencyInfo_ComponentInfo&) = default;
+ChromeLatencyInfo_ComponentInfo& ChromeLatencyInfo_ComponentInfo::operator=(const ChromeLatencyInfo_ComponentInfo&) = default;
+ChromeLatencyInfo_ComponentInfo::ChromeLatencyInfo_ComponentInfo(ChromeLatencyInfo_ComponentInfo&&) noexcept = default;
+ChromeLatencyInfo_ComponentInfo& ChromeLatencyInfo_ComponentInfo::operator=(ChromeLatencyInfo_ComponentInfo&&) = default;
-bool TrackEvent_InlineCallstack::operator==(const TrackEvent_InlineCallstack& other) const {
+bool ChromeLatencyInfo_ComponentInfo::operator==(const ChromeLatencyInfo_ComponentInfo& other) const {
return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
- && ::protozero::internal::gen_helpers::EqualsField(frames_, other.frames_);
+ && ::protozero::internal::gen_helpers::EqualsField(component_type_, other.component_type_)
+ && ::protozero::internal::gen_helpers::EqualsField(time_us_, other.time_us_);
}
-int TrackEvent_InlineCallstack::frames_size() const { return static_cast<int>(frames_.size()); }
-void TrackEvent_InlineCallstack::clear_frames() { frames_.clear(); }
-TrackEvent_InlineCallstack_Frame* TrackEvent_InlineCallstack::add_frames() { frames_.emplace_back(); return &frames_.back(); }
-bool TrackEvent_InlineCallstack::ParseFromArray(const void* raw, size_t size) {
- frames_.clear();
+bool ChromeLatencyInfo_ComponentInfo::ParseFromArray(const void* raw, size_t size) {
unknown_fields_.clear();
bool packed_error = false;
@@ -38134,9 +38007,11 @@ bool TrackEvent_InlineCallstack::ParseFromArray(const void* raw, size_t size) {
_has_field_.set(field.id());
}
switch (field.id()) {
- case 1 /* frames */:
- frames_.emplace_back();
- frames_.back().ParseFromArray(field.data(), field.size());
+ case 1 /* component_type */:
+ field.get(&component_type_);
+ break;
+ case 2 /* time_us */:
+ field.get(&time_us_);
break;
default:
field.SerializeAndAppendTo(&unknown_fields_);
@@ -38146,43 +38021,69 @@ bool TrackEvent_InlineCallstack::ParseFromArray(const void* raw, size_t size) {
return !packed_error && !dec.bytes_left();
}
-std::string TrackEvent_InlineCallstack::SerializeAsString() const {
+std::string ChromeLatencyInfo_ComponentInfo::SerializeAsString() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsString();
}
-std::vector<uint8_t> TrackEvent_InlineCallstack::SerializeAsArray() const {
+std::vector<uint8_t> ChromeLatencyInfo_ComponentInfo::SerializeAsArray() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsArray();
}
-void TrackEvent_InlineCallstack::Serialize(::protozero::Message* msg) const {
- // Field 1: frames
- for (auto& it : frames_) {
- it.Serialize(msg->BeginNestedMessage<::protozero::Message>(1));
+void ChromeLatencyInfo_ComponentInfo::Serialize(::protozero::Message* msg) const {
+ // Field 1: component_type
+ if (_has_field_[1]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(1, component_type_, msg);
+ }
+
+ // Field 2: time_us
+ if (_has_field_[2]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(2, time_us_, msg);
}
protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
}
+} // namespace perfetto
+} // namespace protos
+} // namespace gen
+#if defined(__GNUC__) || defined(__clang__)
+#pragma GCC diagnostic pop
+#endif
+// gen_amalgamated begin source: gen/protos/perfetto/trace/track_event/chrome_legacy_ipc.gen.cc
+// gen_amalgamated expanded: #include "perfetto/protozero/gen_field_helpers.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/message.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/packed_repeated_fields.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/proto_decoder.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/scattered_heap_buffer.h"
+// DO NOT EDIT. Autogenerated by Perfetto cppgen_plugin
+#if defined(__GNUC__) || defined(__clang__)
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wfloat-equal"
+#endif
+// gen_amalgamated expanded: #include "protos/perfetto/trace/track_event/chrome_legacy_ipc.gen.h"
-TrackEvent_InlineCallstack_Frame::TrackEvent_InlineCallstack_Frame() = default;
-TrackEvent_InlineCallstack_Frame::~TrackEvent_InlineCallstack_Frame() = default;
-TrackEvent_InlineCallstack_Frame::TrackEvent_InlineCallstack_Frame(const TrackEvent_InlineCallstack_Frame&) = default;
-TrackEvent_InlineCallstack_Frame& TrackEvent_InlineCallstack_Frame::operator=(const TrackEvent_InlineCallstack_Frame&) = default;
-TrackEvent_InlineCallstack_Frame::TrackEvent_InlineCallstack_Frame(TrackEvent_InlineCallstack_Frame&&) noexcept = default;
-TrackEvent_InlineCallstack_Frame& TrackEvent_InlineCallstack_Frame::operator=(TrackEvent_InlineCallstack_Frame&&) = default;
+namespace perfetto {
+namespace protos {
+namespace gen {
-bool TrackEvent_InlineCallstack_Frame::operator==(const TrackEvent_InlineCallstack_Frame& other) const {
+ChromeLegacyIpc::ChromeLegacyIpc() = default;
+ChromeLegacyIpc::~ChromeLegacyIpc() = default;
+ChromeLegacyIpc::ChromeLegacyIpc(const ChromeLegacyIpc&) = default;
+ChromeLegacyIpc& ChromeLegacyIpc::operator=(const ChromeLegacyIpc&) = default;
+ChromeLegacyIpc::ChromeLegacyIpc(ChromeLegacyIpc&&) noexcept = default;
+ChromeLegacyIpc& ChromeLegacyIpc::operator=(ChromeLegacyIpc&&) = default;
+
+bool ChromeLegacyIpc::operator==(const ChromeLegacyIpc& other) const {
return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
- && ::protozero::internal::gen_helpers::EqualsField(function_name_, other.function_name_)
- && ::protozero::internal::gen_helpers::EqualsField(source_file_, other.source_file_)
- && ::protozero::internal::gen_helpers::EqualsField(line_number_, other.line_number_);
+ && ::protozero::internal::gen_helpers::EqualsField(message_class_, other.message_class_)
+ && ::protozero::internal::gen_helpers::EqualsField(message_line_, other.message_line_);
}
-bool TrackEvent_InlineCallstack_Frame::ParseFromArray(const void* raw, size_t size) {
+bool ChromeLegacyIpc::ParseFromArray(const void* raw, size_t size) {
unknown_fields_.clear();
bool packed_error = false;
@@ -38192,14 +38093,11 @@ bool TrackEvent_InlineCallstack_Frame::ParseFromArray(const void* raw, size_t si
_has_field_.set(field.id());
}
switch (field.id()) {
- case 1 /* function_name */:
- ::protozero::internal::gen_helpers::DeserializeString(field, &function_name_);
- break;
- case 2 /* source_file */:
- ::protozero::internal::gen_helpers::DeserializeString(field, &source_file_);
+ case 1 /* message_class */:
+ field.get(&message_class_);
break;
- case 3 /* line_number */:
- field.get(&line_number_);
+ case 2 /* message_line */:
+ field.get(&message_line_);
break;
default:
field.SerializeAndAppendTo(&unknown_fields_);
@@ -38209,32 +38107,27 @@ bool TrackEvent_InlineCallstack_Frame::ParseFromArray(const void* raw, size_t si
return !packed_error && !dec.bytes_left();
}
-std::string TrackEvent_InlineCallstack_Frame::SerializeAsString() const {
+std::string ChromeLegacyIpc::SerializeAsString() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsString();
}
-std::vector<uint8_t> TrackEvent_InlineCallstack_Frame::SerializeAsArray() const {
+std::vector<uint8_t> ChromeLegacyIpc::SerializeAsArray() const {
::protozero::internal::gen_helpers::MessageSerializer msg;
Serialize(msg.get());
return msg.SerializeAsArray();
}
-void TrackEvent_InlineCallstack_Frame::Serialize(::protozero::Message* msg) const {
- // Field 1: function_name
+void ChromeLegacyIpc::Serialize(::protozero::Message* msg) const {
+ // Field 1: message_class
if (_has_field_[1]) {
- ::protozero::internal::gen_helpers::SerializeString(1, function_name_, msg);
+ ::protozero::internal::gen_helpers::SerializeVarInt(1, message_class_, msg);
}
- // Field 2: source_file
+ // Field 2: message_line
if (_has_field_[2]) {
- ::protozero::internal::gen_helpers::SerializeString(2, source_file_, msg);
- }
-
- // Field 3: line_number
- if (_has_field_[3]) {
- ::protozero::internal::gen_helpers::SerializeVarInt(3, line_number_, msg);
+ ::protozero::internal::gen_helpers::SerializeVarInt(2, message_line_, msg);
}
protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
@@ -38246,49 +38139,3637 @@ void TrackEvent_InlineCallstack_Frame::Serialize(::protozero::Message* msg) cons
#if defined(__GNUC__) || defined(__clang__)
#pragma GCC diagnostic pop
#endif
-// gen_amalgamated begin source: gen/protos/perfetto/common/semantic_type.pbzero.cc
-// Intentionally empty (crbug.com/998165)
-// gen_amalgamated begin source: gen/protos/perfetto/config/android/android_aflags_config.pbzero.cc
-// Intentionally empty (crbug.com/998165)
-// gen_amalgamated begin source: gen/protos/perfetto/config/android/android_game_intervention_list_config.pbzero.cc
-// Intentionally empty (crbug.com/998165)
-// gen_amalgamated begin source: gen/protos/perfetto/config/android/android_input_event_config.pbzero.cc
-// Intentionally empty (crbug.com/998165)
-// gen_amalgamated begin source: gen/protos/perfetto/config/android/android_log_config.pbzero.cc
-// Intentionally empty (crbug.com/998165)
-// gen_amalgamated begin source: gen/protos/perfetto/config/android/android_polled_state_config.pbzero.cc
-// Intentionally empty (crbug.com/998165)
-// gen_amalgamated begin source: gen/protos/perfetto/config/android/android_sdk_sysprop_guard_config.pbzero.cc
-// Intentionally empty (crbug.com/998165)
-// gen_amalgamated begin source: gen/protos/perfetto/config/android/android_system_property_config.pbzero.cc
-// Intentionally empty (crbug.com/998165)
-// gen_amalgamated begin source: gen/protos/perfetto/config/android/app_wakelock_config.pbzero.cc
-// Intentionally empty (crbug.com/998165)
-// gen_amalgamated begin source: gen/protos/perfetto/config/android/cpu_per_uid_config.pbzero.cc
-// Intentionally empty (crbug.com/998165)
-// gen_amalgamated begin source: gen/protos/perfetto/config/android/display_video_config.pbzero.cc
-// Intentionally empty (crbug.com/998165)
-// gen_amalgamated begin source: gen/protos/perfetto/config/android/inputmethod_config.pbzero.cc
-// Intentionally empty (crbug.com/998165)
-// gen_amalgamated begin source: gen/protos/perfetto/config/android/kernel_wakelocks_config.pbzero.cc
-// Intentionally empty (crbug.com/998165)
-// gen_amalgamated begin source: gen/protos/perfetto/config/android/network_trace_config.pbzero.cc
-// Intentionally empty (crbug.com/998165)
-// gen_amalgamated begin source: gen/protos/perfetto/config/android/packages_list_config.pbzero.cc
-// Intentionally empty (crbug.com/998165)
-// gen_amalgamated begin source: gen/protos/perfetto/config/android/pixel_modem_config.pbzero.cc
-// Intentionally empty (crbug.com/998165)
-// gen_amalgamated begin source: gen/protos/perfetto/config/android/protolog_config.pbzero.cc
-// Intentionally empty (crbug.com/998165)
-// gen_amalgamated begin source: gen/protos/perfetto/config/android/surfaceflinger_layers_config.pbzero.cc
-// Intentionally empty (crbug.com/998165)
-// gen_amalgamated begin source: gen/protos/perfetto/config/android/surfaceflinger_transactions_config.pbzero.cc
-// Intentionally empty (crbug.com/998165)
-// gen_amalgamated begin source: gen/protos/perfetto/config/android/user_list_config.pbzero.cc
-// Intentionally empty (crbug.com/998165)
-// gen_amalgamated begin source: gen/protos/perfetto/config/android/windowmanager_config.pbzero.cc
-// Intentionally empty (crbug.com/998165)
-// gen_amalgamated begin source: gen/protos/perfetto/config/ftrace/frozen_ftrace_config.pbzero.cc
+// gen_amalgamated begin source: gen/protos/perfetto/trace/track_event/chrome_message_pump.gen.cc
+// gen_amalgamated expanded: #include "perfetto/protozero/gen_field_helpers.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/message.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/packed_repeated_fields.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/proto_decoder.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/scattered_heap_buffer.h"
+// DO NOT EDIT. Autogenerated by Perfetto cppgen_plugin
+#if defined(__GNUC__) || defined(__clang__)
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wfloat-equal"
+#endif
+// gen_amalgamated expanded: #include "protos/perfetto/trace/track_event/chrome_message_pump.gen.h"
+
+namespace perfetto {
+namespace protos {
+namespace gen {
+
+ChromeMessagePump::ChromeMessagePump() = default;
+ChromeMessagePump::~ChromeMessagePump() = default;
+ChromeMessagePump::ChromeMessagePump(const ChromeMessagePump&) = default;
+ChromeMessagePump& ChromeMessagePump::operator=(const ChromeMessagePump&) = default;
+ChromeMessagePump::ChromeMessagePump(ChromeMessagePump&&) noexcept = default;
+ChromeMessagePump& ChromeMessagePump::operator=(ChromeMessagePump&&) = default;
+
+bool ChromeMessagePump::operator==(const ChromeMessagePump& other) const {
+ return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
+ && ::protozero::internal::gen_helpers::EqualsField(sent_messages_in_queue_, other.sent_messages_in_queue_)
+ && ::protozero::internal::gen_helpers::EqualsField(io_handler_location_iid_, other.io_handler_location_iid_);
+}
+
+bool ChromeMessagePump::ParseFromArray(const void* raw, size_t size) {
+ unknown_fields_.clear();
+ bool packed_error = false;
+
+ ::protozero::ProtoDecoder dec(raw, size);
+ for (auto field = dec.ReadField(); field.valid(); field = dec.ReadField()) {
+ if (field.id() < _has_field_.size()) {
+ _has_field_.set(field.id());
+ }
+ switch (field.id()) {
+ case 1 /* sent_messages_in_queue */:
+ field.get(&sent_messages_in_queue_);
+ break;
+ case 2 /* io_handler_location_iid */:
+ field.get(&io_handler_location_iid_);
+ break;
+ default:
+ field.SerializeAndAppendTo(&unknown_fields_);
+ break;
+ }
+ }
+ return !packed_error && !dec.bytes_left();
+}
+
+std::string ChromeMessagePump::SerializeAsString() const {
+ ::protozero::internal::gen_helpers::MessageSerializer msg;
+ Serialize(msg.get());
+ return msg.SerializeAsString();
+}
+
+std::vector<uint8_t> ChromeMessagePump::SerializeAsArray() const {
+ ::protozero::internal::gen_helpers::MessageSerializer msg;
+ Serialize(msg.get());
+ return msg.SerializeAsArray();
+}
+
+void ChromeMessagePump::Serialize(::protozero::Message* msg) const {
+ // Field 1: sent_messages_in_queue
+ if (_has_field_[1]) {
+ ::protozero::internal::gen_helpers::SerializeTinyVarInt(1, sent_messages_in_queue_, msg);
+ }
+
+ // Field 2: io_handler_location_iid
+ if (_has_field_[2]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(2, io_handler_location_iid_, msg);
+ }
+
+ protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
+}
+
+} // namespace perfetto
+} // namespace protos
+} // namespace gen
+#if defined(__GNUC__) || defined(__clang__)
+#pragma GCC diagnostic pop
+#endif
+// gen_amalgamated begin source: gen/protos/perfetto/trace/track_event/chrome_mojo_event_info.gen.cc
+// gen_amalgamated expanded: #include "perfetto/protozero/gen_field_helpers.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/message.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/packed_repeated_fields.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/proto_decoder.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/scattered_heap_buffer.h"
+// DO NOT EDIT. Autogenerated by Perfetto cppgen_plugin
+#if defined(__GNUC__) || defined(__clang__)
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wfloat-equal"
+#endif
+// gen_amalgamated expanded: #include "protos/perfetto/trace/track_event/chrome_mojo_event_info.gen.h"
+
+namespace perfetto {
+namespace protos {
+namespace gen {
+
+ChromeMojoEventInfo::ChromeMojoEventInfo() = default;
+ChromeMojoEventInfo::~ChromeMojoEventInfo() = default;
+ChromeMojoEventInfo::ChromeMojoEventInfo(const ChromeMojoEventInfo&) = default;
+ChromeMojoEventInfo& ChromeMojoEventInfo::operator=(const ChromeMojoEventInfo&) = default;
+ChromeMojoEventInfo::ChromeMojoEventInfo(ChromeMojoEventInfo&&) noexcept = default;
+ChromeMojoEventInfo& ChromeMojoEventInfo::operator=(ChromeMojoEventInfo&&) = default;
+
+bool ChromeMojoEventInfo::operator==(const ChromeMojoEventInfo& other) const {
+ return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
+ && ::protozero::internal::gen_helpers::EqualsField(watcher_notify_interface_tag_, other.watcher_notify_interface_tag_)
+ && ::protozero::internal::gen_helpers::EqualsField(ipc_hash_, other.ipc_hash_)
+ && ::protozero::internal::gen_helpers::EqualsField(mojo_interface_tag_, other.mojo_interface_tag_)
+ && ::protozero::internal::gen_helpers::EqualsField(mojo_interface_method_iid_, other.mojo_interface_method_iid_)
+ && ::protozero::internal::gen_helpers::EqualsField(is_reply_, other.is_reply_)
+ && ::protozero::internal::gen_helpers::EqualsField(payload_size_, other.payload_size_)
+ && ::protozero::internal::gen_helpers::EqualsField(data_num_bytes_, other.data_num_bytes_);
+}
+
+bool ChromeMojoEventInfo::ParseFromArray(const void* raw, size_t size) {
+ unknown_fields_.clear();
+ bool packed_error = false;
+
+ ::protozero::ProtoDecoder dec(raw, size);
+ for (auto field = dec.ReadField(); field.valid(); field = dec.ReadField()) {
+ if (field.id() < _has_field_.size()) {
+ _has_field_.set(field.id());
+ }
+ switch (field.id()) {
+ case 1 /* watcher_notify_interface_tag */:
+ ::protozero::internal::gen_helpers::DeserializeString(field, &watcher_notify_interface_tag_);
+ break;
+ case 2 /* ipc_hash */:
+ field.get(&ipc_hash_);
+ break;
+ case 3 /* mojo_interface_tag */:
+ ::protozero::internal::gen_helpers::DeserializeString(field, &mojo_interface_tag_);
+ break;
+ case 4 /* mojo_interface_method_iid */:
+ field.get(&mojo_interface_method_iid_);
+ break;
+ case 5 /* is_reply */:
+ field.get(&is_reply_);
+ break;
+ case 6 /* payload_size */:
+ field.get(&payload_size_);
+ break;
+ case 7 /* data_num_bytes */:
+ field.get(&data_num_bytes_);
+ break;
+ default:
+ field.SerializeAndAppendTo(&unknown_fields_);
+ break;
+ }
+ }
+ return !packed_error && !dec.bytes_left();
+}
+
+std::string ChromeMojoEventInfo::SerializeAsString() const {
+ ::protozero::internal::gen_helpers::MessageSerializer msg;
+ Serialize(msg.get());
+ return msg.SerializeAsString();
+}
+
+std::vector<uint8_t> ChromeMojoEventInfo::SerializeAsArray() const {
+ ::protozero::internal::gen_helpers::MessageSerializer msg;
+ Serialize(msg.get());
+ return msg.SerializeAsArray();
+}
+
+void ChromeMojoEventInfo::Serialize(::protozero::Message* msg) const {
+ // Field 1: watcher_notify_interface_tag
+ if (_has_field_[1]) {
+ ::protozero::internal::gen_helpers::SerializeString(1, watcher_notify_interface_tag_, msg);
+ }
+
+ // Field 2: ipc_hash
+ if (_has_field_[2]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(2, ipc_hash_, msg);
+ }
+
+ // Field 3: mojo_interface_tag
+ if (_has_field_[3]) {
+ ::protozero::internal::gen_helpers::SerializeString(3, mojo_interface_tag_, msg);
+ }
+
+ // Field 4: mojo_interface_method_iid
+ if (_has_field_[4]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(4, mojo_interface_method_iid_, msg);
+ }
+
+ // Field 5: is_reply
+ if (_has_field_[5]) {
+ ::protozero::internal::gen_helpers::SerializeTinyVarInt(5, is_reply_, msg);
+ }
+
+ // Field 6: payload_size
+ if (_has_field_[6]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(6, payload_size_, msg);
+ }
+
+ // Field 7: data_num_bytes
+ if (_has_field_[7]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(7, data_num_bytes_, msg);
+ }
+
+ protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
+}
+
+} // namespace perfetto
+} // namespace protos
+} // namespace gen
+#if defined(__GNUC__) || defined(__clang__)
+#pragma GCC diagnostic pop
+#endif
+// gen_amalgamated begin source: gen/protos/perfetto/trace/track_event/chrome_process_descriptor.gen.cc
+// gen_amalgamated expanded: #include "perfetto/protozero/gen_field_helpers.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/message.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/packed_repeated_fields.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/proto_decoder.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/scattered_heap_buffer.h"
+// DO NOT EDIT. Autogenerated by Perfetto cppgen_plugin
+#if defined(__GNUC__) || defined(__clang__)
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wfloat-equal"
+#endif
+// gen_amalgamated expanded: #include "protos/perfetto/trace/track_event/chrome_process_descriptor.gen.h"
+
+namespace perfetto {
+namespace protos {
+namespace gen {
+
+ChromeProcessDescriptor::ChromeProcessDescriptor() = default;
+ChromeProcessDescriptor::~ChromeProcessDescriptor() = default;
+ChromeProcessDescriptor::ChromeProcessDescriptor(const ChromeProcessDescriptor&) = default;
+ChromeProcessDescriptor& ChromeProcessDescriptor::operator=(const ChromeProcessDescriptor&) = default;
+ChromeProcessDescriptor::ChromeProcessDescriptor(ChromeProcessDescriptor&&) noexcept = default;
+ChromeProcessDescriptor& ChromeProcessDescriptor::operator=(ChromeProcessDescriptor&&) = default;
+
+bool ChromeProcessDescriptor::operator==(const ChromeProcessDescriptor& other) const {
+ return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
+ && ::protozero::internal::gen_helpers::EqualsField(process_type_, other.process_type_)
+ && ::protozero::internal::gen_helpers::EqualsField(process_priority_, other.process_priority_)
+ && ::protozero::internal::gen_helpers::EqualsField(legacy_sort_index_, other.legacy_sort_index_)
+ && ::protozero::internal::gen_helpers::EqualsField(host_app_package_name_, other.host_app_package_name_)
+ && ::protozero::internal::gen_helpers::EqualsField(crash_trace_id_, other.crash_trace_id_);
+}
+
+bool ChromeProcessDescriptor::ParseFromArray(const void* raw, size_t size) {
+ unknown_fields_.clear();
+ bool packed_error = false;
+
+ ::protozero::ProtoDecoder dec(raw, size);
+ for (auto field = dec.ReadField(); field.valid(); field = dec.ReadField()) {
+ if (field.id() < _has_field_.size()) {
+ _has_field_.set(field.id());
+ }
+ switch (field.id()) {
+ case 1 /* process_type */:
+ field.get(&process_type_);
+ break;
+ case 2 /* process_priority */:
+ field.get(&process_priority_);
+ break;
+ case 3 /* legacy_sort_index */:
+ field.get(&legacy_sort_index_);
+ break;
+ case 4 /* host_app_package_name */:
+ ::protozero::internal::gen_helpers::DeserializeString(field, &host_app_package_name_);
+ break;
+ case 5 /* crash_trace_id */:
+ field.get(&crash_trace_id_);
+ break;
+ default:
+ field.SerializeAndAppendTo(&unknown_fields_);
+ break;
+ }
+ }
+ return !packed_error && !dec.bytes_left();
+}
+
+std::string ChromeProcessDescriptor::SerializeAsString() const {
+ ::protozero::internal::gen_helpers::MessageSerializer msg;
+ Serialize(msg.get());
+ return msg.SerializeAsString();
+}
+
+std::vector<uint8_t> ChromeProcessDescriptor::SerializeAsArray() const {
+ ::protozero::internal::gen_helpers::MessageSerializer msg;
+ Serialize(msg.get());
+ return msg.SerializeAsArray();
+}
+
+void ChromeProcessDescriptor::Serialize(::protozero::Message* msg) const {
+ // Field 1: process_type
+ if (_has_field_[1]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(1, process_type_, msg);
+ }
+
+ // Field 2: process_priority
+ if (_has_field_[2]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(2, process_priority_, msg);
+ }
+
+ // Field 3: legacy_sort_index
+ if (_has_field_[3]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(3, legacy_sort_index_, msg);
+ }
+
+ // Field 4: host_app_package_name
+ if (_has_field_[4]) {
+ ::protozero::internal::gen_helpers::SerializeString(4, host_app_package_name_, msg);
+ }
+
+ // Field 5: crash_trace_id
+ if (_has_field_[5]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(5, crash_trace_id_, msg);
+ }
+
+ protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
+}
+
+} // namespace perfetto
+} // namespace protos
+} // namespace gen
+#if defined(__GNUC__) || defined(__clang__)
+#pragma GCC diagnostic pop
+#endif
+// gen_amalgamated begin source: gen/protos/perfetto/trace/track_event/chrome_renderer_scheduler_state.gen.cc
+// gen_amalgamated expanded: #include "perfetto/protozero/gen_field_helpers.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/message.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/packed_repeated_fields.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/proto_decoder.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/scattered_heap_buffer.h"
+// DO NOT EDIT. Autogenerated by Perfetto cppgen_plugin
+#if defined(__GNUC__) || defined(__clang__)
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wfloat-equal"
+#endif
+// gen_amalgamated expanded: #include "protos/perfetto/trace/track_event/chrome_renderer_scheduler_state.gen.h"
+
+namespace perfetto {
+namespace protos {
+namespace gen {
+
+ChromeRendererSchedulerState::ChromeRendererSchedulerState() = default;
+ChromeRendererSchedulerState::~ChromeRendererSchedulerState() = default;
+ChromeRendererSchedulerState::ChromeRendererSchedulerState(const ChromeRendererSchedulerState&) = default;
+ChromeRendererSchedulerState& ChromeRendererSchedulerState::operator=(const ChromeRendererSchedulerState&) = default;
+ChromeRendererSchedulerState::ChromeRendererSchedulerState(ChromeRendererSchedulerState&&) noexcept = default;
+ChromeRendererSchedulerState& ChromeRendererSchedulerState::operator=(ChromeRendererSchedulerState&&) = default;
+
+bool ChromeRendererSchedulerState::operator==(const ChromeRendererSchedulerState& other) const {
+ return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
+ && ::protozero::internal::gen_helpers::EqualsField(rail_mode_, other.rail_mode_)
+ && ::protozero::internal::gen_helpers::EqualsField(is_backgrounded_, other.is_backgrounded_)
+ && ::protozero::internal::gen_helpers::EqualsField(is_hidden_, other.is_hidden_);
+}
+
+bool ChromeRendererSchedulerState::ParseFromArray(const void* raw, size_t size) {
+ unknown_fields_.clear();
+ bool packed_error = false;
+
+ ::protozero::ProtoDecoder dec(raw, size);
+ for (auto field = dec.ReadField(); field.valid(); field = dec.ReadField()) {
+ if (field.id() < _has_field_.size()) {
+ _has_field_.set(field.id());
+ }
+ switch (field.id()) {
+ case 1 /* rail_mode */:
+ field.get(&rail_mode_);
+ break;
+ case 2 /* is_backgrounded */:
+ field.get(&is_backgrounded_);
+ break;
+ case 3 /* is_hidden */:
+ field.get(&is_hidden_);
+ break;
+ default:
+ field.SerializeAndAppendTo(&unknown_fields_);
+ break;
+ }
+ }
+ return !packed_error && !dec.bytes_left();
+}
+
+std::string ChromeRendererSchedulerState::SerializeAsString() const {
+ ::protozero::internal::gen_helpers::MessageSerializer msg;
+ Serialize(msg.get());
+ return msg.SerializeAsString();
+}
+
+std::vector<uint8_t> ChromeRendererSchedulerState::SerializeAsArray() const {
+ ::protozero::internal::gen_helpers::MessageSerializer msg;
+ Serialize(msg.get());
+ return msg.SerializeAsArray();
+}
+
+void ChromeRendererSchedulerState::Serialize(::protozero::Message* msg) const {
+ // Field 1: rail_mode
+ if (_has_field_[1]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(1, rail_mode_, msg);
+ }
+
+ // Field 2: is_backgrounded
+ if (_has_field_[2]) {
+ ::protozero::internal::gen_helpers::SerializeTinyVarInt(2, is_backgrounded_, msg);
+ }
+
+ // Field 3: is_hidden
+ if (_has_field_[3]) {
+ ::protozero::internal::gen_helpers::SerializeTinyVarInt(3, is_hidden_, msg);
+ }
+
+ protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
+}
+
+} // namespace perfetto
+} // namespace protos
+} // namespace gen
+#if defined(__GNUC__) || defined(__clang__)
+#pragma GCC diagnostic pop
+#endif
+// gen_amalgamated begin source: gen/protos/perfetto/trace/track_event/chrome_thread_descriptor.gen.cc
+// gen_amalgamated expanded: #include "perfetto/protozero/gen_field_helpers.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/message.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/packed_repeated_fields.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/proto_decoder.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/scattered_heap_buffer.h"
+// DO NOT EDIT. Autogenerated by Perfetto cppgen_plugin
+#if defined(__GNUC__) || defined(__clang__)
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wfloat-equal"
+#endif
+// gen_amalgamated expanded: #include "protos/perfetto/trace/track_event/chrome_thread_descriptor.gen.h"
+
+namespace perfetto {
+namespace protos {
+namespace gen {
+
+ChromeThreadDescriptor::ChromeThreadDescriptor() = default;
+ChromeThreadDescriptor::~ChromeThreadDescriptor() = default;
+ChromeThreadDescriptor::ChromeThreadDescriptor(const ChromeThreadDescriptor&) = default;
+ChromeThreadDescriptor& ChromeThreadDescriptor::operator=(const ChromeThreadDescriptor&) = default;
+ChromeThreadDescriptor::ChromeThreadDescriptor(ChromeThreadDescriptor&&) noexcept = default;
+ChromeThreadDescriptor& ChromeThreadDescriptor::operator=(ChromeThreadDescriptor&&) = default;
+
+bool ChromeThreadDescriptor::operator==(const ChromeThreadDescriptor& other) const {
+ return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
+ && ::protozero::internal::gen_helpers::EqualsField(thread_type_, other.thread_type_)
+ && ::protozero::internal::gen_helpers::EqualsField(legacy_sort_index_, other.legacy_sort_index_)
+ && ::protozero::internal::gen_helpers::EqualsField(is_sandboxed_tid_, other.is_sandboxed_tid_);
+}
+
+bool ChromeThreadDescriptor::ParseFromArray(const void* raw, size_t size) {
+ unknown_fields_.clear();
+ bool packed_error = false;
+
+ ::protozero::ProtoDecoder dec(raw, size);
+ for (auto field = dec.ReadField(); field.valid(); field = dec.ReadField()) {
+ if (field.id() < _has_field_.size()) {
+ _has_field_.set(field.id());
+ }
+ switch (field.id()) {
+ case 1 /* thread_type */:
+ field.get(&thread_type_);
+ break;
+ case 2 /* legacy_sort_index */:
+ field.get(&legacy_sort_index_);
+ break;
+ case 3 /* is_sandboxed_tid */:
+ field.get(&is_sandboxed_tid_);
+ break;
+ default:
+ field.SerializeAndAppendTo(&unknown_fields_);
+ break;
+ }
+ }
+ return !packed_error && !dec.bytes_left();
+}
+
+std::string ChromeThreadDescriptor::SerializeAsString() const {
+ ::protozero::internal::gen_helpers::MessageSerializer msg;
+ Serialize(msg.get());
+ return msg.SerializeAsString();
+}
+
+std::vector<uint8_t> ChromeThreadDescriptor::SerializeAsArray() const {
+ ::protozero::internal::gen_helpers::MessageSerializer msg;
+ Serialize(msg.get());
+ return msg.SerializeAsArray();
+}
+
+void ChromeThreadDescriptor::Serialize(::protozero::Message* msg) const {
+ // Field 1: thread_type
+ if (_has_field_[1]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(1, thread_type_, msg);
+ }
+
+ // Field 2: legacy_sort_index
+ if (_has_field_[2]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(2, legacy_sort_index_, msg);
+ }
+
+ // Field 3: is_sandboxed_tid
+ if (_has_field_[3]) {
+ ::protozero::internal::gen_helpers::SerializeTinyVarInt(3, is_sandboxed_tid_, msg);
+ }
+
+ protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
+}
+
+} // namespace perfetto
+} // namespace protos
+} // namespace gen
+#if defined(__GNUC__) || defined(__clang__)
+#pragma GCC diagnostic pop
+#endif
+// gen_amalgamated begin source: gen/protos/perfetto/trace/track_event/chrome_user_event.gen.cc
+// gen_amalgamated expanded: #include "perfetto/protozero/gen_field_helpers.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/message.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/packed_repeated_fields.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/proto_decoder.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/scattered_heap_buffer.h"
+// DO NOT EDIT. Autogenerated by Perfetto cppgen_plugin
+#if defined(__GNUC__) || defined(__clang__)
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wfloat-equal"
+#endif
+// gen_amalgamated expanded: #include "protos/perfetto/trace/track_event/chrome_user_event.gen.h"
+
+namespace perfetto {
+namespace protos {
+namespace gen {
+
+ChromeUserEvent::ChromeUserEvent() = default;
+ChromeUserEvent::~ChromeUserEvent() = default;
+ChromeUserEvent::ChromeUserEvent(const ChromeUserEvent&) = default;
+ChromeUserEvent& ChromeUserEvent::operator=(const ChromeUserEvent&) = default;
+ChromeUserEvent::ChromeUserEvent(ChromeUserEvent&&) noexcept = default;
+ChromeUserEvent& ChromeUserEvent::operator=(ChromeUserEvent&&) = default;
+
+bool ChromeUserEvent::operator==(const ChromeUserEvent& other) const {
+ return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
+ && ::protozero::internal::gen_helpers::EqualsField(action_, other.action_)
+ && ::protozero::internal::gen_helpers::EqualsField(action_hash_, other.action_hash_);
+}
+
+bool ChromeUserEvent::ParseFromArray(const void* raw, size_t size) {
+ unknown_fields_.clear();
+ bool packed_error = false;
+
+ ::protozero::ProtoDecoder dec(raw, size);
+ for (auto field = dec.ReadField(); field.valid(); field = dec.ReadField()) {
+ if (field.id() < _has_field_.size()) {
+ _has_field_.set(field.id());
+ }
+ switch (field.id()) {
+ case 1 /* action */:
+ ::protozero::internal::gen_helpers::DeserializeString(field, &action_);
+ break;
+ case 2 /* action_hash */:
+ field.get(&action_hash_);
+ break;
+ default:
+ field.SerializeAndAppendTo(&unknown_fields_);
+ break;
+ }
+ }
+ return !packed_error && !dec.bytes_left();
+}
+
+std::string ChromeUserEvent::SerializeAsString() const {
+ ::protozero::internal::gen_helpers::MessageSerializer msg;
+ Serialize(msg.get());
+ return msg.SerializeAsString();
+}
+
+std::vector<uint8_t> ChromeUserEvent::SerializeAsArray() const {
+ ::protozero::internal::gen_helpers::MessageSerializer msg;
+ Serialize(msg.get());
+ return msg.SerializeAsArray();
+}
+
+void ChromeUserEvent::Serialize(::protozero::Message* msg) const {
+ // Field 1: action
+ if (_has_field_[1]) {
+ ::protozero::internal::gen_helpers::SerializeString(1, action_, msg);
+ }
+
+ // Field 2: action_hash
+ if (_has_field_[2]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(2, action_hash_, msg);
+ }
+
+ protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
+}
+
+} // namespace perfetto
+} // namespace protos
+} // namespace gen
+#if defined(__GNUC__) || defined(__clang__)
+#pragma GCC diagnostic pop
+#endif
+// gen_amalgamated begin source: gen/protos/perfetto/trace/track_event/chrome_window_handle_event_info.gen.cc
+// gen_amalgamated expanded: #include "perfetto/protozero/gen_field_helpers.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/message.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/packed_repeated_fields.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/proto_decoder.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/scattered_heap_buffer.h"
+// DO NOT EDIT. Autogenerated by Perfetto cppgen_plugin
+#if defined(__GNUC__) || defined(__clang__)
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wfloat-equal"
+#endif
+// gen_amalgamated expanded: #include "protos/perfetto/trace/track_event/chrome_window_handle_event_info.gen.h"
+
+namespace perfetto {
+namespace protos {
+namespace gen {
+
+ChromeWindowHandleEventInfo::ChromeWindowHandleEventInfo() = default;
+ChromeWindowHandleEventInfo::~ChromeWindowHandleEventInfo() = default;
+ChromeWindowHandleEventInfo::ChromeWindowHandleEventInfo(const ChromeWindowHandleEventInfo&) = default;
+ChromeWindowHandleEventInfo& ChromeWindowHandleEventInfo::operator=(const ChromeWindowHandleEventInfo&) = default;
+ChromeWindowHandleEventInfo::ChromeWindowHandleEventInfo(ChromeWindowHandleEventInfo&&) noexcept = default;
+ChromeWindowHandleEventInfo& ChromeWindowHandleEventInfo::operator=(ChromeWindowHandleEventInfo&&) = default;
+
+bool ChromeWindowHandleEventInfo::operator==(const ChromeWindowHandleEventInfo& other) const {
+ return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
+ && ::protozero::internal::gen_helpers::EqualsField(dpi_, other.dpi_)
+ && ::protozero::internal::gen_helpers::EqualsField(message_id_, other.message_id_)
+ && ::protozero::internal::gen_helpers::EqualsField(hwnd_ptr_, other.hwnd_ptr_);
+}
+
+bool ChromeWindowHandleEventInfo::ParseFromArray(const void* raw, size_t size) {
+ unknown_fields_.clear();
+ bool packed_error = false;
+
+ ::protozero::ProtoDecoder dec(raw, size);
+ for (auto field = dec.ReadField(); field.valid(); field = dec.ReadField()) {
+ if (field.id() < _has_field_.size()) {
+ _has_field_.set(field.id());
+ }
+ switch (field.id()) {
+ case 1 /* dpi */:
+ field.get(&dpi_);
+ break;
+ case 2 /* message_id */:
+ field.get(&message_id_);
+ break;
+ case 3 /* hwnd_ptr */:
+ field.get(&hwnd_ptr_);
+ break;
+ default:
+ field.SerializeAndAppendTo(&unknown_fields_);
+ break;
+ }
+ }
+ return !packed_error && !dec.bytes_left();
+}
+
+std::string ChromeWindowHandleEventInfo::SerializeAsString() const {
+ ::protozero::internal::gen_helpers::MessageSerializer msg;
+ Serialize(msg.get());
+ return msg.SerializeAsString();
+}
+
+std::vector<uint8_t> ChromeWindowHandleEventInfo::SerializeAsArray() const {
+ ::protozero::internal::gen_helpers::MessageSerializer msg;
+ Serialize(msg.get());
+ return msg.SerializeAsArray();
+}
+
+void ChromeWindowHandleEventInfo::Serialize(::protozero::Message* msg) const {
+ // Field 1: dpi
+ if (_has_field_[1]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(1, dpi_, msg);
+ }
+
+ // Field 2: message_id
+ if (_has_field_[2]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(2, message_id_, msg);
+ }
+
+ // Field 3: hwnd_ptr
+ if (_has_field_[3]) {
+ ::protozero::internal::gen_helpers::SerializeFixed(3, hwnd_ptr_, msg);
+ }
+
+ protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
+}
+
+} // namespace perfetto
+} // namespace protos
+} // namespace gen
+#if defined(__GNUC__) || defined(__clang__)
+#pragma GCC diagnostic pop
+#endif
+// gen_amalgamated begin source: gen/protos/perfetto/trace/track_event/counter_descriptor.gen.cc
+// gen_amalgamated expanded: #include "perfetto/protozero/gen_field_helpers.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/message.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/packed_repeated_fields.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/proto_decoder.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/scattered_heap_buffer.h"
+// DO NOT EDIT. Autogenerated by Perfetto cppgen_plugin
+#if defined(__GNUC__) || defined(__clang__)
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wfloat-equal"
+#endif
+// gen_amalgamated expanded: #include "protos/perfetto/trace/track_event/counter_descriptor.gen.h"
+
+namespace perfetto {
+namespace protos {
+namespace gen {
+
+CounterDescriptor::CounterDescriptor() = default;
+CounterDescriptor::~CounterDescriptor() = default;
+CounterDescriptor::CounterDescriptor(const CounterDescriptor&) = default;
+CounterDescriptor& CounterDescriptor::operator=(const CounterDescriptor&) = default;
+CounterDescriptor::CounterDescriptor(CounterDescriptor&&) noexcept = default;
+CounterDescriptor& CounterDescriptor::operator=(CounterDescriptor&&) = default;
+
+bool CounterDescriptor::operator==(const CounterDescriptor& other) const {
+ return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
+ && ::protozero::internal::gen_helpers::EqualsField(type_, other.type_)
+ && ::protozero::internal::gen_helpers::EqualsField(categories_, other.categories_)
+ && ::protozero::internal::gen_helpers::EqualsField(unit_, other.unit_)
+ && ::protozero::internal::gen_helpers::EqualsField(unit_name_, other.unit_name_)
+ && ::protozero::internal::gen_helpers::EqualsField(unit_multiplier_, other.unit_multiplier_)
+ && ::protozero::internal::gen_helpers::EqualsField(is_incremental_, other.is_incremental_)
+ && ::protozero::internal::gen_helpers::EqualsField(y_axis_share_key_, other.y_axis_share_key_);
+}
+
+bool CounterDescriptor::ParseFromArray(const void* raw, size_t size) {
+ categories_.clear();
+ unknown_fields_.clear();
+ bool packed_error = false;
+
+ ::protozero::ProtoDecoder dec(raw, size);
+ for (auto field = dec.ReadField(); field.valid(); field = dec.ReadField()) {
+ if (field.id() < _has_field_.size()) {
+ _has_field_.set(field.id());
+ }
+ switch (field.id()) {
+ case 1 /* type */:
+ field.get(&type_);
+ break;
+ case 2 /* categories */:
+ categories_.emplace_back();
+ ::protozero::internal::gen_helpers::DeserializeString(field, &categories_.back());
+ break;
+ case 3 /* unit */:
+ field.get(&unit_);
+ break;
+ case 6 /* unit_name */:
+ ::protozero::internal::gen_helpers::DeserializeString(field, &unit_name_);
+ break;
+ case 4 /* unit_multiplier */:
+ field.get(&unit_multiplier_);
+ break;
+ case 5 /* is_incremental */:
+ field.get(&is_incremental_);
+ break;
+ case 7 /* y_axis_share_key */:
+ ::protozero::internal::gen_helpers::DeserializeString(field, &y_axis_share_key_);
+ break;
+ default:
+ field.SerializeAndAppendTo(&unknown_fields_);
+ break;
+ }
+ }
+ return !packed_error && !dec.bytes_left();
+}
+
+std::string CounterDescriptor::SerializeAsString() const {
+ ::protozero::internal::gen_helpers::MessageSerializer msg;
+ Serialize(msg.get());
+ return msg.SerializeAsString();
+}
+
+std::vector<uint8_t> CounterDescriptor::SerializeAsArray() const {
+ ::protozero::internal::gen_helpers::MessageSerializer msg;
+ Serialize(msg.get());
+ return msg.SerializeAsArray();
+}
+
+void CounterDescriptor::Serialize(::protozero::Message* msg) const {
+ // Field 1: type
+ if (_has_field_[1]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(1, type_, msg);
+ }
+
+ // Field 2: categories
+ for (auto& it : categories_) {
+ ::protozero::internal::gen_helpers::SerializeString(2, it, msg);
+ }
+
+ // Field 3: unit
+ if (_has_field_[3]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(3, unit_, msg);
+ }
+
+ // Field 6: unit_name
+ if (_has_field_[6]) {
+ ::protozero::internal::gen_helpers::SerializeString(6, unit_name_, msg);
+ }
+
+ // Field 4: unit_multiplier
+ if (_has_field_[4]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(4, unit_multiplier_, msg);
+ }
+
+ // Field 5: is_incremental
+ if (_has_field_[5]) {
+ ::protozero::internal::gen_helpers::SerializeTinyVarInt(5, is_incremental_, msg);
+ }
+
+ // Field 7: y_axis_share_key
+ if (_has_field_[7]) {
+ ::protozero::internal::gen_helpers::SerializeString(7, y_axis_share_key_, msg);
+ }
+
+ protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
+}
+
+} // namespace perfetto
+} // namespace protos
+} // namespace gen
+#if defined(__GNUC__) || defined(__clang__)
+#pragma GCC diagnostic pop
+#endif
+// gen_amalgamated begin source: gen/protos/perfetto/trace/track_event/debug_annotation.gen.cc
+// gen_amalgamated expanded: #include "perfetto/protozero/gen_field_helpers.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/message.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/packed_repeated_fields.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/proto_decoder.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/scattered_heap_buffer.h"
+// DO NOT EDIT. Autogenerated by Perfetto cppgen_plugin
+#if defined(__GNUC__) || defined(__clang__)
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wfloat-equal"
+#endif
+// gen_amalgamated expanded: #include "protos/perfetto/trace/track_event/debug_annotation.gen.h"
+
+namespace perfetto {
+namespace protos {
+namespace gen {
+
+DebugAnnotationValueTypeName::DebugAnnotationValueTypeName() = default;
+DebugAnnotationValueTypeName::~DebugAnnotationValueTypeName() = default;
+DebugAnnotationValueTypeName::DebugAnnotationValueTypeName(const DebugAnnotationValueTypeName&) = default;
+DebugAnnotationValueTypeName& DebugAnnotationValueTypeName::operator=(const DebugAnnotationValueTypeName&) = default;
+DebugAnnotationValueTypeName::DebugAnnotationValueTypeName(DebugAnnotationValueTypeName&&) noexcept = default;
+DebugAnnotationValueTypeName& DebugAnnotationValueTypeName::operator=(DebugAnnotationValueTypeName&&) = default;
+
+bool DebugAnnotationValueTypeName::operator==(const DebugAnnotationValueTypeName& other) const {
+ return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
+ && ::protozero::internal::gen_helpers::EqualsField(iid_, other.iid_)
+ && ::protozero::internal::gen_helpers::EqualsField(name_, other.name_);
+}
+
+bool DebugAnnotationValueTypeName::ParseFromArray(const void* raw, size_t size) {
+ unknown_fields_.clear();
+ bool packed_error = false;
+
+ ::protozero::ProtoDecoder dec(raw, size);
+ for (auto field = dec.ReadField(); field.valid(); field = dec.ReadField()) {
+ if (field.id() < _has_field_.size()) {
+ _has_field_.set(field.id());
+ }
+ switch (field.id()) {
+ case 1 /* iid */:
+ field.get(&iid_);
+ break;
+ case 2 /* name */:
+ ::protozero::internal::gen_helpers::DeserializeString(field, &name_);
+ break;
+ default:
+ field.SerializeAndAppendTo(&unknown_fields_);
+ break;
+ }
+ }
+ return !packed_error && !dec.bytes_left();
+}
+
+std::string DebugAnnotationValueTypeName::SerializeAsString() const {
+ ::protozero::internal::gen_helpers::MessageSerializer msg;
+ Serialize(msg.get());
+ return msg.SerializeAsString();
+}
+
+std::vector<uint8_t> DebugAnnotationValueTypeName::SerializeAsArray() const {
+ ::protozero::internal::gen_helpers::MessageSerializer msg;
+ Serialize(msg.get());
+ return msg.SerializeAsArray();
+}
+
+void DebugAnnotationValueTypeName::Serialize(::protozero::Message* msg) const {
+ // Field 1: iid
+ if (_has_field_[1]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(1, iid_, msg);
+ }
+
+ // Field 2: name
+ if (_has_field_[2]) {
+ ::protozero::internal::gen_helpers::SerializeString(2, name_, msg);
+ }
+
+ protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
+}
+
+
+DebugAnnotationName::DebugAnnotationName() = default;
+DebugAnnotationName::~DebugAnnotationName() = default;
+DebugAnnotationName::DebugAnnotationName(const DebugAnnotationName&) = default;
+DebugAnnotationName& DebugAnnotationName::operator=(const DebugAnnotationName&) = default;
+DebugAnnotationName::DebugAnnotationName(DebugAnnotationName&&) noexcept = default;
+DebugAnnotationName& DebugAnnotationName::operator=(DebugAnnotationName&&) = default;
+
+bool DebugAnnotationName::operator==(const DebugAnnotationName& other) const {
+ return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
+ && ::protozero::internal::gen_helpers::EqualsField(iid_, other.iid_)
+ && ::protozero::internal::gen_helpers::EqualsField(name_, other.name_);
+}
+
+bool DebugAnnotationName::ParseFromArray(const void* raw, size_t size) {
+ unknown_fields_.clear();
+ bool packed_error = false;
+
+ ::protozero::ProtoDecoder dec(raw, size);
+ for (auto field = dec.ReadField(); field.valid(); field = dec.ReadField()) {
+ if (field.id() < _has_field_.size()) {
+ _has_field_.set(field.id());
+ }
+ switch (field.id()) {
+ case 1 /* iid */:
+ field.get(&iid_);
+ break;
+ case 2 /* name */:
+ ::protozero::internal::gen_helpers::DeserializeString(field, &name_);
+ break;
+ default:
+ field.SerializeAndAppendTo(&unknown_fields_);
+ break;
+ }
+ }
+ return !packed_error && !dec.bytes_left();
+}
+
+std::string DebugAnnotationName::SerializeAsString() const {
+ ::protozero::internal::gen_helpers::MessageSerializer msg;
+ Serialize(msg.get());
+ return msg.SerializeAsString();
+}
+
+std::vector<uint8_t> DebugAnnotationName::SerializeAsArray() const {
+ ::protozero::internal::gen_helpers::MessageSerializer msg;
+ Serialize(msg.get());
+ return msg.SerializeAsArray();
+}
+
+void DebugAnnotationName::Serialize(::protozero::Message* msg) const {
+ // Field 1: iid
+ if (_has_field_[1]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(1, iid_, msg);
+ }
+
+ // Field 2: name
+ if (_has_field_[2]) {
+ ::protozero::internal::gen_helpers::SerializeString(2, name_, msg);
+ }
+
+ protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
+}
+
+
+DebugAnnotation::DebugAnnotation() = default;
+DebugAnnotation::~DebugAnnotation() = default;
+DebugAnnotation::DebugAnnotation(const DebugAnnotation&) = default;
+DebugAnnotation& DebugAnnotation::operator=(const DebugAnnotation&) = default;
+DebugAnnotation::DebugAnnotation(DebugAnnotation&&) noexcept = default;
+DebugAnnotation& DebugAnnotation::operator=(DebugAnnotation&&) = default;
+
+bool DebugAnnotation::operator==(const DebugAnnotation& other) const {
+ return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
+ && ::protozero::internal::gen_helpers::EqualsField(name_iid_, other.name_iid_)
+ && ::protozero::internal::gen_helpers::EqualsField(name_, other.name_)
+ && ::protozero::internal::gen_helpers::EqualsField(bool_value_, other.bool_value_)
+ && ::protozero::internal::gen_helpers::EqualsField(uint_value_, other.uint_value_)
+ && ::protozero::internal::gen_helpers::EqualsField(int_value_, other.int_value_)
+ && ::protozero::internal::gen_helpers::EqualsField(double_value_, other.double_value_)
+ && ::protozero::internal::gen_helpers::EqualsField(pointer_value_, other.pointer_value_)
+ && ::protozero::internal::gen_helpers::EqualsField(nested_value_, other.nested_value_)
+ && ::protozero::internal::gen_helpers::EqualsField(legacy_json_value_, other.legacy_json_value_)
+ && ::protozero::internal::gen_helpers::EqualsField(string_value_, other.string_value_)
+ && ::protozero::internal::gen_helpers::EqualsField(string_value_iid_, other.string_value_iid_)
+ && ::protozero::internal::gen_helpers::EqualsField(proto_type_name_, other.proto_type_name_)
+ && ::protozero::internal::gen_helpers::EqualsField(proto_type_name_iid_, other.proto_type_name_iid_)
+ && ::protozero::internal::gen_helpers::EqualsField(proto_value_, other.proto_value_)
+ && ::protozero::internal::gen_helpers::EqualsField(dict_entries_, other.dict_entries_)
+ && ::protozero::internal::gen_helpers::EqualsField(array_values_, other.array_values_);
+}
+
+int DebugAnnotation::dict_entries_size() const { return static_cast<int>(dict_entries_.size()); }
+void DebugAnnotation::clear_dict_entries() { dict_entries_.clear(); }
+DebugAnnotation* DebugAnnotation::add_dict_entries() { dict_entries_.emplace_back(); return &dict_entries_.back(); }
+int DebugAnnotation::array_values_size() const { return static_cast<int>(array_values_.size()); }
+void DebugAnnotation::clear_array_values() { array_values_.clear(); }
+DebugAnnotation* DebugAnnotation::add_array_values() { array_values_.emplace_back(); return &array_values_.back(); }
+bool DebugAnnotation::ParseFromArray(const void* raw, size_t size) {
+ dict_entries_.clear();
+ array_values_.clear();
+ unknown_fields_.clear();
+ bool packed_error = false;
+
+ ::protozero::ProtoDecoder dec(raw, size);
+ for (auto field = dec.ReadField(); field.valid(); field = dec.ReadField()) {
+ if (field.id() < _has_field_.size()) {
+ _has_field_.set(field.id());
+ }
+ switch (field.id()) {
+ case 1 /* name_iid */:
+ field.get(&name_iid_);
+ break;
+ case 10 /* name */:
+ ::protozero::internal::gen_helpers::DeserializeString(field, &name_);
+ break;
+ case 2 /* bool_value */:
+ field.get(&bool_value_);
+ break;
+ case 3 /* uint_value */:
+ field.get(&uint_value_);
+ break;
+ case 4 /* int_value */:
+ field.get(&int_value_);
+ break;
+ case 5 /* double_value */:
+ field.get(&double_value_);
+ break;
+ case 7 /* pointer_value */:
+ field.get(&pointer_value_);
+ break;
+ case 8 /* nested_value */:
+ (*nested_value_).ParseFromArray(field.data(), field.size());
+ break;
+ case 9 /* legacy_json_value */:
+ ::protozero::internal::gen_helpers::DeserializeString(field, &legacy_json_value_);
+ break;
+ case 6 /* string_value */:
+ ::protozero::internal::gen_helpers::DeserializeString(field, &string_value_);
+ break;
+ case 17 /* string_value_iid */:
+ field.get(&string_value_iid_);
+ break;
+ case 16 /* proto_type_name */:
+ ::protozero::internal::gen_helpers::DeserializeString(field, &proto_type_name_);
+ break;
+ case 13 /* proto_type_name_iid */:
+ field.get(&proto_type_name_iid_);
+ break;
+ case 14 /* proto_value */:
+ field.get(&proto_value_);
+ break;
+ case 11 /* dict_entries */:
+ dict_entries_.emplace_back();
+ dict_entries_.back().ParseFromArray(field.data(), field.size());
+ break;
+ case 12 /* array_values */:
+ array_values_.emplace_back();
+ array_values_.back().ParseFromArray(field.data(), field.size());
+ break;
+ default:
+ field.SerializeAndAppendTo(&unknown_fields_);
+ break;
+ }
+ }
+ return !packed_error && !dec.bytes_left();
+}
+
+std::string DebugAnnotation::SerializeAsString() const {
+ ::protozero::internal::gen_helpers::MessageSerializer msg;
+ Serialize(msg.get());
+ return msg.SerializeAsString();
+}
+
+std::vector<uint8_t> DebugAnnotation::SerializeAsArray() const {
+ ::protozero::internal::gen_helpers::MessageSerializer msg;
+ Serialize(msg.get());
+ return msg.SerializeAsArray();
+}
+
+void DebugAnnotation::Serialize(::protozero::Message* msg) const {
+ // Field 1: name_iid
+ if (_has_field_[1]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(1, name_iid_, msg);
+ }
+
+ // Field 10: name
+ if (_has_field_[10]) {
+ ::protozero::internal::gen_helpers::SerializeString(10, name_, msg);
+ }
+
+ // Field 2: bool_value
+ if (_has_field_[2]) {
+ ::protozero::internal::gen_helpers::SerializeTinyVarInt(2, bool_value_, msg);
+ }
+
+ // Field 3: uint_value
+ if (_has_field_[3]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(3, uint_value_, msg);
+ }
+
+ // Field 4: int_value
+ if (_has_field_[4]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(4, int_value_, msg);
+ }
+
+ // Field 5: double_value
+ if (_has_field_[5]) {
+ ::protozero::internal::gen_helpers::SerializeFixed(5, double_value_, msg);
+ }
+
+ // Field 7: pointer_value
+ if (_has_field_[7]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(7, pointer_value_, msg);
+ }
+
+ // Field 8: nested_value
+ if (_has_field_[8]) {
+ (*nested_value_).Serialize(msg->BeginNestedMessage<::protozero::Message>(8));
+ }
+
+ // Field 9: legacy_json_value
+ if (_has_field_[9]) {
+ ::protozero::internal::gen_helpers::SerializeString(9, legacy_json_value_, msg);
+ }
+
+ // Field 6: string_value
+ if (_has_field_[6]) {
+ ::protozero::internal::gen_helpers::SerializeString(6, string_value_, msg);
+ }
+
+ // Field 17: string_value_iid
+ if (_has_field_[17]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(17, string_value_iid_, msg);
+ }
+
+ // Field 16: proto_type_name
+ if (_has_field_[16]) {
+ ::protozero::internal::gen_helpers::SerializeString(16, proto_type_name_, msg);
+ }
+
+ // Field 13: proto_type_name_iid
+ if (_has_field_[13]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(13, proto_type_name_iid_, msg);
+ }
+
+ // Field 14: proto_value
+ if (_has_field_[14]) {
+ ::protozero::internal::gen_helpers::SerializeString(14, proto_value_, msg);
+ }
+
+ // Field 11: dict_entries
+ for (auto& it : dict_entries_) {
+ it.Serialize(msg->BeginNestedMessage<::protozero::Message>(11));
+ }
+
+ // Field 12: array_values
+ for (auto& it : array_values_) {
+ it.Serialize(msg->BeginNestedMessage<::protozero::Message>(12));
+ }
+
+ protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
+}
+
+
+DebugAnnotation_NestedValue::DebugAnnotation_NestedValue() = default;
+DebugAnnotation_NestedValue::~DebugAnnotation_NestedValue() = default;
+DebugAnnotation_NestedValue::DebugAnnotation_NestedValue(const DebugAnnotation_NestedValue&) = default;
+DebugAnnotation_NestedValue& DebugAnnotation_NestedValue::operator=(const DebugAnnotation_NestedValue&) = default;
+DebugAnnotation_NestedValue::DebugAnnotation_NestedValue(DebugAnnotation_NestedValue&&) noexcept = default;
+DebugAnnotation_NestedValue& DebugAnnotation_NestedValue::operator=(DebugAnnotation_NestedValue&&) = default;
+
+bool DebugAnnotation_NestedValue::operator==(const DebugAnnotation_NestedValue& other) const {
+ return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
+ && ::protozero::internal::gen_helpers::EqualsField(nested_type_, other.nested_type_)
+ && ::protozero::internal::gen_helpers::EqualsField(dict_keys_, other.dict_keys_)
+ && ::protozero::internal::gen_helpers::EqualsField(dict_values_, other.dict_values_)
+ && ::protozero::internal::gen_helpers::EqualsField(array_values_, other.array_values_)
+ && ::protozero::internal::gen_helpers::EqualsField(int_value_, other.int_value_)
+ && ::protozero::internal::gen_helpers::EqualsField(double_value_, other.double_value_)
+ && ::protozero::internal::gen_helpers::EqualsField(bool_value_, other.bool_value_)
+ && ::protozero::internal::gen_helpers::EqualsField(string_value_, other.string_value_);
+}
+
+int DebugAnnotation_NestedValue::dict_values_size() const { return static_cast<int>(dict_values_.size()); }
+void DebugAnnotation_NestedValue::clear_dict_values() { dict_values_.clear(); }
+DebugAnnotation_NestedValue* DebugAnnotation_NestedValue::add_dict_values() { dict_values_.emplace_back(); return &dict_values_.back(); }
+int DebugAnnotation_NestedValue::array_values_size() const { return static_cast<int>(array_values_.size()); }
+void DebugAnnotation_NestedValue::clear_array_values() { array_values_.clear(); }
+DebugAnnotation_NestedValue* DebugAnnotation_NestedValue::add_array_values() { array_values_.emplace_back(); return &array_values_.back(); }
+bool DebugAnnotation_NestedValue::ParseFromArray(const void* raw, size_t size) {
+ dict_keys_.clear();
+ dict_values_.clear();
+ array_values_.clear();
+ unknown_fields_.clear();
+ bool packed_error = false;
+
+ ::protozero::ProtoDecoder dec(raw, size);
+ for (auto field = dec.ReadField(); field.valid(); field = dec.ReadField()) {
+ if (field.id() < _has_field_.size()) {
+ _has_field_.set(field.id());
+ }
+ switch (field.id()) {
+ case 1 /* nested_type */:
+ field.get(&nested_type_);
+ break;
+ case 2 /* dict_keys */:
+ dict_keys_.emplace_back();
+ ::protozero::internal::gen_helpers::DeserializeString(field, &dict_keys_.back());
+ break;
+ case 3 /* dict_values */:
+ dict_values_.emplace_back();
+ dict_values_.back().ParseFromArray(field.data(), field.size());
+ break;
+ case 4 /* array_values */:
+ array_values_.emplace_back();
+ array_values_.back().ParseFromArray(field.data(), field.size());
+ break;
+ case 5 /* int_value */:
+ field.get(&int_value_);
+ break;
+ case 6 /* double_value */:
+ field.get(&double_value_);
+ break;
+ case 7 /* bool_value */:
+ field.get(&bool_value_);
+ break;
+ case 8 /* string_value */:
+ ::protozero::internal::gen_helpers::DeserializeString(field, &string_value_);
+ break;
+ default:
+ field.SerializeAndAppendTo(&unknown_fields_);
+ break;
+ }
+ }
+ return !packed_error && !dec.bytes_left();
+}
+
+std::string DebugAnnotation_NestedValue::SerializeAsString() const {
+ ::protozero::internal::gen_helpers::MessageSerializer msg;
+ Serialize(msg.get());
+ return msg.SerializeAsString();
+}
+
+std::vector<uint8_t> DebugAnnotation_NestedValue::SerializeAsArray() const {
+ ::protozero::internal::gen_helpers::MessageSerializer msg;
+ Serialize(msg.get());
+ return msg.SerializeAsArray();
+}
+
+void DebugAnnotation_NestedValue::Serialize(::protozero::Message* msg) const {
+ // Field 1: nested_type
+ if (_has_field_[1]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(1, nested_type_, msg);
+ }
+
+ // Field 2: dict_keys
+ for (auto& it : dict_keys_) {
+ ::protozero::internal::gen_helpers::SerializeString(2, it, msg);
+ }
+
+ // Field 3: dict_values
+ for (auto& it : dict_values_) {
+ it.Serialize(msg->BeginNestedMessage<::protozero::Message>(3));
+ }
+
+ // Field 4: array_values
+ for (auto& it : array_values_) {
+ it.Serialize(msg->BeginNestedMessage<::protozero::Message>(4));
+ }
+
+ // Field 5: int_value
+ if (_has_field_[5]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(5, int_value_, msg);
+ }
+
+ // Field 6: double_value
+ if (_has_field_[6]) {
+ ::protozero::internal::gen_helpers::SerializeFixed(6, double_value_, msg);
+ }
+
+ // Field 7: bool_value
+ if (_has_field_[7]) {
+ ::protozero::internal::gen_helpers::SerializeTinyVarInt(7, bool_value_, msg);
+ }
+
+ // Field 8: string_value
+ if (_has_field_[8]) {
+ ::protozero::internal::gen_helpers::SerializeString(8, string_value_, msg);
+ }
+
+ protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
+}
+
+} // namespace perfetto
+} // namespace protos
+} // namespace gen
+#if defined(__GNUC__) || defined(__clang__)
+#pragma GCC diagnostic pop
+#endif
+// gen_amalgamated begin source: gen/protos/perfetto/trace/track_event/log_message.gen.cc
+// gen_amalgamated expanded: #include "perfetto/protozero/gen_field_helpers.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/message.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/packed_repeated_fields.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/proto_decoder.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/scattered_heap_buffer.h"
+// DO NOT EDIT. Autogenerated by Perfetto cppgen_plugin
+#if defined(__GNUC__) || defined(__clang__)
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wfloat-equal"
+#endif
+// gen_amalgamated expanded: #include "protos/perfetto/trace/track_event/log_message.gen.h"
+
+namespace perfetto {
+namespace protos {
+namespace gen {
+
+LogMessageBody::LogMessageBody() = default;
+LogMessageBody::~LogMessageBody() = default;
+LogMessageBody::LogMessageBody(const LogMessageBody&) = default;
+LogMessageBody& LogMessageBody::operator=(const LogMessageBody&) = default;
+LogMessageBody::LogMessageBody(LogMessageBody&&) noexcept = default;
+LogMessageBody& LogMessageBody::operator=(LogMessageBody&&) = default;
+
+bool LogMessageBody::operator==(const LogMessageBody& other) const {
+ return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
+ && ::protozero::internal::gen_helpers::EqualsField(iid_, other.iid_)
+ && ::protozero::internal::gen_helpers::EqualsField(body_, other.body_);
+}
+
+bool LogMessageBody::ParseFromArray(const void* raw, size_t size) {
+ unknown_fields_.clear();
+ bool packed_error = false;
+
+ ::protozero::ProtoDecoder dec(raw, size);
+ for (auto field = dec.ReadField(); field.valid(); field = dec.ReadField()) {
+ if (field.id() < _has_field_.size()) {
+ _has_field_.set(field.id());
+ }
+ switch (field.id()) {
+ case 1 /* iid */:
+ field.get(&iid_);
+ break;
+ case 2 /* body */:
+ ::protozero::internal::gen_helpers::DeserializeString(field, &body_);
+ break;
+ default:
+ field.SerializeAndAppendTo(&unknown_fields_);
+ break;
+ }
+ }
+ return !packed_error && !dec.bytes_left();
+}
+
+std::string LogMessageBody::SerializeAsString() const {
+ ::protozero::internal::gen_helpers::MessageSerializer msg;
+ Serialize(msg.get());
+ return msg.SerializeAsString();
+}
+
+std::vector<uint8_t> LogMessageBody::SerializeAsArray() const {
+ ::protozero::internal::gen_helpers::MessageSerializer msg;
+ Serialize(msg.get());
+ return msg.SerializeAsArray();
+}
+
+void LogMessageBody::Serialize(::protozero::Message* msg) const {
+ // Field 1: iid
+ if (_has_field_[1]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(1, iid_, msg);
+ }
+
+ // Field 2: body
+ if (_has_field_[2]) {
+ ::protozero::internal::gen_helpers::SerializeString(2, body_, msg);
+ }
+
+ protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
+}
+
+
+LogMessage::LogMessage() = default;
+LogMessage::~LogMessage() = default;
+LogMessage::LogMessage(const LogMessage&) = default;
+LogMessage& LogMessage::operator=(const LogMessage&) = default;
+LogMessage::LogMessage(LogMessage&&) noexcept = default;
+LogMessage& LogMessage::operator=(LogMessage&&) = default;
+
+bool LogMessage::operator==(const LogMessage& other) const {
+ return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
+ && ::protozero::internal::gen_helpers::EqualsField(source_location_iid_, other.source_location_iid_)
+ && ::protozero::internal::gen_helpers::EqualsField(body_iid_, other.body_iid_)
+ && ::protozero::internal::gen_helpers::EqualsField(prio_, other.prio_);
+}
+
+bool LogMessage::ParseFromArray(const void* raw, size_t size) {
+ unknown_fields_.clear();
+ bool packed_error = false;
+
+ ::protozero::ProtoDecoder dec(raw, size);
+ for (auto field = dec.ReadField(); field.valid(); field = dec.ReadField()) {
+ if (field.id() < _has_field_.size()) {
+ _has_field_.set(field.id());
+ }
+ switch (field.id()) {
+ case 1 /* source_location_iid */:
+ field.get(&source_location_iid_);
+ break;
+ case 2 /* body_iid */:
+ field.get(&body_iid_);
+ break;
+ case 3 /* prio */:
+ field.get(&prio_);
+ break;
+ default:
+ field.SerializeAndAppendTo(&unknown_fields_);
+ break;
+ }
+ }
+ return !packed_error && !dec.bytes_left();
+}
+
+std::string LogMessage::SerializeAsString() const {
+ ::protozero::internal::gen_helpers::MessageSerializer msg;
+ Serialize(msg.get());
+ return msg.SerializeAsString();
+}
+
+std::vector<uint8_t> LogMessage::SerializeAsArray() const {
+ ::protozero::internal::gen_helpers::MessageSerializer msg;
+ Serialize(msg.get());
+ return msg.SerializeAsArray();
+}
+
+void LogMessage::Serialize(::protozero::Message* msg) const {
+ // Field 1: source_location_iid
+ if (_has_field_[1]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(1, source_location_iid_, msg);
+ }
+
+ // Field 2: body_iid
+ if (_has_field_[2]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(2, body_iid_, msg);
+ }
+
+ // Field 3: prio
+ if (_has_field_[3]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(3, prio_, msg);
+ }
+
+ protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
+}
+
+} // namespace perfetto
+} // namespace protos
+} // namespace gen
+#if defined(__GNUC__) || defined(__clang__)
+#pragma GCC diagnostic pop
+#endif
+// gen_amalgamated begin source: gen/protos/perfetto/trace/track_event/process_descriptor.gen.cc
+// gen_amalgamated expanded: #include "perfetto/protozero/gen_field_helpers.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/message.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/packed_repeated_fields.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/proto_decoder.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/scattered_heap_buffer.h"
+// DO NOT EDIT. Autogenerated by Perfetto cppgen_plugin
+#if defined(__GNUC__) || defined(__clang__)
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wfloat-equal"
+#endif
+// gen_amalgamated expanded: #include "protos/perfetto/trace/track_event/process_descriptor.gen.h"
+
+namespace perfetto {
+namespace protos {
+namespace gen {
+
+ProcessDescriptor::ProcessDescriptor() = default;
+ProcessDescriptor::~ProcessDescriptor() = default;
+ProcessDescriptor::ProcessDescriptor(const ProcessDescriptor&) = default;
+ProcessDescriptor& ProcessDescriptor::operator=(const ProcessDescriptor&) = default;
+ProcessDescriptor::ProcessDescriptor(ProcessDescriptor&&) noexcept = default;
+ProcessDescriptor& ProcessDescriptor::operator=(ProcessDescriptor&&) = default;
+
+bool ProcessDescriptor::operator==(const ProcessDescriptor& other) const {
+ return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
+ && ::protozero::internal::gen_helpers::EqualsField(pid_, other.pid_)
+ && ::protozero::internal::gen_helpers::EqualsField(cmdline_, other.cmdline_)
+ && ::protozero::internal::gen_helpers::EqualsField(process_name_, other.process_name_)
+ && ::protozero::internal::gen_helpers::EqualsField(process_priority_, other.process_priority_)
+ && ::protozero::internal::gen_helpers::EqualsField(start_timestamp_ns_, other.start_timestamp_ns_)
+ && ::protozero::internal::gen_helpers::EqualsField(chrome_process_type_, other.chrome_process_type_)
+ && ::protozero::internal::gen_helpers::EqualsField(legacy_sort_index_, other.legacy_sort_index_)
+ && ::protozero::internal::gen_helpers::EqualsField(process_labels_, other.process_labels_);
+}
+
+bool ProcessDescriptor::ParseFromArray(const void* raw, size_t size) {
+ cmdline_.clear();
+ process_labels_.clear();
+ unknown_fields_.clear();
+ bool packed_error = false;
+
+ ::protozero::ProtoDecoder dec(raw, size);
+ for (auto field = dec.ReadField(); field.valid(); field = dec.ReadField()) {
+ if (field.id() < _has_field_.size()) {
+ _has_field_.set(field.id());
+ }
+ switch (field.id()) {
+ case 1 /* pid */:
+ field.get(&pid_);
+ break;
+ case 2 /* cmdline */:
+ cmdline_.emplace_back();
+ ::protozero::internal::gen_helpers::DeserializeString(field, &cmdline_.back());
+ break;
+ case 6 /* process_name */:
+ ::protozero::internal::gen_helpers::DeserializeString(field, &process_name_);
+ break;
+ case 5 /* process_priority */:
+ field.get(&process_priority_);
+ break;
+ case 7 /* start_timestamp_ns */:
+ field.get(&start_timestamp_ns_);
+ break;
+ case 4 /* chrome_process_type */:
+ field.get(&chrome_process_type_);
+ break;
+ case 3 /* legacy_sort_index */:
+ field.get(&legacy_sort_index_);
+ break;
+ case 8 /* process_labels */:
+ process_labels_.emplace_back();
+ ::protozero::internal::gen_helpers::DeserializeString(field, &process_labels_.back());
+ break;
+ default:
+ field.SerializeAndAppendTo(&unknown_fields_);
+ break;
+ }
+ }
+ return !packed_error && !dec.bytes_left();
+}
+
+std::string ProcessDescriptor::SerializeAsString() const {
+ ::protozero::internal::gen_helpers::MessageSerializer msg;
+ Serialize(msg.get());
+ return msg.SerializeAsString();
+}
+
+std::vector<uint8_t> ProcessDescriptor::SerializeAsArray() const {
+ ::protozero::internal::gen_helpers::MessageSerializer msg;
+ Serialize(msg.get());
+ return msg.SerializeAsArray();
+}
+
+void ProcessDescriptor::Serialize(::protozero::Message* msg) const {
+ // Field 1: pid
+ if (_has_field_[1]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(1, pid_, msg);
+ }
+
+ // Field 2: cmdline
+ for (auto& it : cmdline_) {
+ ::protozero::internal::gen_helpers::SerializeString(2, it, msg);
+ }
+
+ // Field 6: process_name
+ if (_has_field_[6]) {
+ ::protozero::internal::gen_helpers::SerializeString(6, process_name_, msg);
+ }
+
+ // Field 5: process_priority
+ if (_has_field_[5]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(5, process_priority_, msg);
+ }
+
+ // Field 7: start_timestamp_ns
+ if (_has_field_[7]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(7, start_timestamp_ns_, msg);
+ }
+
+ // Field 4: chrome_process_type
+ if (_has_field_[4]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(4, chrome_process_type_, msg);
+ }
+
+ // Field 3: legacy_sort_index
+ if (_has_field_[3]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(3, legacy_sort_index_, msg);
+ }
+
+ // Field 8: process_labels
+ for (auto& it : process_labels_) {
+ ::protozero::internal::gen_helpers::SerializeString(8, it, msg);
+ }
+
+ protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
+}
+
+} // namespace perfetto
+} // namespace protos
+} // namespace gen
+#if defined(__GNUC__) || defined(__clang__)
+#pragma GCC diagnostic pop
+#endif
+// gen_amalgamated begin source: gen/protos/perfetto/trace/track_event/range_of_interest.gen.cc
+// gen_amalgamated expanded: #include "perfetto/protozero/gen_field_helpers.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/message.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/packed_repeated_fields.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/proto_decoder.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/scattered_heap_buffer.h"
+// DO NOT EDIT. Autogenerated by Perfetto cppgen_plugin
+#if defined(__GNUC__) || defined(__clang__)
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wfloat-equal"
+#endif
+// gen_amalgamated expanded: #include "protos/perfetto/trace/track_event/range_of_interest.gen.h"
+
+namespace perfetto {
+namespace protos {
+namespace gen {
+
+TrackEventRangeOfInterest::TrackEventRangeOfInterest() = default;
+TrackEventRangeOfInterest::~TrackEventRangeOfInterest() = default;
+TrackEventRangeOfInterest::TrackEventRangeOfInterest(const TrackEventRangeOfInterest&) = default;
+TrackEventRangeOfInterest& TrackEventRangeOfInterest::operator=(const TrackEventRangeOfInterest&) = default;
+TrackEventRangeOfInterest::TrackEventRangeOfInterest(TrackEventRangeOfInterest&&) noexcept = default;
+TrackEventRangeOfInterest& TrackEventRangeOfInterest::operator=(TrackEventRangeOfInterest&&) = default;
+
+bool TrackEventRangeOfInterest::operator==(const TrackEventRangeOfInterest& other) const {
+ return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
+ && ::protozero::internal::gen_helpers::EqualsField(start_us_, other.start_us_);
+}
+
+bool TrackEventRangeOfInterest::ParseFromArray(const void* raw, size_t size) {
+ unknown_fields_.clear();
+ bool packed_error = false;
+
+ ::protozero::ProtoDecoder dec(raw, size);
+ for (auto field = dec.ReadField(); field.valid(); field = dec.ReadField()) {
+ if (field.id() < _has_field_.size()) {
+ _has_field_.set(field.id());
+ }
+ switch (field.id()) {
+ case 1 /* start_us */:
+ field.get(&start_us_);
+ break;
+ default:
+ field.SerializeAndAppendTo(&unknown_fields_);
+ break;
+ }
+ }
+ return !packed_error && !dec.bytes_left();
+}
+
+std::string TrackEventRangeOfInterest::SerializeAsString() const {
+ ::protozero::internal::gen_helpers::MessageSerializer msg;
+ Serialize(msg.get());
+ return msg.SerializeAsString();
+}
+
+std::vector<uint8_t> TrackEventRangeOfInterest::SerializeAsArray() const {
+ ::protozero::internal::gen_helpers::MessageSerializer msg;
+ Serialize(msg.get());
+ return msg.SerializeAsArray();
+}
+
+void TrackEventRangeOfInterest::Serialize(::protozero::Message* msg) const {
+ // Field 1: start_us
+ if (_has_field_[1]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(1, start_us_, msg);
+ }
+
+ protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
+}
+
+} // namespace perfetto
+} // namespace protos
+} // namespace gen
+#if defined(__GNUC__) || defined(__clang__)
+#pragma GCC diagnostic pop
+#endif
+// gen_amalgamated begin source: gen/protos/perfetto/trace/track_event/screenshot.gen.cc
+// gen_amalgamated expanded: #include "perfetto/protozero/gen_field_helpers.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/message.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/packed_repeated_fields.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/proto_decoder.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/scattered_heap_buffer.h"
+// DO NOT EDIT. Autogenerated by Perfetto cppgen_plugin
+#if defined(__GNUC__) || defined(__clang__)
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wfloat-equal"
+#endif
+// gen_amalgamated expanded: #include "protos/perfetto/trace/track_event/screenshot.gen.h"
+
+namespace perfetto {
+namespace protos {
+namespace gen {
+
+Screenshot::Screenshot() = default;
+Screenshot::~Screenshot() = default;
+Screenshot::Screenshot(const Screenshot&) = default;
+Screenshot& Screenshot::operator=(const Screenshot&) = default;
+Screenshot::Screenshot(Screenshot&&) noexcept = default;
+Screenshot& Screenshot::operator=(Screenshot&&) = default;
+
+bool Screenshot::operator==(const Screenshot& other) const {
+ return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
+ && ::protozero::internal::gen_helpers::EqualsField(jpg_image_, other.jpg_image_)
+ && ::protozero::internal::gen_helpers::EqualsField(pam_image_, other.pam_image_)
+ && ::protozero::internal::gen_helpers::EqualsField(ppm_image_, other.ppm_image_);
+}
+
+bool Screenshot::ParseFromArray(const void* raw, size_t size) {
+ unknown_fields_.clear();
+ bool packed_error = false;
+
+ ::protozero::ProtoDecoder dec(raw, size);
+ for (auto field = dec.ReadField(); field.valid(); field = dec.ReadField()) {
+ if (field.id() < _has_field_.size()) {
+ _has_field_.set(field.id());
+ }
+ switch (field.id()) {
+ case 1 /* jpg_image */:
+ field.get(&jpg_image_);
+ break;
+ case 2 /* pam_image */:
+ field.get(&pam_image_);
+ break;
+ case 3 /* ppm_image */:
+ field.get(&ppm_image_);
+ break;
+ default:
+ field.SerializeAndAppendTo(&unknown_fields_);
+ break;
+ }
+ }
+ return !packed_error && !dec.bytes_left();
+}
+
+std::string Screenshot::SerializeAsString() const {
+ ::protozero::internal::gen_helpers::MessageSerializer msg;
+ Serialize(msg.get());
+ return msg.SerializeAsString();
+}
+
+std::vector<uint8_t> Screenshot::SerializeAsArray() const {
+ ::protozero::internal::gen_helpers::MessageSerializer msg;
+ Serialize(msg.get());
+ return msg.SerializeAsArray();
+}
+
+void Screenshot::Serialize(::protozero::Message* msg) const {
+ // Field 1: jpg_image
+ if (_has_field_[1]) {
+ ::protozero::internal::gen_helpers::SerializeString(1, jpg_image_, msg);
+ }
+
+ // Field 2: pam_image
+ if (_has_field_[2]) {
+ ::protozero::internal::gen_helpers::SerializeString(2, pam_image_, msg);
+ }
+
+ // Field 3: ppm_image
+ if (_has_field_[3]) {
+ ::protozero::internal::gen_helpers::SerializeString(3, ppm_image_, msg);
+ }
+
+ protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
+}
+
+} // namespace perfetto
+} // namespace protos
+} // namespace gen
+#if defined(__GNUC__) || defined(__clang__)
+#pragma GCC diagnostic pop
+#endif
+// gen_amalgamated begin source: gen/protos/perfetto/trace/track_event/source_location.gen.cc
+// gen_amalgamated expanded: #include "perfetto/protozero/gen_field_helpers.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/message.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/packed_repeated_fields.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/proto_decoder.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/scattered_heap_buffer.h"
+// DO NOT EDIT. Autogenerated by Perfetto cppgen_plugin
+#if defined(__GNUC__) || defined(__clang__)
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wfloat-equal"
+#endif
+// gen_amalgamated expanded: #include "protos/perfetto/trace/track_event/source_location.gen.h"
+
+namespace perfetto {
+namespace protos {
+namespace gen {
+
+SourceLocation::SourceLocation() = default;
+SourceLocation::~SourceLocation() = default;
+SourceLocation::SourceLocation(const SourceLocation&) = default;
+SourceLocation& SourceLocation::operator=(const SourceLocation&) = default;
+SourceLocation::SourceLocation(SourceLocation&&) noexcept = default;
+SourceLocation& SourceLocation::operator=(SourceLocation&&) = default;
+
+bool SourceLocation::operator==(const SourceLocation& other) const {
+ return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
+ && ::protozero::internal::gen_helpers::EqualsField(iid_, other.iid_)
+ && ::protozero::internal::gen_helpers::EqualsField(file_name_, other.file_name_)
+ && ::protozero::internal::gen_helpers::EqualsField(function_name_, other.function_name_)
+ && ::protozero::internal::gen_helpers::EqualsField(line_number_, other.line_number_);
+}
+
+bool SourceLocation::ParseFromArray(const void* raw, size_t size) {
+ unknown_fields_.clear();
+ bool packed_error = false;
+
+ ::protozero::ProtoDecoder dec(raw, size);
+ for (auto field = dec.ReadField(); field.valid(); field = dec.ReadField()) {
+ if (field.id() < _has_field_.size()) {
+ _has_field_.set(field.id());
+ }
+ switch (field.id()) {
+ case 1 /* iid */:
+ field.get(&iid_);
+ break;
+ case 2 /* file_name */:
+ ::protozero::internal::gen_helpers::DeserializeString(field, &file_name_);
+ break;
+ case 3 /* function_name */:
+ ::protozero::internal::gen_helpers::DeserializeString(field, &function_name_);
+ break;
+ case 4 /* line_number */:
+ field.get(&line_number_);
+ break;
+ default:
+ field.SerializeAndAppendTo(&unknown_fields_);
+ break;
+ }
+ }
+ return !packed_error && !dec.bytes_left();
+}
+
+std::string SourceLocation::SerializeAsString() const {
+ ::protozero::internal::gen_helpers::MessageSerializer msg;
+ Serialize(msg.get());
+ return msg.SerializeAsString();
+}
+
+std::vector<uint8_t> SourceLocation::SerializeAsArray() const {
+ ::protozero::internal::gen_helpers::MessageSerializer msg;
+ Serialize(msg.get());
+ return msg.SerializeAsArray();
+}
+
+void SourceLocation::Serialize(::protozero::Message* msg) const {
+ // Field 1: iid
+ if (_has_field_[1]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(1, iid_, msg);
+ }
+
+ // Field 2: file_name
+ if (_has_field_[2]) {
+ ::protozero::internal::gen_helpers::SerializeString(2, file_name_, msg);
+ }
+
+ // Field 3: function_name
+ if (_has_field_[3]) {
+ ::protozero::internal::gen_helpers::SerializeString(3, function_name_, msg);
+ }
+
+ // Field 4: line_number
+ if (_has_field_[4]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(4, line_number_, msg);
+ }
+
+ protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
+}
+
+
+UnsymbolizedSourceLocation::UnsymbolizedSourceLocation() = default;
+UnsymbolizedSourceLocation::~UnsymbolizedSourceLocation() = default;
+UnsymbolizedSourceLocation::UnsymbolizedSourceLocation(const UnsymbolizedSourceLocation&) = default;
+UnsymbolizedSourceLocation& UnsymbolizedSourceLocation::operator=(const UnsymbolizedSourceLocation&) = default;
+UnsymbolizedSourceLocation::UnsymbolizedSourceLocation(UnsymbolizedSourceLocation&&) noexcept = default;
+UnsymbolizedSourceLocation& UnsymbolizedSourceLocation::operator=(UnsymbolizedSourceLocation&&) = default;
+
+bool UnsymbolizedSourceLocation::operator==(const UnsymbolizedSourceLocation& other) const {
+ return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
+ && ::protozero::internal::gen_helpers::EqualsField(iid_, other.iid_)
+ && ::protozero::internal::gen_helpers::EqualsField(mapping_id_, other.mapping_id_)
+ && ::protozero::internal::gen_helpers::EqualsField(rel_pc_, other.rel_pc_);
+}
+
+bool UnsymbolizedSourceLocation::ParseFromArray(const void* raw, size_t size) {
+ unknown_fields_.clear();
+ bool packed_error = false;
+
+ ::protozero::ProtoDecoder dec(raw, size);
+ for (auto field = dec.ReadField(); field.valid(); field = dec.ReadField()) {
+ if (field.id() < _has_field_.size()) {
+ _has_field_.set(field.id());
+ }
+ switch (field.id()) {
+ case 1 /* iid */:
+ field.get(&iid_);
+ break;
+ case 2 /* mapping_id */:
+ field.get(&mapping_id_);
+ break;
+ case 3 /* rel_pc */:
+ field.get(&rel_pc_);
+ break;
+ default:
+ field.SerializeAndAppendTo(&unknown_fields_);
+ break;
+ }
+ }
+ return !packed_error && !dec.bytes_left();
+}
+
+std::string UnsymbolizedSourceLocation::SerializeAsString() const {
+ ::protozero::internal::gen_helpers::MessageSerializer msg;
+ Serialize(msg.get());
+ return msg.SerializeAsString();
+}
+
+std::vector<uint8_t> UnsymbolizedSourceLocation::SerializeAsArray() const {
+ ::protozero::internal::gen_helpers::MessageSerializer msg;
+ Serialize(msg.get());
+ return msg.SerializeAsArray();
+}
+
+void UnsymbolizedSourceLocation::Serialize(::protozero::Message* msg) const {
+ // Field 1: iid
+ if (_has_field_[1]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(1, iid_, msg);
+ }
+
+ // Field 2: mapping_id
+ if (_has_field_[2]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(2, mapping_id_, msg);
+ }
+
+ // Field 3: rel_pc
+ if (_has_field_[3]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(3, rel_pc_, msg);
+ }
+
+ protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
+}
+
+} // namespace perfetto
+} // namespace protos
+} // namespace gen
+#if defined(__GNUC__) || defined(__clang__)
+#pragma GCC diagnostic pop
+#endif
+// gen_amalgamated begin source: gen/protos/perfetto/trace/track_event/state_descriptor.gen.cc
+// gen_amalgamated expanded: #include "perfetto/protozero/gen_field_helpers.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/message.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/packed_repeated_fields.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/proto_decoder.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/scattered_heap_buffer.h"
+// DO NOT EDIT. Autogenerated by Perfetto cppgen_plugin
+#if defined(__GNUC__) || defined(__clang__)
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wfloat-equal"
+#endif
+// gen_amalgamated expanded: #include "protos/perfetto/trace/track_event/state_descriptor.gen.h"
+
+namespace perfetto {
+namespace protos {
+namespace gen {
+
+StateDescriptor::StateDescriptor() = default;
+StateDescriptor::~StateDescriptor() = default;
+StateDescriptor::StateDescriptor(const StateDescriptor&) = default;
+StateDescriptor& StateDescriptor::operator=(const StateDescriptor&) = default;
+StateDescriptor::StateDescriptor(StateDescriptor&&) noexcept = default;
+StateDescriptor& StateDescriptor::operator=(StateDescriptor&&) = default;
+
+bool StateDescriptor::operator==(const StateDescriptor& other) const {
+ return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_);
+}
+
+bool StateDescriptor::ParseFromArray(const void* raw, size_t size) {
+ unknown_fields_.clear();
+ bool packed_error = false;
+
+ ::protozero::ProtoDecoder dec(raw, size);
+ for (auto field = dec.ReadField(); field.valid(); field = dec.ReadField()) {
+ if (field.id() < _has_field_.size()) {
+ _has_field_.set(field.id());
+ }
+ switch (field.id()) {
+ default:
+ field.SerializeAndAppendTo(&unknown_fields_);
+ break;
+ }
+ }
+ return !packed_error && !dec.bytes_left();
+}
+
+std::string StateDescriptor::SerializeAsString() const {
+ ::protozero::internal::gen_helpers::MessageSerializer msg;
+ Serialize(msg.get());
+ return msg.SerializeAsString();
+}
+
+std::vector<uint8_t> StateDescriptor::SerializeAsArray() const {
+ ::protozero::internal::gen_helpers::MessageSerializer msg;
+ Serialize(msg.get());
+ return msg.SerializeAsArray();
+}
+
+void StateDescriptor::Serialize(::protozero::Message* msg) const {
+ protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
+}
+
+} // namespace perfetto
+} // namespace protos
+} // namespace gen
+#if defined(__GNUC__) || defined(__clang__)
+#pragma GCC diagnostic pop
+#endif
+// gen_amalgamated begin source: gen/protos/perfetto/trace/track_event/task_execution.gen.cc
+// gen_amalgamated expanded: #include "perfetto/protozero/gen_field_helpers.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/message.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/packed_repeated_fields.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/proto_decoder.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/scattered_heap_buffer.h"
+// DO NOT EDIT. Autogenerated by Perfetto cppgen_plugin
+#if defined(__GNUC__) || defined(__clang__)
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wfloat-equal"
+#endif
+// gen_amalgamated expanded: #include "protos/perfetto/trace/track_event/task_execution.gen.h"
+
+namespace perfetto {
+namespace protos {
+namespace gen {
+
+TaskExecution::TaskExecution() = default;
+TaskExecution::~TaskExecution() = default;
+TaskExecution::TaskExecution(const TaskExecution&) = default;
+TaskExecution& TaskExecution::operator=(const TaskExecution&) = default;
+TaskExecution::TaskExecution(TaskExecution&&) noexcept = default;
+TaskExecution& TaskExecution::operator=(TaskExecution&&) = default;
+
+bool TaskExecution::operator==(const TaskExecution& other) const {
+ return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
+ && ::protozero::internal::gen_helpers::EqualsField(posted_from_iid_, other.posted_from_iid_);
+}
+
+bool TaskExecution::ParseFromArray(const void* raw, size_t size) {
+ unknown_fields_.clear();
+ bool packed_error = false;
+
+ ::protozero::ProtoDecoder dec(raw, size);
+ for (auto field = dec.ReadField(); field.valid(); field = dec.ReadField()) {
+ if (field.id() < _has_field_.size()) {
+ _has_field_.set(field.id());
+ }
+ switch (field.id()) {
+ case 1 /* posted_from_iid */:
+ field.get(&posted_from_iid_);
+ break;
+ default:
+ field.SerializeAndAppendTo(&unknown_fields_);
+ break;
+ }
+ }
+ return !packed_error && !dec.bytes_left();
+}
+
+std::string TaskExecution::SerializeAsString() const {
+ ::protozero::internal::gen_helpers::MessageSerializer msg;
+ Serialize(msg.get());
+ return msg.SerializeAsString();
+}
+
+std::vector<uint8_t> TaskExecution::SerializeAsArray() const {
+ ::protozero::internal::gen_helpers::MessageSerializer msg;
+ Serialize(msg.get());
+ return msg.SerializeAsArray();
+}
+
+void TaskExecution::Serialize(::protozero::Message* msg) const {
+ // Field 1: posted_from_iid
+ if (_has_field_[1]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(1, posted_from_iid_, msg);
+ }
+
+ protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
+}
+
+} // namespace perfetto
+} // namespace protos
+} // namespace gen
+#if defined(__GNUC__) || defined(__clang__)
+#pragma GCC diagnostic pop
+#endif
+// gen_amalgamated begin source: gen/protos/perfetto/trace/track_event/thread_descriptor.gen.cc
+// gen_amalgamated expanded: #include "perfetto/protozero/gen_field_helpers.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/message.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/packed_repeated_fields.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/proto_decoder.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/scattered_heap_buffer.h"
+// DO NOT EDIT. Autogenerated by Perfetto cppgen_plugin
+#if defined(__GNUC__) || defined(__clang__)
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wfloat-equal"
+#endif
+// gen_amalgamated expanded: #include "protos/perfetto/trace/track_event/thread_descriptor.gen.h"
+
+namespace perfetto {
+namespace protos {
+namespace gen {
+
+ThreadDescriptor::ThreadDescriptor() = default;
+ThreadDescriptor::~ThreadDescriptor() = default;
+ThreadDescriptor::ThreadDescriptor(const ThreadDescriptor&) = default;
+ThreadDescriptor& ThreadDescriptor::operator=(const ThreadDescriptor&) = default;
+ThreadDescriptor::ThreadDescriptor(ThreadDescriptor&&) noexcept = default;
+ThreadDescriptor& ThreadDescriptor::operator=(ThreadDescriptor&&) = default;
+
+bool ThreadDescriptor::operator==(const ThreadDescriptor& other) const {
+ return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
+ && ::protozero::internal::gen_helpers::EqualsField(pid_, other.pid_)
+ && ::protozero::internal::gen_helpers::EqualsField(tid_, other.tid_)
+ && ::protozero::internal::gen_helpers::EqualsField(thread_name_, other.thread_name_)
+ && ::protozero::internal::gen_helpers::EqualsField(chrome_thread_type_, other.chrome_thread_type_)
+ && ::protozero::internal::gen_helpers::EqualsField(reference_timestamp_us_, other.reference_timestamp_us_)
+ && ::protozero::internal::gen_helpers::EqualsField(reference_thread_time_us_, other.reference_thread_time_us_)
+ && ::protozero::internal::gen_helpers::EqualsField(reference_thread_instruction_count_, other.reference_thread_instruction_count_)
+ && ::protozero::internal::gen_helpers::EqualsField(legacy_sort_index_, other.legacy_sort_index_);
+}
+
+bool ThreadDescriptor::ParseFromArray(const void* raw, size_t size) {
+ unknown_fields_.clear();
+ bool packed_error = false;
+
+ ::protozero::ProtoDecoder dec(raw, size);
+ for (auto field = dec.ReadField(); field.valid(); field = dec.ReadField()) {
+ if (field.id() < _has_field_.size()) {
+ _has_field_.set(field.id());
+ }
+ switch (field.id()) {
+ case 1 /* pid */:
+ field.get(&pid_);
+ break;
+ case 2 /* tid */:
+ field.get(&tid_);
+ break;
+ case 5 /* thread_name */:
+ ::protozero::internal::gen_helpers::DeserializeString(field, &thread_name_);
+ break;
+ case 4 /* chrome_thread_type */:
+ field.get(&chrome_thread_type_);
+ break;
+ case 6 /* reference_timestamp_us */:
+ field.get(&reference_timestamp_us_);
+ break;
+ case 7 /* reference_thread_time_us */:
+ field.get(&reference_thread_time_us_);
+ break;
+ case 8 /* reference_thread_instruction_count */:
+ field.get(&reference_thread_instruction_count_);
+ break;
+ case 3 /* legacy_sort_index */:
+ field.get(&legacy_sort_index_);
+ break;
+ default:
+ field.SerializeAndAppendTo(&unknown_fields_);
+ break;
+ }
+ }
+ return !packed_error && !dec.bytes_left();
+}
+
+std::string ThreadDescriptor::SerializeAsString() const {
+ ::protozero::internal::gen_helpers::MessageSerializer msg;
+ Serialize(msg.get());
+ return msg.SerializeAsString();
+}
+
+std::vector<uint8_t> ThreadDescriptor::SerializeAsArray() const {
+ ::protozero::internal::gen_helpers::MessageSerializer msg;
+ Serialize(msg.get());
+ return msg.SerializeAsArray();
+}
+
+void ThreadDescriptor::Serialize(::protozero::Message* msg) const {
+ // Field 1: pid
+ if (_has_field_[1]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(1, pid_, msg);
+ }
+
+ // Field 2: tid
+ if (_has_field_[2]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(2, tid_, msg);
+ }
+
+ // Field 5: thread_name
+ if (_has_field_[5]) {
+ ::protozero::internal::gen_helpers::SerializeString(5, thread_name_, msg);
+ }
+
+ // Field 4: chrome_thread_type
+ if (_has_field_[4]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(4, chrome_thread_type_, msg);
+ }
+
+ // Field 6: reference_timestamp_us
+ if (_has_field_[6]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(6, reference_timestamp_us_, msg);
+ }
+
+ // Field 7: reference_thread_time_us
+ if (_has_field_[7]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(7, reference_thread_time_us_, msg);
+ }
+
+ // Field 8: reference_thread_instruction_count
+ if (_has_field_[8]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(8, reference_thread_instruction_count_, msg);
+ }
+
+ // Field 3: legacy_sort_index
+ if (_has_field_[3]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(3, legacy_sort_index_, msg);
+ }
+
+ protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
+}
+
+} // namespace perfetto
+} // namespace protos
+} // namespace gen
+#if defined(__GNUC__) || defined(__clang__)
+#pragma GCC diagnostic pop
+#endif
+// gen_amalgamated begin source: gen/protos/perfetto/trace/track_event/track_descriptor.gen.cc
+// gen_amalgamated expanded: #include "perfetto/protozero/gen_field_helpers.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/message.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/packed_repeated_fields.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/proto_decoder.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/scattered_heap_buffer.h"
+// DO NOT EDIT. Autogenerated by Perfetto cppgen_plugin
+#if defined(__GNUC__) || defined(__clang__)
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wfloat-equal"
+#endif
+// gen_amalgamated expanded: #include "protos/perfetto/trace/track_event/track_descriptor.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/trace/track_event/state_descriptor.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/trace/track_event/counter_descriptor.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/trace/track_event/thread_descriptor.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/trace/track_event/process_descriptor.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/trace/track_event/chrome_thread_descriptor.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/trace/track_event/chrome_process_descriptor.gen.h"
+
+namespace perfetto {
+namespace protos {
+namespace gen {
+
+TrackDescriptor::TrackDescriptor() = default;
+TrackDescriptor::~TrackDescriptor() = default;
+TrackDescriptor::TrackDescriptor(const TrackDescriptor&) = default;
+TrackDescriptor& TrackDescriptor::operator=(const TrackDescriptor&) = default;
+TrackDescriptor::TrackDescriptor(TrackDescriptor&&) noexcept = default;
+TrackDescriptor& TrackDescriptor::operator=(TrackDescriptor&&) = default;
+
+bool TrackDescriptor::operator==(const TrackDescriptor& other) const {
+ return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
+ && ::protozero::internal::gen_helpers::EqualsField(uuid_, other.uuid_)
+ && ::protozero::internal::gen_helpers::EqualsField(parent_uuid_, other.parent_uuid_)
+ && ::protozero::internal::gen_helpers::EqualsField(name_, other.name_)
+ && ::protozero::internal::gen_helpers::EqualsField(static_name_, other.static_name_)
+ && ::protozero::internal::gen_helpers::EqualsField(atrace_name_, other.atrace_name_)
+ && ::protozero::internal::gen_helpers::EqualsField(description_, other.description_)
+ && ::protozero::internal::gen_helpers::EqualsField(process_, other.process_)
+ && ::protozero::internal::gen_helpers::EqualsField(chrome_process_, other.chrome_process_)
+ && ::protozero::internal::gen_helpers::EqualsField(thread_, other.thread_)
+ && ::protozero::internal::gen_helpers::EqualsField(chrome_thread_, other.chrome_thread_)
+ && ::protozero::internal::gen_helpers::EqualsField(counter_, other.counter_)
+ && ::protozero::internal::gen_helpers::EqualsField(state_, other.state_)
+ && ::protozero::internal::gen_helpers::EqualsField(disallow_merging_with_system_tracks_, other.disallow_merging_with_system_tracks_)
+ && ::protozero::internal::gen_helpers::EqualsField(child_ordering_, other.child_ordering_)
+ && ::protozero::internal::gen_helpers::EqualsField(sibling_order_rank_, other.sibling_order_rank_)
+ && ::protozero::internal::gen_helpers::EqualsField(sibling_merge_behavior_, other.sibling_merge_behavior_)
+ && ::protozero::internal::gen_helpers::EqualsField(sibling_merge_key_, other.sibling_merge_key_)
+ && ::protozero::internal::gen_helpers::EqualsField(sibling_merge_key_int_, other.sibling_merge_key_int_)
+ && ::protozero::internal::gen_helpers::EqualsField(process_ordering_, other.process_ordering_)
+ && ::protozero::internal::gen_helpers::EqualsField(thread_ordering_, other.thread_ordering_);
+}
+
+bool TrackDescriptor::ParseFromArray(const void* raw, size_t size) {
+ unknown_fields_.clear();
+ bool packed_error = false;
+
+ ::protozero::ProtoDecoder dec(raw, size);
+ for (auto field = dec.ReadField(); field.valid(); field = dec.ReadField()) {
+ if (field.id() < _has_field_.size()) {
+ _has_field_.set(field.id());
+ }
+ switch (field.id()) {
+ case 1 /* uuid */:
+ field.get(&uuid_);
+ break;
+ case 5 /* parent_uuid */:
+ field.get(&parent_uuid_);
+ break;
+ case 2 /* name */:
+ ::protozero::internal::gen_helpers::DeserializeString(field, &name_);
+ break;
+ case 10 /* static_name */:
+ ::protozero::internal::gen_helpers::DeserializeString(field, &static_name_);
+ break;
+ case 13 /* atrace_name */:
+ ::protozero::internal::gen_helpers::DeserializeString(field, &atrace_name_);
+ break;
+ case 14 /* description */:
+ ::protozero::internal::gen_helpers::DeserializeString(field, &description_);
+ break;
+ case 3 /* process */:
+ (*process_).ParseFromArray(field.data(), field.size());
+ break;
+ case 6 /* chrome_process */:
+ (*chrome_process_).ParseFromArray(field.data(), field.size());
+ break;
+ case 4 /* thread */:
+ (*thread_).ParseFromArray(field.data(), field.size());
+ break;
+ case 7 /* chrome_thread */:
+ (*chrome_thread_).ParseFromArray(field.data(), field.size());
+ break;
+ case 8 /* counter */:
+ (*counter_).ParseFromArray(field.data(), field.size());
+ break;
+ case 18 /* state */:
+ (*state_).ParseFromArray(field.data(), field.size());
+ break;
+ case 9 /* disallow_merging_with_system_tracks */:
+ field.get(&disallow_merging_with_system_tracks_);
+ break;
+ case 11 /* child_ordering */:
+ field.get(&child_ordering_);
+ break;
+ case 12 /* sibling_order_rank */:
+ field.get(&sibling_order_rank_);
+ break;
+ case 15 /* sibling_merge_behavior */:
+ field.get(&sibling_merge_behavior_);
+ break;
+ case 16 /* sibling_merge_key */:
+ ::protozero::internal::gen_helpers::DeserializeString(field, &sibling_merge_key_);
+ break;
+ case 17 /* sibling_merge_key_int */:
+ field.get(&sibling_merge_key_int_);
+ break;
+ case 19 /* process_ordering */:
+ field.get(&process_ordering_);
+ break;
+ case 20 /* thread_ordering */:
+ field.get(&thread_ordering_);
+ break;
+ default:
+ field.SerializeAndAppendTo(&unknown_fields_);
+ break;
+ }
+ }
+ return !packed_error && !dec.bytes_left();
+}
+
+std::string TrackDescriptor::SerializeAsString() const {
+ ::protozero::internal::gen_helpers::MessageSerializer msg;
+ Serialize(msg.get());
+ return msg.SerializeAsString();
+}
+
+std::vector<uint8_t> TrackDescriptor::SerializeAsArray() const {
+ ::protozero::internal::gen_helpers::MessageSerializer msg;
+ Serialize(msg.get());
+ return msg.SerializeAsArray();
+}
+
+void TrackDescriptor::Serialize(::protozero::Message* msg) const {
+ // Field 1: uuid
+ if (_has_field_[1]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(1, uuid_, msg);
+ }
+
+ // Field 5: parent_uuid
+ if (_has_field_[5]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(5, parent_uuid_, msg);
+ }
+
+ // Field 2: name
+ if (_has_field_[2]) {
+ ::protozero::internal::gen_helpers::SerializeString(2, name_, msg);
+ }
+
+ // Field 10: static_name
+ if (_has_field_[10]) {
+ ::protozero::internal::gen_helpers::SerializeString(10, static_name_, msg);
+ }
+
+ // Field 13: atrace_name
+ if (_has_field_[13]) {
+ ::protozero::internal::gen_helpers::SerializeString(13, atrace_name_, msg);
+ }
+
+ // Field 14: description
+ if (_has_field_[14]) {
+ ::protozero::internal::gen_helpers::SerializeString(14, description_, msg);
+ }
+
+ // Field 3: process
+ if (_has_field_[3]) {
+ (*process_).Serialize(msg->BeginNestedMessage<::protozero::Message>(3));
+ }
+
+ // Field 6: chrome_process
+ if (_has_field_[6]) {
+ (*chrome_process_).Serialize(msg->BeginNestedMessage<::protozero::Message>(6));
+ }
+
+ // Field 4: thread
+ if (_has_field_[4]) {
+ (*thread_).Serialize(msg->BeginNestedMessage<::protozero::Message>(4));
+ }
+
+ // Field 7: chrome_thread
+ if (_has_field_[7]) {
+ (*chrome_thread_).Serialize(msg->BeginNestedMessage<::protozero::Message>(7));
+ }
+
+ // Field 8: counter
+ if (_has_field_[8]) {
+ (*counter_).Serialize(msg->BeginNestedMessage<::protozero::Message>(8));
+ }
+
+ // Field 18: state
+ if (_has_field_[18]) {
+ (*state_).Serialize(msg->BeginNestedMessage<::protozero::Message>(18));
+ }
+
+ // Field 9: disallow_merging_with_system_tracks
+ if (_has_field_[9]) {
+ ::protozero::internal::gen_helpers::SerializeTinyVarInt(9, disallow_merging_with_system_tracks_, msg);
+ }
+
+ // Field 11: child_ordering
+ if (_has_field_[11]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(11, child_ordering_, msg);
+ }
+
+ // Field 12: sibling_order_rank
+ if (_has_field_[12]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(12, sibling_order_rank_, msg);
+ }
+
+ // Field 15: sibling_merge_behavior
+ if (_has_field_[15]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(15, sibling_merge_behavior_, msg);
+ }
+
+ // Field 16: sibling_merge_key
+ if (_has_field_[16]) {
+ ::protozero::internal::gen_helpers::SerializeString(16, sibling_merge_key_, msg);
+ }
+
+ // Field 17: sibling_merge_key_int
+ if (_has_field_[17]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(17, sibling_merge_key_int_, msg);
+ }
+
+ // Field 19: process_ordering
+ if (_has_field_[19]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(19, process_ordering_, msg);
+ }
+
+ // Field 20: thread_ordering
+ if (_has_field_[20]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(20, thread_ordering_, msg);
+ }
+
+ protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
+}
+
+} // namespace perfetto
+} // namespace protos
+} // namespace gen
+#if defined(__GNUC__) || defined(__clang__)
+#pragma GCC diagnostic pop
+#endif
+// gen_amalgamated begin source: gen/protos/perfetto/trace/track_event/track_event.gen.cc
+// gen_amalgamated expanded: #include "perfetto/protozero/gen_field_helpers.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/message.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/packed_repeated_fields.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/proto_decoder.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/scattered_heap_buffer.h"
+// DO NOT EDIT. Autogenerated by Perfetto cppgen_plugin
+#if defined(__GNUC__) || defined(__clang__)
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wfloat-equal"
+#endif
+// gen_amalgamated expanded: #include "protos/perfetto/trace/track_event/track_event.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/trace/track_event/source_location.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/trace/track_event/screenshot.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/trace/track_event/chrome_window_handle_event_info.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/trace/track_event/chrome_user_event.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/trace/track_event/chrome_renderer_scheduler_state.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/trace/track_event/chrome_mojo_event_info.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/trace/track_event/chrome_message_pump.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/trace/track_event/chrome_legacy_ipc.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/trace/track_event/chrome_latency_info.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/trace/track_event/chrome_keyed_service.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/trace/track_event/chrome_histogram_sample.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/trace/track_event/chrome_frame_reporter.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/trace/track_event/chrome_content_settings_event_info.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/trace/track_event/chrome_compositor_scheduler_state.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/trace/track_event/chrome_application_state_info.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/trace/track_event/chrome_active_processes.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/trace/track_event/task_execution.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/trace/track_event/log_message.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/trace/track_event/debug_annotation.gen.h"
+
+namespace perfetto {
+namespace protos {
+namespace gen {
+
+EventName::EventName() = default;
+EventName::~EventName() = default;
+EventName::EventName(const EventName&) = default;
+EventName& EventName::operator=(const EventName&) = default;
+EventName::EventName(EventName&&) noexcept = default;
+EventName& EventName::operator=(EventName&&) = default;
+
+bool EventName::operator==(const EventName& other) const {
+ return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
+ && ::protozero::internal::gen_helpers::EqualsField(iid_, other.iid_)
+ && ::protozero::internal::gen_helpers::EqualsField(name_, other.name_);
+}
+
+bool EventName::ParseFromArray(const void* raw, size_t size) {
+ unknown_fields_.clear();
+ bool packed_error = false;
+
+ ::protozero::ProtoDecoder dec(raw, size);
+ for (auto field = dec.ReadField(); field.valid(); field = dec.ReadField()) {
+ if (field.id() < _has_field_.size()) {
+ _has_field_.set(field.id());
+ }
+ switch (field.id()) {
+ case 1 /* iid */:
+ field.get(&iid_);
+ break;
+ case 2 /* name */:
+ ::protozero::internal::gen_helpers::DeserializeString(field, &name_);
+ break;
+ default:
+ field.SerializeAndAppendTo(&unknown_fields_);
+ break;
+ }
+ }
+ return !packed_error && !dec.bytes_left();
+}
+
+std::string EventName::SerializeAsString() const {
+ ::protozero::internal::gen_helpers::MessageSerializer msg;
+ Serialize(msg.get());
+ return msg.SerializeAsString();
+}
+
+std::vector<uint8_t> EventName::SerializeAsArray() const {
+ ::protozero::internal::gen_helpers::MessageSerializer msg;
+ Serialize(msg.get());
+ return msg.SerializeAsArray();
+}
+
+void EventName::Serialize(::protozero::Message* msg) const {
+ // Field 1: iid
+ if (_has_field_[1]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(1, iid_, msg);
+ }
+
+ // Field 2: name
+ if (_has_field_[2]) {
+ ::protozero::internal::gen_helpers::SerializeString(2, name_, msg);
+ }
+
+ protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
+}
+
+
+EventCategory::EventCategory() = default;
+EventCategory::~EventCategory() = default;
+EventCategory::EventCategory(const EventCategory&) = default;
+EventCategory& EventCategory::operator=(const EventCategory&) = default;
+EventCategory::EventCategory(EventCategory&&) noexcept = default;
+EventCategory& EventCategory::operator=(EventCategory&&) = default;
+
+bool EventCategory::operator==(const EventCategory& other) const {
+ return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
+ && ::protozero::internal::gen_helpers::EqualsField(iid_, other.iid_)
+ && ::protozero::internal::gen_helpers::EqualsField(name_, other.name_);
+}
+
+bool EventCategory::ParseFromArray(const void* raw, size_t size) {
+ unknown_fields_.clear();
+ bool packed_error = false;
+
+ ::protozero::ProtoDecoder dec(raw, size);
+ for (auto field = dec.ReadField(); field.valid(); field = dec.ReadField()) {
+ if (field.id() < _has_field_.size()) {
+ _has_field_.set(field.id());
+ }
+ switch (field.id()) {
+ case 1 /* iid */:
+ field.get(&iid_);
+ break;
+ case 2 /* name */:
+ ::protozero::internal::gen_helpers::DeserializeString(field, &name_);
+ break;
+ default:
+ field.SerializeAndAppendTo(&unknown_fields_);
+ break;
+ }
+ }
+ return !packed_error && !dec.bytes_left();
+}
+
+std::string EventCategory::SerializeAsString() const {
+ ::protozero::internal::gen_helpers::MessageSerializer msg;
+ Serialize(msg.get());
+ return msg.SerializeAsString();
+}
+
+std::vector<uint8_t> EventCategory::SerializeAsArray() const {
+ ::protozero::internal::gen_helpers::MessageSerializer msg;
+ Serialize(msg.get());
+ return msg.SerializeAsArray();
+}
+
+void EventCategory::Serialize(::protozero::Message* msg) const {
+ // Field 1: iid
+ if (_has_field_[1]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(1, iid_, msg);
+ }
+
+ // Field 2: name
+ if (_has_field_[2]) {
+ ::protozero::internal::gen_helpers::SerializeString(2, name_, msg);
+ }
+
+ protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
+}
+
+
+TrackEventDefaults::TrackEventDefaults() = default;
+TrackEventDefaults::~TrackEventDefaults() = default;
+TrackEventDefaults::TrackEventDefaults(const TrackEventDefaults&) = default;
+TrackEventDefaults& TrackEventDefaults::operator=(const TrackEventDefaults&) = default;
+TrackEventDefaults::TrackEventDefaults(TrackEventDefaults&&) noexcept = default;
+TrackEventDefaults& TrackEventDefaults::operator=(TrackEventDefaults&&) = default;
+
+bool TrackEventDefaults::operator==(const TrackEventDefaults& other) const {
+ return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
+ && ::protozero::internal::gen_helpers::EqualsField(track_uuid_, other.track_uuid_)
+ && ::protozero::internal::gen_helpers::EqualsField(extra_counter_track_uuids_, other.extra_counter_track_uuids_)
+ && ::protozero::internal::gen_helpers::EqualsField(extra_double_counter_track_uuids_, other.extra_double_counter_track_uuids_);
+}
+
+bool TrackEventDefaults::ParseFromArray(const void* raw, size_t size) {
+ extra_counter_track_uuids_.clear();
+ extra_double_counter_track_uuids_.clear();
+ unknown_fields_.clear();
+ bool packed_error = false;
+
+ ::protozero::ProtoDecoder dec(raw, size);
+ for (auto field = dec.ReadField(); field.valid(); field = dec.ReadField()) {
+ if (field.id() < _has_field_.size()) {
+ _has_field_.set(field.id());
+ }
+ switch (field.id()) {
+ case 11 /* track_uuid */:
+ field.get(&track_uuid_);
+ break;
+ case 31 /* extra_counter_track_uuids */:
+ extra_counter_track_uuids_.emplace_back();
+ field.get(&extra_counter_track_uuids_.back());
+ break;
+ case 45 /* extra_double_counter_track_uuids */:
+ extra_double_counter_track_uuids_.emplace_back();
+ field.get(&extra_double_counter_track_uuids_.back());
+ break;
+ default:
+ field.SerializeAndAppendTo(&unknown_fields_);
+ break;
+ }
+ }
+ return !packed_error && !dec.bytes_left();
+}
+
+std::string TrackEventDefaults::SerializeAsString() const {
+ ::protozero::internal::gen_helpers::MessageSerializer msg;
+ Serialize(msg.get());
+ return msg.SerializeAsString();
+}
+
+std::vector<uint8_t> TrackEventDefaults::SerializeAsArray() const {
+ ::protozero::internal::gen_helpers::MessageSerializer msg;
+ Serialize(msg.get());
+ return msg.SerializeAsArray();
+}
+
+void TrackEventDefaults::Serialize(::protozero::Message* msg) const {
+ // Field 11: track_uuid
+ if (_has_field_[11]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(11, track_uuid_, msg);
+ }
+
+ // Field 31: extra_counter_track_uuids
+ for (auto& it : extra_counter_track_uuids_) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(31, it, msg);
+ }
+
+ // Field 45: extra_double_counter_track_uuids
+ for (auto& it : extra_double_counter_track_uuids_) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(45, it, msg);
+ }
+
+ protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
+}
+
+
+TrackEvent::TrackEvent() = default;
+TrackEvent::~TrackEvent() = default;
+TrackEvent::TrackEvent(const TrackEvent&) = default;
+TrackEvent& TrackEvent::operator=(const TrackEvent&) = default;
+TrackEvent::TrackEvent(TrackEvent&&) noexcept = default;
+TrackEvent& TrackEvent::operator=(TrackEvent&&) = default;
+
+bool TrackEvent::operator==(const TrackEvent& other) const {
+ return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
+ && ::protozero::internal::gen_helpers::EqualsField(category_iids_, other.category_iids_)
+ && ::protozero::internal::gen_helpers::EqualsField(categories_, other.categories_)
+ && ::protozero::internal::gen_helpers::EqualsField(name_iid_, other.name_iid_)
+ && ::protozero::internal::gen_helpers::EqualsField(name_, other.name_)
+ && ::protozero::internal::gen_helpers::EqualsField(type_, other.type_)
+ && ::protozero::internal::gen_helpers::EqualsField(track_uuid_, other.track_uuid_)
+ && ::protozero::internal::gen_helpers::EqualsField(counter_value_, other.counter_value_)
+ && ::protozero::internal::gen_helpers::EqualsField(double_counter_value_, other.double_counter_value_)
+ && ::protozero::internal::gen_helpers::EqualsField(extra_counter_track_uuids_, other.extra_counter_track_uuids_)
+ && ::protozero::internal::gen_helpers::EqualsField(extra_counter_values_, other.extra_counter_values_)
+ && ::protozero::internal::gen_helpers::EqualsField(extra_double_counter_track_uuids_, other.extra_double_counter_track_uuids_)
+ && ::protozero::internal::gen_helpers::EqualsField(extra_double_counter_values_, other.extra_double_counter_values_)
+ && ::protozero::internal::gen_helpers::EqualsField(flow_ids_old_, other.flow_ids_old_)
+ && ::protozero::internal::gen_helpers::EqualsField(flow_ids_, other.flow_ids_)
+ && ::protozero::internal::gen_helpers::EqualsField(terminating_flow_ids_old_, other.terminating_flow_ids_old_)
+ && ::protozero::internal::gen_helpers::EqualsField(terminating_flow_ids_, other.terminating_flow_ids_)
+ && ::protozero::internal::gen_helpers::EqualsField(correlation_id_, other.correlation_id_)
+ && ::protozero::internal::gen_helpers::EqualsField(correlation_id_str_, other.correlation_id_str_)
+ && ::protozero::internal::gen_helpers::EqualsField(correlation_id_str_iid_, other.correlation_id_str_iid_)
+ && ::protozero::internal::gen_helpers::EqualsField(callstack_, other.callstack_)
+ && ::protozero::internal::gen_helpers::EqualsField(callstack_iid_, other.callstack_iid_)
+ && ::protozero::internal::gen_helpers::EqualsField(callstack_weight_, other.callstack_weight_)
+ && ::protozero::internal::gen_helpers::EqualsField(debug_annotations_, other.debug_annotations_)
+ && ::protozero::internal::gen_helpers::EqualsField(task_execution_, other.task_execution_)
+ && ::protozero::internal::gen_helpers::EqualsField(log_message_, other.log_message_)
+ && ::protozero::internal::gen_helpers::EqualsField(cc_scheduler_state_, other.cc_scheduler_state_)
+ && ::protozero::internal::gen_helpers::EqualsField(chrome_user_event_, other.chrome_user_event_)
+ && ::protozero::internal::gen_helpers::EqualsField(chrome_keyed_service_, other.chrome_keyed_service_)
+ && ::protozero::internal::gen_helpers::EqualsField(chrome_legacy_ipc_, other.chrome_legacy_ipc_)
+ && ::protozero::internal::gen_helpers::EqualsField(chrome_histogram_sample_, other.chrome_histogram_sample_)
+ && ::protozero::internal::gen_helpers::EqualsField(chrome_latency_info_, other.chrome_latency_info_)
+ && ::protozero::internal::gen_helpers::EqualsField(chrome_frame_reporter_, other.chrome_frame_reporter_)
+ && ::protozero::internal::gen_helpers::EqualsField(chrome_application_state_info_, other.chrome_application_state_info_)
+ && ::protozero::internal::gen_helpers::EqualsField(chrome_renderer_scheduler_state_, other.chrome_renderer_scheduler_state_)
+ && ::protozero::internal::gen_helpers::EqualsField(chrome_window_handle_event_info_, other.chrome_window_handle_event_info_)
+ && ::protozero::internal::gen_helpers::EqualsField(chrome_content_settings_event_info_, other.chrome_content_settings_event_info_)
+ && ::protozero::internal::gen_helpers::EqualsField(chrome_active_processes_, other.chrome_active_processes_)
+ && ::protozero::internal::gen_helpers::EqualsField(screenshot_, other.screenshot_)
+ && ::protozero::internal::gen_helpers::EqualsField(source_location_, other.source_location_)
+ && ::protozero::internal::gen_helpers::EqualsField(source_location_iid_, other.source_location_iid_)
+ && ::protozero::internal::gen_helpers::EqualsField(chrome_message_pump_, other.chrome_message_pump_)
+ && ::protozero::internal::gen_helpers::EqualsField(chrome_mojo_event_info_, other.chrome_mojo_event_info_)
+ && ::protozero::internal::gen_helpers::EqualsField(timestamp_delta_us_, other.timestamp_delta_us_)
+ && ::protozero::internal::gen_helpers::EqualsField(timestamp_absolute_us_, other.timestamp_absolute_us_)
+ && ::protozero::internal::gen_helpers::EqualsField(thread_time_delta_us_, other.thread_time_delta_us_)
+ && ::protozero::internal::gen_helpers::EqualsField(thread_time_absolute_us_, other.thread_time_absolute_us_)
+ && ::protozero::internal::gen_helpers::EqualsField(thread_instruction_count_delta_, other.thread_instruction_count_delta_)
+ && ::protozero::internal::gen_helpers::EqualsField(thread_instruction_count_absolute_, other.thread_instruction_count_absolute_)
+ && ::protozero::internal::gen_helpers::EqualsField(legacy_event_, other.legacy_event_);
+}
+
+int TrackEvent::debug_annotations_size() const { return static_cast<int>(debug_annotations_.size()); }
+void TrackEvent::clear_debug_annotations() { debug_annotations_.clear(); }
+DebugAnnotation* TrackEvent::add_debug_annotations() { debug_annotations_.emplace_back(); return &debug_annotations_.back(); }
+bool TrackEvent::ParseFromArray(const void* raw, size_t size) {
+ category_iids_.clear();
+ categories_.clear();
+ extra_counter_track_uuids_.clear();
+ extra_counter_values_.clear();
+ extra_double_counter_track_uuids_.clear();
+ extra_double_counter_values_.clear();
+ flow_ids_old_.clear();
+ flow_ids_.clear();
+ terminating_flow_ids_old_.clear();
+ terminating_flow_ids_.clear();
+ debug_annotations_.clear();
+ unknown_fields_.clear();
+ bool packed_error = false;
+
+ ::protozero::ProtoDecoder dec(raw, size);
+ for (auto field = dec.ReadField(); field.valid(); field = dec.ReadField()) {
+ if (field.id() < _has_field_.size()) {
+ _has_field_.set(field.id());
+ }
+ switch (field.id()) {
+ case 3 /* category_iids */:
+ category_iids_.emplace_back();
+ field.get(&category_iids_.back());
+ break;
+ case 22 /* categories */:
+ categories_.emplace_back();
+ ::protozero::internal::gen_helpers::DeserializeString(field, &categories_.back());
+ break;
+ case 10 /* name_iid */:
+ field.get(&name_iid_);
+ break;
+ case 23 /* name */:
+ ::protozero::internal::gen_helpers::DeserializeString(field, &name_);
+ break;
+ case 9 /* type */:
+ field.get(&type_);
+ break;
+ case 11 /* track_uuid */:
+ field.get(&track_uuid_);
+ break;
+ case 30 /* counter_value */:
+ field.get(&counter_value_);
+ break;
+ case 44 /* double_counter_value */:
+ field.get(&double_counter_value_);
+ break;
+ case 31 /* extra_counter_track_uuids */:
+ extra_counter_track_uuids_.emplace_back();
+ field.get(&extra_counter_track_uuids_.back());
+ break;
+ case 12 /* extra_counter_values */:
+ extra_counter_values_.emplace_back();
+ field.get(&extra_counter_values_.back());
+ break;
+ case 45 /* extra_double_counter_track_uuids */:
+ extra_double_counter_track_uuids_.emplace_back();
+ field.get(&extra_double_counter_track_uuids_.back());
+ break;
+ case 46 /* extra_double_counter_values */:
+ extra_double_counter_values_.emplace_back();
+ field.get(&extra_double_counter_values_.back());
+ break;
+ case 36 /* flow_ids_old */:
+ flow_ids_old_.emplace_back();
+ field.get(&flow_ids_old_.back());
+ break;
+ case 47 /* flow_ids */:
+ flow_ids_.emplace_back();
+ field.get(&flow_ids_.back());
+ break;
+ case 42 /* terminating_flow_ids_old */:
+ terminating_flow_ids_old_.emplace_back();
+ field.get(&terminating_flow_ids_old_.back());
+ break;
+ case 48 /* terminating_flow_ids */:
+ terminating_flow_ids_.emplace_back();
+ field.get(&terminating_flow_ids_.back());
+ break;
+ case 52 /* correlation_id */:
+ field.get(&correlation_id_);
+ break;
+ case 53 /* correlation_id_str */:
+ ::protozero::internal::gen_helpers::DeserializeString(field, &correlation_id_str_);
+ break;
+ case 54 /* correlation_id_str_iid */:
+ field.get(&correlation_id_str_iid_);
+ break;
+ case 55 /* callstack */:
+ (*callstack_).ParseFromArray(field.data(), field.size());
+ break;
+ case 56 /* callstack_iid */:
+ field.get(&callstack_iid_);
+ break;
+ case 57 /* callstack_weight */:
+ field.get(&callstack_weight_);
+ break;
+ case 4 /* debug_annotations */:
+ debug_annotations_.emplace_back();
+ debug_annotations_.back().ParseFromArray(field.data(), field.size());
+ break;
+ case 5 /* task_execution */:
+ (*task_execution_).ParseFromArray(field.data(), field.size());
+ break;
+ case 21 /* log_message */:
+ (*log_message_).ParseFromArray(field.data(), field.size());
+ break;
+ case 24 /* cc_scheduler_state */:
+ (*cc_scheduler_state_).ParseFromArray(field.data(), field.size());
+ break;
+ case 25 /* chrome_user_event */:
+ (*chrome_user_event_).ParseFromArray(field.data(), field.size());
+ break;
+ case 26 /* chrome_keyed_service */:
+ (*chrome_keyed_service_).ParseFromArray(field.data(), field.size());
+ break;
+ case 27 /* chrome_legacy_ipc */:
+ (*chrome_legacy_ipc_).ParseFromArray(field.data(), field.size());
+ break;
+ case 28 /* chrome_histogram_sample */:
+ (*chrome_histogram_sample_).ParseFromArray(field.data(), field.size());
+ break;
+ case 29 /* chrome_latency_info */:
+ (*chrome_latency_info_).ParseFromArray(field.data(), field.size());
+ break;
+ case 32 /* chrome_frame_reporter */:
+ (*chrome_frame_reporter_).ParseFromArray(field.data(), field.size());
+ break;
+ case 39 /* chrome_application_state_info */:
+ (*chrome_application_state_info_).ParseFromArray(field.data(), field.size());
+ break;
+ case 40 /* chrome_renderer_scheduler_state */:
+ (*chrome_renderer_scheduler_state_).ParseFromArray(field.data(), field.size());
+ break;
+ case 41 /* chrome_window_handle_event_info */:
+ (*chrome_window_handle_event_info_).ParseFromArray(field.data(), field.size());
+ break;
+ case 43 /* chrome_content_settings_event_info */:
+ (*chrome_content_settings_event_info_).ParseFromArray(field.data(), field.size());
+ break;
+ case 49 /* chrome_active_processes */:
+ (*chrome_active_processes_).ParseFromArray(field.data(), field.size());
+ break;
+ case 50 /* screenshot */:
+ (*screenshot_).ParseFromArray(field.data(), field.size());
+ break;
+ case 33 /* source_location */:
+ (*source_location_).ParseFromArray(field.data(), field.size());
+ break;
+ case 34 /* source_location_iid */:
+ field.get(&source_location_iid_);
+ break;
+ case 35 /* chrome_message_pump */:
+ (*chrome_message_pump_).ParseFromArray(field.data(), field.size());
+ break;
+ case 38 /* chrome_mojo_event_info */:
+ (*chrome_mojo_event_info_).ParseFromArray(field.data(), field.size());
+ break;
+ case 1 /* timestamp_delta_us */:
+ field.get(×tamp_delta_us_);
+ break;
+ case 16 /* timestamp_absolute_us */:
+ field.get(×tamp_absolute_us_);
+ break;
+ case 2 /* thread_time_delta_us */:
+ field.get(&thread_time_delta_us_);
+ break;
+ case 17 /* thread_time_absolute_us */:
+ field.get(&thread_time_absolute_us_);
+ break;
+ case 8 /* thread_instruction_count_delta */:
+ field.get(&thread_instruction_count_delta_);
+ break;
+ case 20 /* thread_instruction_count_absolute */:
+ field.get(&thread_instruction_count_absolute_);
+ break;
+ case 6 /* legacy_event */:
+ (*legacy_event_).ParseFromArray(field.data(), field.size());
+ break;
+ default:
+ field.SerializeAndAppendTo(&unknown_fields_);
+ break;
+ }
+ }
+ return !packed_error && !dec.bytes_left();
+}
+
+std::string TrackEvent::SerializeAsString() const {
+ ::protozero::internal::gen_helpers::MessageSerializer msg;
+ Serialize(msg.get());
+ return msg.SerializeAsString();
+}
+
+std::vector<uint8_t> TrackEvent::SerializeAsArray() const {
+ ::protozero::internal::gen_helpers::MessageSerializer msg;
+ Serialize(msg.get());
+ return msg.SerializeAsArray();
+}
+
+void TrackEvent::Serialize(::protozero::Message* msg) const {
+ // Field 3: category_iids
+ for (auto& it : category_iids_) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(3, it, msg);
+ }
+
+ // Field 22: categories
+ for (auto& it : categories_) {
+ ::protozero::internal::gen_helpers::SerializeString(22, it, msg);
+ }
+
+ // Field 10: name_iid
+ if (_has_field_[10]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(10, name_iid_, msg);
+ }
+
+ // Field 23: name
+ if (_has_field_[23]) {
+ ::protozero::internal::gen_helpers::SerializeString(23, name_, msg);
+ }
+
+ // Field 9: type
+ if (_has_field_[9]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(9, type_, msg);
+ }
+
+ // Field 11: track_uuid
+ if (_has_field_[11]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(11, track_uuid_, msg);
+ }
+
+ // Field 30: counter_value
+ if (_has_field_[30]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(30, counter_value_, msg);
+ }
+
+ // Field 44: double_counter_value
+ if (_has_field_[44]) {
+ ::protozero::internal::gen_helpers::SerializeFixed(44, double_counter_value_, msg);
+ }
+
+ // Field 31: extra_counter_track_uuids
+ for (auto& it : extra_counter_track_uuids_) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(31, it, msg);
+ }
+
+ // Field 12: extra_counter_values
+ for (auto& it : extra_counter_values_) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(12, it, msg);
+ }
+
+ // Field 45: extra_double_counter_track_uuids
+ for (auto& it : extra_double_counter_track_uuids_) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(45, it, msg);
+ }
+
+ // Field 46: extra_double_counter_values
+ for (auto& it : extra_double_counter_values_) {
+ ::protozero::internal::gen_helpers::SerializeFixed(46, it, msg);
+ }
+
+ // Field 36: flow_ids_old
+ for (auto& it : flow_ids_old_) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(36, it, msg);
+ }
+
+ // Field 47: flow_ids
+ for (auto& it : flow_ids_) {
+ ::protozero::internal::gen_helpers::SerializeFixed(47, it, msg);
+ }
+
+ // Field 42: terminating_flow_ids_old
+ for (auto& it : terminating_flow_ids_old_) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(42, it, msg);
+ }
+
+ // Field 48: terminating_flow_ids
+ for (auto& it : terminating_flow_ids_) {
+ ::protozero::internal::gen_helpers::SerializeFixed(48, it, msg);
+ }
+
+ // Field 52: correlation_id
+ if (_has_field_[52]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(52, correlation_id_, msg);
+ }
+
+ // Field 53: correlation_id_str
+ if (_has_field_[53]) {
+ ::protozero::internal::gen_helpers::SerializeString(53, correlation_id_str_, msg);
+ }
+
+ // Field 54: correlation_id_str_iid
+ if (_has_field_[54]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(54, correlation_id_str_iid_, msg);
+ }
+
+ // Field 55: callstack
+ if (_has_field_[55]) {
+ (*callstack_).Serialize(msg->BeginNestedMessage<::protozero::Message>(55));
+ }
+
+ // Field 56: callstack_iid
+ if (_has_field_[56]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(56, callstack_iid_, msg);
+ }
+
+ // Field 57: callstack_weight
+ if (_has_field_[57]) {
+ ::protozero::internal::gen_helpers::SerializeFixed(57, callstack_weight_, msg);
+ }
+
+ // Field 4: debug_annotations
+ for (auto& it : debug_annotations_) {
+ it.Serialize(msg->BeginNestedMessage<::protozero::Message>(4));
+ }
+
+ // Field 5: task_execution
+ if (_has_field_[5]) {
+ (*task_execution_).Serialize(msg->BeginNestedMessage<::protozero::Message>(5));
+ }
+
+ // Field 21: log_message
+ if (_has_field_[21]) {
+ (*log_message_).Serialize(msg->BeginNestedMessage<::protozero::Message>(21));
+ }
+
+ // Field 24: cc_scheduler_state
+ if (_has_field_[24]) {
+ (*cc_scheduler_state_).Serialize(msg->BeginNestedMessage<::protozero::Message>(24));
+ }
+
+ // Field 25: chrome_user_event
+ if (_has_field_[25]) {
+ (*chrome_user_event_).Serialize(msg->BeginNestedMessage<::protozero::Message>(25));
+ }
+
+ // Field 26: chrome_keyed_service
+ if (_has_field_[26]) {
+ (*chrome_keyed_service_).Serialize(msg->BeginNestedMessage<::protozero::Message>(26));
+ }
+
+ // Field 27: chrome_legacy_ipc
+ if (_has_field_[27]) {
+ (*chrome_legacy_ipc_).Serialize(msg->BeginNestedMessage<::protozero::Message>(27));
+ }
+
+ // Field 28: chrome_histogram_sample
+ if (_has_field_[28]) {
+ (*chrome_histogram_sample_).Serialize(msg->BeginNestedMessage<::protozero::Message>(28));
+ }
+
+ // Field 29: chrome_latency_info
+ if (_has_field_[29]) {
+ (*chrome_latency_info_).Serialize(msg->BeginNestedMessage<::protozero::Message>(29));
+ }
+
+ // Field 32: chrome_frame_reporter
+ if (_has_field_[32]) {
+ (*chrome_frame_reporter_).Serialize(msg->BeginNestedMessage<::protozero::Message>(32));
+ }
+
+ // Field 39: chrome_application_state_info
+ if (_has_field_[39]) {
+ (*chrome_application_state_info_).Serialize(msg->BeginNestedMessage<::protozero::Message>(39));
+ }
+
+ // Field 40: chrome_renderer_scheduler_state
+ if (_has_field_[40]) {
+ (*chrome_renderer_scheduler_state_).Serialize(msg->BeginNestedMessage<::protozero::Message>(40));
+ }
+
+ // Field 41: chrome_window_handle_event_info
+ if (_has_field_[41]) {
+ (*chrome_window_handle_event_info_).Serialize(msg->BeginNestedMessage<::protozero::Message>(41));
+ }
+
+ // Field 43: chrome_content_settings_event_info
+ if (_has_field_[43]) {
+ (*chrome_content_settings_event_info_).Serialize(msg->BeginNestedMessage<::protozero::Message>(43));
+ }
+
+ // Field 49: chrome_active_processes
+ if (_has_field_[49]) {
+ (*chrome_active_processes_).Serialize(msg->BeginNestedMessage<::protozero::Message>(49));
+ }
+
+ // Field 50: screenshot
+ if (_has_field_[50]) {
+ (*screenshot_).Serialize(msg->BeginNestedMessage<::protozero::Message>(50));
+ }
+
+ // Field 33: source_location
+ if (_has_field_[33]) {
+ (*source_location_).Serialize(msg->BeginNestedMessage<::protozero::Message>(33));
+ }
+
+ // Field 34: source_location_iid
+ if (_has_field_[34]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(34, source_location_iid_, msg);
+ }
+
+ // Field 35: chrome_message_pump
+ if (_has_field_[35]) {
+ (*chrome_message_pump_).Serialize(msg->BeginNestedMessage<::protozero::Message>(35));
+ }
+
+ // Field 38: chrome_mojo_event_info
+ if (_has_field_[38]) {
+ (*chrome_mojo_event_info_).Serialize(msg->BeginNestedMessage<::protozero::Message>(38));
+ }
+
+ // Field 1: timestamp_delta_us
+ if (_has_field_[1]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(1, timestamp_delta_us_, msg);
+ }
+
+ // Field 16: timestamp_absolute_us
+ if (_has_field_[16]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(16, timestamp_absolute_us_, msg);
+ }
+
+ // Field 2: thread_time_delta_us
+ if (_has_field_[2]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(2, thread_time_delta_us_, msg);
+ }
+
+ // Field 17: thread_time_absolute_us
+ if (_has_field_[17]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(17, thread_time_absolute_us_, msg);
+ }
+
+ // Field 8: thread_instruction_count_delta
+ if (_has_field_[8]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(8, thread_instruction_count_delta_, msg);
+ }
+
+ // Field 20: thread_instruction_count_absolute
+ if (_has_field_[20]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(20, thread_instruction_count_absolute_, msg);
+ }
+
+ // Field 6: legacy_event
+ if (_has_field_[6]) {
+ (*legacy_event_).Serialize(msg->BeginNestedMessage<::protozero::Message>(6));
+ }
+
+ protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
+}
+
+
+TrackEvent_LegacyEvent::TrackEvent_LegacyEvent() = default;
+TrackEvent_LegacyEvent::~TrackEvent_LegacyEvent() = default;
+TrackEvent_LegacyEvent::TrackEvent_LegacyEvent(const TrackEvent_LegacyEvent&) = default;
+TrackEvent_LegacyEvent& TrackEvent_LegacyEvent::operator=(const TrackEvent_LegacyEvent&) = default;
+TrackEvent_LegacyEvent::TrackEvent_LegacyEvent(TrackEvent_LegacyEvent&&) noexcept = default;
+TrackEvent_LegacyEvent& TrackEvent_LegacyEvent::operator=(TrackEvent_LegacyEvent&&) = default;
+
+bool TrackEvent_LegacyEvent::operator==(const TrackEvent_LegacyEvent& other) const {
+ return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
+ && ::protozero::internal::gen_helpers::EqualsField(name_iid_, other.name_iid_)
+ && ::protozero::internal::gen_helpers::EqualsField(phase_, other.phase_)
+ && ::protozero::internal::gen_helpers::EqualsField(duration_us_, other.duration_us_)
+ && ::protozero::internal::gen_helpers::EqualsField(thread_duration_us_, other.thread_duration_us_)
+ && ::protozero::internal::gen_helpers::EqualsField(thread_instruction_delta_, other.thread_instruction_delta_)
+ && ::protozero::internal::gen_helpers::EqualsField(unscoped_id_, other.unscoped_id_)
+ && ::protozero::internal::gen_helpers::EqualsField(local_id_, other.local_id_)
+ && ::protozero::internal::gen_helpers::EqualsField(global_id_, other.global_id_)
+ && ::protozero::internal::gen_helpers::EqualsField(id_scope_, other.id_scope_)
+ && ::protozero::internal::gen_helpers::EqualsField(use_async_tts_, other.use_async_tts_)
+ && ::protozero::internal::gen_helpers::EqualsField(bind_id_, other.bind_id_)
+ && ::protozero::internal::gen_helpers::EqualsField(bind_to_enclosing_, other.bind_to_enclosing_)
+ && ::protozero::internal::gen_helpers::EqualsField(flow_direction_, other.flow_direction_)
+ && ::protozero::internal::gen_helpers::EqualsField(instant_event_scope_, other.instant_event_scope_)
+ && ::protozero::internal::gen_helpers::EqualsField(pid_override_, other.pid_override_)
+ && ::protozero::internal::gen_helpers::EqualsField(tid_override_, other.tid_override_);
+}
+
+bool TrackEvent_LegacyEvent::ParseFromArray(const void* raw, size_t size) {
+ unknown_fields_.clear();
+ bool packed_error = false;
+
+ ::protozero::ProtoDecoder dec(raw, size);
+ for (auto field = dec.ReadField(); field.valid(); field = dec.ReadField()) {
+ if (field.id() < _has_field_.size()) {
+ _has_field_.set(field.id());
+ }
+ switch (field.id()) {
+ case 1 /* name_iid */:
+ field.get(&name_iid_);
+ break;
+ case 2 /* phase */:
+ field.get(&phase_);
+ break;
+ case 3 /* duration_us */:
+ field.get(&duration_us_);
+ break;
+ case 4 /* thread_duration_us */:
+ field.get(&thread_duration_us_);
+ break;
+ case 15 /* thread_instruction_delta */:
+ field.get(&thread_instruction_delta_);
+ break;
+ case 6 /* unscoped_id */:
+ field.get(&unscoped_id_);
+ break;
+ case 10 /* local_id */:
+ field.get(&local_id_);
+ break;
+ case 11 /* global_id */:
+ field.get(&global_id_);
+ break;
+ case 7 /* id_scope */:
+ ::protozero::internal::gen_helpers::DeserializeString(field, &id_scope_);
+ break;
+ case 9 /* use_async_tts */:
+ field.get(&use_async_tts_);
+ break;
+ case 8 /* bind_id */:
+ field.get(&bind_id_);
+ break;
+ case 12 /* bind_to_enclosing */:
+ field.get(&bind_to_enclosing_);
+ break;
+ case 13 /* flow_direction */:
+ field.get(&flow_direction_);
+ break;
+ case 14 /* instant_event_scope */:
+ field.get(&instant_event_scope_);
+ break;
+ case 18 /* pid_override */:
+ field.get(&pid_override_);
+ break;
+ case 19 /* tid_override */:
+ field.get(&tid_override_);
+ break;
+ default:
+ field.SerializeAndAppendTo(&unknown_fields_);
+ break;
+ }
+ }
+ return !packed_error && !dec.bytes_left();
+}
+
+std::string TrackEvent_LegacyEvent::SerializeAsString() const {
+ ::protozero::internal::gen_helpers::MessageSerializer msg;
+ Serialize(msg.get());
+ return msg.SerializeAsString();
+}
+
+std::vector<uint8_t> TrackEvent_LegacyEvent::SerializeAsArray() const {
+ ::protozero::internal::gen_helpers::MessageSerializer msg;
+ Serialize(msg.get());
+ return msg.SerializeAsArray();
+}
+
+void TrackEvent_LegacyEvent::Serialize(::protozero::Message* msg) const {
+ // Field 1: name_iid
+ if (_has_field_[1]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(1, name_iid_, msg);
+ }
+
+ // Field 2: phase
+ if (_has_field_[2]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(2, phase_, msg);
+ }
+
+ // Field 3: duration_us
+ if (_has_field_[3]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(3, duration_us_, msg);
+ }
+
+ // Field 4: thread_duration_us
+ if (_has_field_[4]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(4, thread_duration_us_, msg);
+ }
+
+ // Field 15: thread_instruction_delta
+ if (_has_field_[15]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(15, thread_instruction_delta_, msg);
+ }
+
+ // Field 6: unscoped_id
+ if (_has_field_[6]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(6, unscoped_id_, msg);
+ }
+
+ // Field 10: local_id
+ if (_has_field_[10]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(10, local_id_, msg);
+ }
+
+ // Field 11: global_id
+ if (_has_field_[11]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(11, global_id_, msg);
+ }
+
+ // Field 7: id_scope
+ if (_has_field_[7]) {
+ ::protozero::internal::gen_helpers::SerializeString(7, id_scope_, msg);
+ }
+
+ // Field 9: use_async_tts
+ if (_has_field_[9]) {
+ ::protozero::internal::gen_helpers::SerializeTinyVarInt(9, use_async_tts_, msg);
+ }
+
+ // Field 8: bind_id
+ if (_has_field_[8]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(8, bind_id_, msg);
+ }
+
+ // Field 12: bind_to_enclosing
+ if (_has_field_[12]) {
+ ::protozero::internal::gen_helpers::SerializeTinyVarInt(12, bind_to_enclosing_, msg);
+ }
+
+ // Field 13: flow_direction
+ if (_has_field_[13]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(13, flow_direction_, msg);
+ }
+
+ // Field 14: instant_event_scope
+ if (_has_field_[14]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(14, instant_event_scope_, msg);
+ }
+
+ // Field 18: pid_override
+ if (_has_field_[18]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(18, pid_override_, msg);
+ }
+
+ // Field 19: tid_override
+ if (_has_field_[19]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(19, tid_override_, msg);
+ }
+
+ protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
+}
+
+
+TrackEvent_InlineCallstack::TrackEvent_InlineCallstack() = default;
+TrackEvent_InlineCallstack::~TrackEvent_InlineCallstack() = default;
+TrackEvent_InlineCallstack::TrackEvent_InlineCallstack(const TrackEvent_InlineCallstack&) = default;
+TrackEvent_InlineCallstack& TrackEvent_InlineCallstack::operator=(const TrackEvent_InlineCallstack&) = default;
+TrackEvent_InlineCallstack::TrackEvent_InlineCallstack(TrackEvent_InlineCallstack&&) noexcept = default;
+TrackEvent_InlineCallstack& TrackEvent_InlineCallstack::operator=(TrackEvent_InlineCallstack&&) = default;
+
+bool TrackEvent_InlineCallstack::operator==(const TrackEvent_InlineCallstack& other) const {
+ return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
+ && ::protozero::internal::gen_helpers::EqualsField(frames_, other.frames_);
+}
+
+int TrackEvent_InlineCallstack::frames_size() const { return static_cast<int>(frames_.size()); }
+void TrackEvent_InlineCallstack::clear_frames() { frames_.clear(); }
+TrackEvent_InlineCallstack_Frame* TrackEvent_InlineCallstack::add_frames() { frames_.emplace_back(); return &frames_.back(); }
+bool TrackEvent_InlineCallstack::ParseFromArray(const void* raw, size_t size) {
+ frames_.clear();
+ unknown_fields_.clear();
+ bool packed_error = false;
+
+ ::protozero::ProtoDecoder dec(raw, size);
+ for (auto field = dec.ReadField(); field.valid(); field = dec.ReadField()) {
+ if (field.id() < _has_field_.size()) {
+ _has_field_.set(field.id());
+ }
+ switch (field.id()) {
+ case 1 /* frames */:
+ frames_.emplace_back();
+ frames_.back().ParseFromArray(field.data(), field.size());
+ break;
+ default:
+ field.SerializeAndAppendTo(&unknown_fields_);
+ break;
+ }
+ }
+ return !packed_error && !dec.bytes_left();
+}
+
+std::string TrackEvent_InlineCallstack::SerializeAsString() const {
+ ::protozero::internal::gen_helpers::MessageSerializer msg;
+ Serialize(msg.get());
+ return msg.SerializeAsString();
+}
+
+std::vector<uint8_t> TrackEvent_InlineCallstack::SerializeAsArray() const {
+ ::protozero::internal::gen_helpers::MessageSerializer msg;
+ Serialize(msg.get());
+ return msg.SerializeAsArray();
+}
+
+void TrackEvent_InlineCallstack::Serialize(::protozero::Message* msg) const {
+ // Field 1: frames
+ for (auto& it : frames_) {
+ it.Serialize(msg->BeginNestedMessage<::protozero::Message>(1));
+ }
+
+ protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
+}
+
+
+TrackEvent_InlineCallstack_Frame::TrackEvent_InlineCallstack_Frame() = default;
+TrackEvent_InlineCallstack_Frame::~TrackEvent_InlineCallstack_Frame() = default;
+TrackEvent_InlineCallstack_Frame::TrackEvent_InlineCallstack_Frame(const TrackEvent_InlineCallstack_Frame&) = default;
+TrackEvent_InlineCallstack_Frame& TrackEvent_InlineCallstack_Frame::operator=(const TrackEvent_InlineCallstack_Frame&) = default;
+TrackEvent_InlineCallstack_Frame::TrackEvent_InlineCallstack_Frame(TrackEvent_InlineCallstack_Frame&&) noexcept = default;
+TrackEvent_InlineCallstack_Frame& TrackEvent_InlineCallstack_Frame::operator=(TrackEvent_InlineCallstack_Frame&&) = default;
+
+bool TrackEvent_InlineCallstack_Frame::operator==(const TrackEvent_InlineCallstack_Frame& other) const {
+ return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
+ && ::protozero::internal::gen_helpers::EqualsField(function_name_, other.function_name_)
+ && ::protozero::internal::gen_helpers::EqualsField(source_file_, other.source_file_)
+ && ::protozero::internal::gen_helpers::EqualsField(line_number_, other.line_number_);
+}
+
+bool TrackEvent_InlineCallstack_Frame::ParseFromArray(const void* raw, size_t size) {
+ unknown_fields_.clear();
+ bool packed_error = false;
+
+ ::protozero::ProtoDecoder dec(raw, size);
+ for (auto field = dec.ReadField(); field.valid(); field = dec.ReadField()) {
+ if (field.id() < _has_field_.size()) {
+ _has_field_.set(field.id());
+ }
+ switch (field.id()) {
+ case 1 /* function_name */:
+ ::protozero::internal::gen_helpers::DeserializeString(field, &function_name_);
+ break;
+ case 2 /* source_file */:
+ ::protozero::internal::gen_helpers::DeserializeString(field, &source_file_);
+ break;
+ case 3 /* line_number */:
+ field.get(&line_number_);
+ break;
+ default:
+ field.SerializeAndAppendTo(&unknown_fields_);
+ break;
+ }
+ }
+ return !packed_error && !dec.bytes_left();
+}
+
+std::string TrackEvent_InlineCallstack_Frame::SerializeAsString() const {
+ ::protozero::internal::gen_helpers::MessageSerializer msg;
+ Serialize(msg.get());
+ return msg.SerializeAsString();
+}
+
+std::vector<uint8_t> TrackEvent_InlineCallstack_Frame::SerializeAsArray() const {
+ ::protozero::internal::gen_helpers::MessageSerializer msg;
+ Serialize(msg.get());
+ return msg.SerializeAsArray();
+}
+
+void TrackEvent_InlineCallstack_Frame::Serialize(::protozero::Message* msg) const {
+ // Field 1: function_name
+ if (_has_field_[1]) {
+ ::protozero::internal::gen_helpers::SerializeString(1, function_name_, msg);
+ }
+
+ // Field 2: source_file
+ if (_has_field_[2]) {
+ ::protozero::internal::gen_helpers::SerializeString(2, source_file_, msg);
+ }
+
+ // Field 3: line_number
+ if (_has_field_[3]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(3, line_number_, msg);
+ }
+
+ protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
+}
+
+} // namespace perfetto
+} // namespace protos
+} // namespace gen
+#if defined(__GNUC__) || defined(__clang__)
+#pragma GCC diagnostic pop
+#endif
+// gen_amalgamated begin source: gen/protos/perfetto/common/semantic_type.pbzero.cc
+// Intentionally empty (crbug.com/998165)
+// gen_amalgamated begin source: gen/protos/perfetto/config/android/android_aflags_config.pbzero.cc
+// Intentionally empty (crbug.com/998165)
+// gen_amalgamated begin source: gen/protos/perfetto/config/android/android_game_intervention_list_config.pbzero.cc
+// Intentionally empty (crbug.com/998165)
+// gen_amalgamated begin source: gen/protos/perfetto/config/android/android_input_event_config.pbzero.cc
+// Intentionally empty (crbug.com/998165)
+// gen_amalgamated begin source: gen/protos/perfetto/config/android/android_log_config.pbzero.cc
+// Intentionally empty (crbug.com/998165)
+// gen_amalgamated begin source: gen/protos/perfetto/config/android/android_polled_state_config.pbzero.cc
+// Intentionally empty (crbug.com/998165)
+// gen_amalgamated begin source: gen/protos/perfetto/config/android/android_process_state_config.pbzero.cc
+// Intentionally empty (crbug.com/998165)
+// gen_amalgamated begin source: gen/protos/perfetto/config/android/android_sdk_sysprop_guard_config.pbzero.cc
+// Intentionally empty (crbug.com/998165)
+// gen_amalgamated begin source: gen/protos/perfetto/config/android/android_system_property_config.pbzero.cc
+// Intentionally empty (crbug.com/998165)
+// gen_amalgamated begin source: gen/protos/perfetto/config/android/app_wakelock_config.pbzero.cc
+// Intentionally empty (crbug.com/998165)
+// gen_amalgamated begin source: gen/protos/perfetto/config/android/cpu_per_uid_config.pbzero.cc
+// Intentionally empty (crbug.com/998165)
+// gen_amalgamated begin source: gen/protos/perfetto/config/android/display_video_config.pbzero.cc
+// Intentionally empty (crbug.com/998165)
+// gen_amalgamated begin source: gen/protos/perfetto/config/android/inputmethod_config.pbzero.cc
+// Intentionally empty (crbug.com/998165)
+// gen_amalgamated begin source: gen/protos/perfetto/config/android/kernel_wakelocks_config.pbzero.cc
+// Intentionally empty (crbug.com/998165)
+// gen_amalgamated begin source: gen/protos/perfetto/config/android/network_trace_config.pbzero.cc
+// Intentionally empty (crbug.com/998165)
+// gen_amalgamated begin source: gen/protos/perfetto/config/android/packages_list_config.pbzero.cc
+// Intentionally empty (crbug.com/998165)
+// gen_amalgamated begin source: gen/protos/perfetto/config/android/pixel_modem_config.pbzero.cc
+// Intentionally empty (crbug.com/998165)
+// gen_amalgamated begin source: gen/protos/perfetto/config/android/protolog_config.pbzero.cc
+// Intentionally empty (crbug.com/998165)
+// gen_amalgamated begin source: gen/protos/perfetto/config/android/surfaceflinger_layers_config.pbzero.cc
+// Intentionally empty (crbug.com/998165)
+// gen_amalgamated begin source: gen/protos/perfetto/config/android/surfaceflinger_transactions_config.pbzero.cc
+// Intentionally empty (crbug.com/998165)
+// gen_amalgamated begin source: gen/protos/perfetto/config/android/user_list_config.pbzero.cc
+// Intentionally empty (crbug.com/998165)
+// gen_amalgamated begin source: gen/protos/perfetto/config/android/windowmanager_config.pbzero.cc
+// Intentionally empty (crbug.com/998165)
+// gen_amalgamated begin source: gen/protos/perfetto/config/ftrace/frozen_ftrace_config.pbzero.cc
// Intentionally empty (crbug.com/998165)
// gen_amalgamated begin source: gen/protos/perfetto/config/ftrace/ftrace_config.pbzero.cc
// Intentionally empty (crbug.com/998165)
@@ -38336,8 +41817,12 @@ void TrackEvent_InlineCallstack_Frame::Serialize(::protozero::Message* msg) cons
// Intentionally empty (crbug.com/998165)
// gen_amalgamated begin source: gen/protos/perfetto/config/chrome/histogram_samples.pbzero.cc
// Intentionally empty (crbug.com/998165)
+// gen_amalgamated begin source: gen/protos/perfetto/config/chrome/sampling_heap_profiler.pbzero.cc
+// Intentionally empty (crbug.com/998165)
// gen_amalgamated begin source: gen/protos/perfetto/config/chrome/scenario_config.pbzero.cc
// Intentionally empty (crbug.com/998165)
+// gen_amalgamated begin source: gen/protos/perfetto/config/chrome/stack_sampling_profiler.pbzero.cc
+// Intentionally empty (crbug.com/998165)
// gen_amalgamated begin source: gen/protos/perfetto/config/chrome/system_metrics.pbzero.cc
// Intentionally empty (crbug.com/998165)
// gen_amalgamated begin source: gen/protos/perfetto/config/chrome/v8_config.pbzero.cc
@@ -38478,6 +41963,8 @@ void TrackEvent_InlineCallstack_Frame::Serialize(::protozero::Message* msg) cons
// Intentionally empty (crbug.com/998165)
// gen_amalgamated begin source: gen/protos/perfetto/trace/ftrace/perf_trace_counters.pbzero.cc
// Intentionally empty (crbug.com/998165)
+// gen_amalgamated begin source: gen/protos/perfetto/trace/ftrace/pixel_metrics.pbzero.cc
+// Intentionally empty (crbug.com/998165)
// gen_amalgamated begin source: gen/protos/perfetto/trace/ftrace/pixel_mm.pbzero.cc
// Intentionally empty (crbug.com/998165)
// gen_amalgamated begin source: gen/protos/perfetto/trace/ftrace/power.pbzero.cc
@@ -39301,7 +42788,7 @@ namespace perfetto {
// The SMB is *not* the ultimate logging buffer seen by the Consumer. That one
// is larger (~MBs) and not shared with Producers.
// Each SMB is small, typically few KB. Its size is configurable by the producer
-// within a max limit of ~MB (see kMaxShmSize in tracing_service_impl.cc).
+// within a max limit of ~MB (see kMaxShmSize in tracing_service.h).
// The SMB is partitioned into fixed-size Page(s). The size of the Pages are
// determined by each Producer at connection time and cannot be changed.
// Hence, different producers can have SMB(s) that have a different Page size
@@ -40512,6 +43999,55 @@ class ClientIdentity;
// TODO: for the moment this assumes that all the calls happen on the same
// thread/sequence. Not sure this will be the case long term in Chrome.
+// A shared memory layout and the operations that send its data to the service.
+// Each version is independent. Support for v2 does not imply support for v1.
+//
+// Each value is a single bit. Peers exchange and store a set of versions as a
+// uint32_t mask, e.g. kProtocolAbiV1 | kProtocolAbiV2.
+// A new version must take the next unused bit: 1 << 2, then 1 << 3.
+//
+// At connection setup:
+// - The producer sends the mask of versions it supports in
+// InitializeConnection.
+// - The service returns the mask of versions that both sides support.
+// - An old peer sends no mask. This means v1 only.
+// - No common version means the connection fails.
+// The proto enum in protos/perfetto/ipc/producer_port.proto has the same
+// values.
+//
+// The common mask stays fixed for the connection. A writer must use one of
+// these versions that its data source config and target buffer permit.
+//
+// A layout change that an old peer cannot read needs a new version.
+enum ProtocolAbiVersion : uint32_t {
+ // The original protocol.
+ // - The producer and the service share one shared memory buffer (SMB) of
+ // pages and chunks.
+ // - Writers fill chunks. The producer tells the service which chunks are
+ // complete with CommitData() IPCs.
+ // - Lengths of nested messages that cross a chunk are patched later, usually
+ // through CommitData().
+ // Layout: include/perfetto/ext/tracing/core/shared_memory_abi.h.
+ // Docs: https://perfetto.dev/docs/design-docs/api-and-abi#shmem-abi.
+ kProtocolAbiV1 = 1 << 0,
+
+ // Tracing v2. It is still under development and its ABI is not stable yet.
+ //
+ // The producer allocates a ring buffer:
+ // - AttachV2RingBuffer() shares it with the service, once.
+ // - Writers append chunks and never patch them. Nested messages use proto
+ // group encoding, so no length needs a patch.
+ // - DrainV2RingBuffer() asks the service to read it. There is no CommitData()
+ // for these chunks.
+ // A connection can use both writer types only if both versions are in the
+ // common mask. A writer sequence must use one format throughout its life.
+ // Layout: src/tracing/v2/shared_ring_buffer_abi.h.
+ // Design: RFC-0014, https://github.com/google/perfetto/discussions/4508.
+ // Ring buffer ABI: RFC-0046,
+ // https://github.com/google/perfetto/discussions/7120.
+ kProtocolAbiV2 = 1 << 1,
+};
+
// The API for the Producer port of the Service.
// Subclassed by:
// 1. The tracing_service_impl.cc business logic when returning it in response
@@ -40560,6 +44096,59 @@ class PERFETTO_EXPORT_COMPONENT ProducerEndpoint {
virtual SharedMemory* shared_memory() const = 0;
+ // Attempts to allocate and attach the producer's tracing v2 ring buffer.
+ // Call on the endpoint thread after tracing setup, if the caller selects v2.
+ // Complete this call before allowing writer threads to call
+ // CreateTraceWriterV2().
+ // - Uses |config|'s chunk size options and drain occupancy percentage.
+ // Pass the config of the first instance that selects v2.
+ // - After the first attempt, later calls on the same connection do nothing,
+ // even if the config differs or sizing, allocation or attachment failed.
+ // This keeps the arbiter pointer stable for writer threads, which read it
+ // without a lock.
+ // - Does not wait for the service's attach reply. Writers can publish while
+ // the reply is pending.
+ // - Does nothing if the endpoint or the connection has no tracing v2.
+ virtual void InitializeV2RingBuffer(const DataSourceConfig& config);
+
+ // Attaches the producer's tracing v2 ring buffer to the service, which
+ // installs a reader for it. The producer calls this on the endpoint
+ // sequence, before any DrainV2RingBuffer().
+ // - The producer owns |memory| and keeps it mapped for its writers.
+ // - Over IPC, ProducerIPCClientImpl sends the descriptor of |memory| in the
+ // AttachV2RingBuffer IPC. ProducerIPCService maps it and calls this on the
+ // service's ProducerEndpointImpl.
+ // - The ring buffer must be new: the reader starts at position 0. A ring
+ // buffer that another reader drained fails on the first drain.
+ //
+ // Results:
+ // - Accepted: the layout is valid and the reader exists. Data that the
+ // producer published before the call is kept. The service takes a
+ // reference to |memory| and keeps it until the producer disconnects.
+ // - Rejected: the connection and any existing attachment stay unchanged.
+ // The service keeps no reference to |memory|.
+ // If no ring buffer is attached, the producer can retry with a valid
+ // mapping.
+ // - |callback| runs on the endpoint sequence, possibly inline.
+ // - |memory| refers to the caller's shared_ptr, and |callback| may reset it.
+ // An implementation that needs the mapping after running |callback| must
+ // copy |memory| first.
+ virtual void AttachV2RingBuffer(const std::shared_ptr<SharedMemory>& memory,
+ uint32_t chunk_size_bytes,
+ std::function<void(bool)> callback);
+
+ // Requests a drain of the tracing v2 ring buffer, the equivalent of
+ // CommitData() for the v2 protocol.
+ //
+ // - Called on the producer endpoint sequence. The call has no reply.
+ // - Without an accepted ring buffer, the call does nothing.
+ // - The service processes requests from each producer in order. Flush relies
+ // on the drain completing before later requests, such as
+ // NotifyDataSourceStopped().
+ //
+ // See RFC 0046: https://github.com/google/perfetto/discussions/7120.
+ virtual void DrainV2RingBuffer();
+
// Size of shared memory buffer pages. It's always a multiple of 4K.
// See shared_memory_abi.h
virtual size_t shared_buffer_page_size_kb() const = 0;
@@ -40575,10 +44164,24 @@ class PERFETTO_EXPORT_COMPONENT ProducerEndpoint {
// writer should be stored by the tracing service. This value is passed
// upon creation of the data source (StartDataSource()) in the
// DataSourceConfig.target_buffer().
+ //
+ // This method always creates a v1 writer, which writes into the
+ // shared memory buffer (SMB).
+ // If v1 is not in the connection's common mask, it returns a
+ // NullTraceWriter, which discards all packets.
virtual std::unique_ptr<TraceWriter> CreateTraceWriter(
BufferID target_buffer,
BufferExhaustedPolicy buffer_exhausted_policy) = 0;
+ // |CreateTraceWriter| equivalent for tracing service v2.
+ // Creates a ring buffer writer, or a NullTraceWriter on failure.
+ // - Any thread can call it after InitializeV2RingBuffer() returns.
+ // - Does not initialize the ring buffer, and never falls back to v1.
+ // - Endpoints without tracing v2 support return a NullTraceWriter by default.
+ virtual std::unique_ptr<TraceWriter> CreateTraceWriterV2(
+ BufferID,
+ BufferExhaustedPolicy);
+
// TODO(eseckler): Also expose CreateStartupTraceWriter() ?
// In some cases you can access the producer's SharedMemoryArbiter (for
@@ -40827,6 +44430,8 @@ class PERFETTO_EXPORT_COMPONENT TracingService {
// Default sizes used by the service implementation and client library.
static constexpr size_t kDefaultShmPageSize = 4096ul;
static constexpr size_t kDefaultShmSize = 256 * 1024ul;
+ // Maximum size in bytes for service created or producer provided SMBs.
+ static constexpr size_t kMaxShmSize = 32 * 1024 * 1024ul;
enum class ProducerSMBScrapingMode {
// Use service's default setting for SMB scraping. Currently, the default
@@ -40859,8 +44464,9 @@ class PERFETTO_EXPORT_COMPONENT TracingService {
// specifically:
// 1) The Service will call Producer::* methods on the Service's task runner.
// 2) The Producer should call ProducerEndpoint::* methods only on the
- // service's task runner, except for ProducerEndpoint::CreateTraceWriter(),
- // which can be called on any thread. To disconnect just destroy the
+ // service's task runner, except for CreateTraceWriter() and
+ // CreateTraceWriterV2(), which can be called on any thread.
+ // To disconnect just destroy the
// returned ProducerEndpoint object. It is safe to destroy the Producer
// once the Producer::OnDisconnect() has been invoked.
//
@@ -40871,7 +44477,7 @@ class PERFETTO_EXPORT_COMPONENT TracingService {
// (e.g., if the hints are unreasonably large or other sizes were configured
// in a tracing session's config). |in_process| enables the ProducerEndpoint
// to manage its own shared memory and enables use of
- // |ProducerEndpoint::CreateTraceWriter|.
+ // |ProducerEndpoint::CreateTraceWriter| and |CreateTraceWriterV2|.
//
// The producer can optionally provide a non-null |shm|, which the service
// will adopt for the connection to the producer, provided it is correctly
@@ -40888,6 +44494,9 @@ class PERFETTO_EXPORT_COMPONENT TracingService {
// Producer::StartDataSource(). The |shm| will also be rejected when
// connecting to a service that is too old (pre Android-11).
//
+ // |protocol_abi_versions| is a bitmask of the ProtocolAbiVersion values that
+ // both peers support. It must not be zero. The default is v1 only.
+ //
// Can return null in the unlikely event that service has too many producers
// connected.
virtual std::unique_ptr<ProducerEndpoint> ConnectProducer(
@@ -40901,7 +44510,8 @@ class PERFETTO_EXPORT_COMPONENT TracingService {
size_t shared_memory_page_size_hint_bytes = 0,
std::unique_ptr<SharedMemory> shm = nullptr,
const std::string& sdk_version = {},
- const std::string& machine_name = {}) = 0;
+ const std::string& machine_name = {},
+ uint32_t protocol_abi_versions = kProtocolAbiV1) = 0;
// Connects a Consumer instance and obtains a ConsumerEndpoint, which is
// essentially a 1:1 channel between one Consumer and the Service.
@@ -41120,6 +44730,23 @@ class PERFETTO_EXPORT_COMPONENT SharedMemoryArbiter {
// true.
virtual bool TryShutdown() = 0;
+ // WriterIDs for tracing v2 ring buffer writers. Any thread can call these.
+ //
+ // Why v2 writers take their ID from this arbiter:
+ // - The service keys each sequence by (producer, WriterID). v1 and v2
+ // writers of one producer share that key space, so they share one pool.
+ // - A live ID makes TryShutdown() fail. This keeps the endpoint and the
+ // ring buffer alive until the last v2 writer is destroyed.
+ //
+ // Unlike CreateTraceWriter(), these do not call RegisterTraceWriter(): each
+ // ring buffer chunk names its own target buffer.
+ //
+ // Returns zero after shutdown or when all IDs are in use.
+ virtual WriterID AllocateTracingV2WriterID() = 0;
+ // Returns the ID to the pool. Call it after the writer's final publication:
+ // another writer can get the ID at once, and TryShutdown() can succeed.
+ virtual void ReleaseTracingV2WriterID(WriterID) = 0;
+
// Create a bound arbiter instance. Args:
// |SharedMemory|: the shared memory buffer to use.
// |page_size|: a multiple of 4KB that defines the granularity of tracing
@@ -41409,6 +45036,8 @@ class SharedMemoryArbiterImpl : public SharedMemoryArbiter {
void ScrapeEmulatedSharedMemoryBuffer(
const std::map<WriterID, BufferID>& buffer_for_writers) override;
bool TryShutdown() override;
+ WriterID AllocateTracingV2WriterID() override;
+ void ReleaseTracingV2WriterID(WriterID) override;
base::TaskRunner* task_runner() const { return task_runner_; }
size_t page_size() const { return shmem_abi_.page_size(); }
@@ -42421,6 +46050,12 @@ bool SharedMemoryArbiterImpl::TryDirectPatchLocked(
for (auto ctm_it = chunks_to_move.rbegin(); ctm_it != chunks_to_move.rend();
++ctm_it) {
uint32_t header_bitmap = shmem_abi_.GetPageHeaderBitmap(ctm_it->page());
+ // The page layout may have changed concurrently in shared memory.
+ // See b/513159433.
+ if (ctm_it->chunk() >=
+ SharedMemoryABI::GetNumChunksFromHeaderBitmap(header_bitmap)) {
+ continue;
+ }
auto chunk_state = shmem_abi_.GetChunkStateFromHeaderBitmap(
header_bitmap, ctm_it->chunk());
// Note: the subset of |commit_data_req_| chunks that still need patching is
@@ -42552,6 +46187,12 @@ void SharedMemoryArbiterImpl::FlushPendingCommitDataRequests(
// them to kChunkComplete - otherwise the service won't look at them.
for (auto& ctm : *commit_data_req_->mutable_chunks_to_move()) {
uint32_t header_bitmap = shmem_abi_.GetPageHeaderBitmap(ctm.page());
+ // The page layout may have changed concurrently in shared memory.
+ // See b/513159433.
+ if (ctm.chunk() >=
+ SharedMemoryABI::GetNumChunksFromHeaderBitmap(header_bitmap)) {
+ continue;
+ }
auto chunk_state = shmem_abi_.GetChunkStateFromHeaderBitmap(
header_bitmap, ctm.chunk());
// Note: the subset of |commit_data_req_| chunks that still need
@@ -43021,6 +46662,16 @@ std::unique_ptr<TraceWriter> SharedMemoryArbiterImpl::CreateTraceWriterInternal(
new TraceWriterImpl(this, id, target_buffer, buffer_exhausted_policy));
}
+WriterID SharedMemoryArbiterImpl::AllocateTracingV2WriterID() {
+ std::lock_guard<base::MaybeRtMutex> lock(lock_);
+ return did_shutdown_ ? 0 : active_writer_ids_.Allocate();
+}
+
+void SharedMemoryArbiterImpl::ReleaseTracingV2WriterID(WriterID id) {
+ std::lock_guard<base::MaybeRtMutex> lock(lock_);
+ active_writer_ids_.Free(id);
+}
+
void SharedMemoryArbiterImpl::ReleaseWriterID(WriterID id) {
base::TaskRunner* task_runner = nullptr;
base::WeakPtr<SharedMemoryArbiterImpl> weak_this;
@@ -43975,7 +47626,9 @@ class PERFETTO_EXPORT_COMPONENT Producer {
// gen_amalgamated expanded: #include "perfetto/ext/tracing/core/producer.h"
// gen_amalgamated expanded: #include "perfetto/ext/tracing/core/shared_memory.h"
// gen_amalgamated expanded: #include "perfetto/ext/tracing/core/shared_memory_arbiter.h"
+// gen_amalgamated expanded: #include "perfetto/ext/tracing/core/trace_writer.h"
// gen_amalgamated expanded: #include "perfetto/ext/tracing/core/tracing_service.h"
+// gen_amalgamated expanded: #include "src/tracing/core/null_trace_writer.h"
// gen_amalgamated expanded: #include "protos/perfetto/common/tracing_service_state.gen.h"
@@ -43999,6 +47652,26 @@ SharedMemoryArbiter::~SharedMemoryArbiter() = default;
// TODO(primiano): make pure virtual after various 3way patches.
void Consumer::OnSessionCloned(const OnSessionClonedArgs&) {}
+// Endpoints without tracing v2 support do not initialize a ring buffer.
+void ProducerEndpoint::InitializeV2RingBuffer(const DataSourceConfig&) {}
+
+// Endpoints without tracing v2 support reject ring buffers.
+void ProducerEndpoint::AttachV2RingBuffer(const std::shared_ptr<SharedMemory>&,
+ uint32_t,
+ std::function<void(bool)> callback) {
+ callback(false);
+}
+
+// Endpoints without tracing v2 support ignore drain requests.
+void ProducerEndpoint::DrainV2RingBuffer() {}
+
+// Endpoints without tracing v2 support discard v2 packets.
+std::unique_ptr<TraceWriter> ProducerEndpoint::CreateTraceWriterV2(
+ BufferID,
+ BufferExhaustedPolicy) {
+ return std::make_unique<NullTraceWriter>();
+}
+
} // namespace perfetto
// gen_amalgamated begin source: src/tracing/console_interceptor.cc
/*
@@ -44522,6 +48195,7 @@ bool DataSourceBase::CanAdoptStartupSession(
DataSourceConfig service_config_stripped = service_config;
startup_config_stripped.set_target_buffer(0);
+ startup_config_stripped.set_supports_tracing_v2(false);
startup_config_stripped.set_tracing_session_id(0);
startup_config_stripped.set_session_initiator(
DataSourceConfig::SESSION_INITIATOR_UNSPECIFIED);
@@ -44530,6 +48204,7 @@ bool DataSourceBase::CanAdoptStartupSession(
startup_config_stripped.set_enable_extra_guardrails(false);
service_config_stripped.set_target_buffer(0);
+ service_config_stripped.set_supports_tracing_v2(false);
service_config_stripped.set_tracing_session_id(0);
service_config_stripped.set_session_initiator(
DataSourceConfig::SESSION_INITIATOR_UNSPECIFIED);
@@ -44703,17 +48378,437 @@ struct PERFETTO_EXPORT_COMPONENT InternedDebugAnnotationValueTypeName
SmallInternedDataTraits> {
~InternedDebugAnnotationValueTypeName() override;
- static void Add(protos::pbzero::InternedData* interned_data,
- size_t iid,
- const char* value);
+ static void Add(protos::pbzero::InternedData* interned_data,
+ size_t iid,
+ const char* value);
+};
+
+} // namespace internal
+} // namespace perfetto
+
+#endif // INCLUDE_PERFETTO_TRACING_INTERNAL_TRACK_EVENT_INTERNED_FIELDS_H_
+/*
+ * 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.
+ */
+
+// gen_amalgamated expanded: #include "perfetto/tracing/event_context.h"
+
+// gen_amalgamated expanded: #include "perfetto/tracing/internal/track_event_interned_fields.h"
+// gen_amalgamated expanded: #include "protos/perfetto/trace/interned_data/interned_data.pbzero.h"
+// gen_amalgamated expanded: #include "protos/perfetto/trace/track_event/track_event.pbzero.h"
+
+namespace perfetto {
+
+EventContext::EventContext(
+ EventContext::TracePacketHandle trace_packet,
+ internal::TrackEventIncrementalState* incremental_state,
+ internal::TrackEventTlsState* tls_state)
+ : trace_packet_(std::move(trace_packet)),
+ event_(trace_packet_->set_track_event()),
+ incremental_state_(incremental_state),
+ tls_state_(tls_state) {}
+
+EventContext::~EventContext() {
+ if (!trace_packet_)
+ return;
+
+ // When the track event is finalized (i.e., the context is destroyed), we
+ // should flush any newly seen interned data to the trace. The data has
+ // earlier been written to a heap allocated protobuf message
+ // (|serialized_interned_data|). Here we just need to flush it to the main
+ // trace.
+ auto& serialized_interned_data = incremental_state_->serialized_interned_data;
+ if (PERFETTO_UNLIKELY(!serialized_interned_data.empty())) {
+ auto ranges = serialized_interned_data.GetRanges();
+ trace_packet_->AppendScatteredBytes(
+ perfetto::protos::pbzero::TracePacket::kInternedDataFieldNumber,
+ &ranges[0], ranges.size());
+
+ // Reset the message but keep one buffer allocated for future use.
+ serialized_interned_data.Reset();
+ }
+}
+
+protos::pbzero::DebugAnnotation* EventContext::AddDebugAnnotation(
+ const char* name) {
+ auto annotation = event()->add_debug_annotations();
+ annotation->set_name_iid(
+ internal::InternedDebugAnnotationName::Get(this, name));
+ return annotation;
+}
+
+protos::pbzero::DebugAnnotation* EventContext::AddDebugAnnotation(
+ ::perfetto::DynamicString name) {
+ auto annotation = event()->add_debug_annotations();
+ annotation->set_name(name.value);
+ return annotation;
+}
+
+TrackEventTlsStateUserData* EventContext::GetTlsUserData(const void* key) {
+ PERFETTO_CHECK(tls_state_);
+ PERFETTO_CHECK(key);
+ auto it = tls_state_->user_data.find(key);
+ if (it != tls_state_->user_data.end()) {
+ return it->second.get();
+ }
+ return nullptr;
+}
+
+void EventContext::SetTlsUserData(
+ const void* key,
+ std::unique_ptr<TrackEventTlsStateUserData> data) {
+ PERFETTO_CHECK(tls_state_);
+ PERFETTO_CHECK(key);
+ tls_state_->user_data[key] = std::move(data);
+}
+
+} // namespace perfetto
+// gen_amalgamated begin source: src/tracing/interceptor.cc
+/*
+ * 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.
+ */
+
+// gen_amalgamated expanded: #include "perfetto/tracing/interceptor.h"
+
+// gen_amalgamated expanded: #include "perfetto/tracing/internal/tracing_muxer.h"
+
+namespace perfetto {
+
+InterceptorBase::~InterceptorBase() = default;
+InterceptorBase::ThreadLocalState::~ThreadLocalState() = default;
+
+// static
+void InterceptorBase::RegisterImpl(
+ const InterceptorDescriptor& descriptor,
+ std::function<std::unique_ptr<InterceptorBase>()> factory,
+ InterceptorBase::TLSFactory tls_factory,
+ InterceptorBase::TracePacketCallback on_trace_packet) {
+ auto* tracing_impl = internal::TracingMuxer::Get();
+ tracing_impl->RegisterInterceptor(descriptor, factory, tls_factory,
+ on_trace_packet);
+}
+
+} // namespace perfetto
+// gen_amalgamated begin source: src/tracing/internal/checked_scope.cc
+/*
+ * Copyright (C) 2021 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.
+ */
+
+// gen_amalgamated expanded: #include "perfetto/tracing/internal/checked_scope.h"
+
+#include <utility>
+
+namespace perfetto {
+namespace internal {
+
+#if PERFETTO_DCHECK_IS_ON()
+CheckedScope::CheckedScope(CheckedScope* parent_scope)
+ : parent_scope_(parent_scope) {
+ if (parent_scope_) {
+ PERFETTO_DCHECK(parent_scope_->is_active());
+ parent_scope_->set_is_active(false);
+ }
+}
+
+CheckedScope::~CheckedScope() {
+ Reset();
+}
+
+void CheckedScope::Reset() {
+ if (!is_active_) {
+ // The only case when inactive scope could be destroyed is when Reset() was
+ // called explicitly or the contents of the object were moved away.
+ PERFETTO_DCHECK(deleted_);
+ return;
+ }
+ is_active_ = false;
+ deleted_ = true;
+ if (parent_scope_)
+ parent_scope_->set_is_active(true);
+}
+
+CheckedScope::CheckedScope(CheckedScope&& other) {
+ *this = std::move(other);
+}
+
+CheckedScope& CheckedScope::operator=(CheckedScope&& other) {
+ is_active_ = other.is_active_;
+ parent_scope_ = other.parent_scope_;
+ deleted_ = other.deleted_;
+
+ other.is_active_ = false;
+ other.parent_scope_ = nullptr;
+ other.deleted_ = true;
+
+ return *this;
+}
+#endif
+
+} // namespace internal
+} // namespace perfetto
+// gen_amalgamated begin source: src/tracing/internal/interceptor_trace_writer.cc
+// gen_amalgamated begin header: include/perfetto/tracing/internal/interceptor_trace_writer.h
+/*
+ * 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.
+ */
+
+#ifndef INCLUDE_PERFETTO_TRACING_INTERNAL_INTERCEPTOR_TRACE_WRITER_H_
+#define INCLUDE_PERFETTO_TRACING_INTERNAL_INTERCEPTOR_TRACE_WRITER_H_
+
+#include <atomic>
+#include <cstdint>
+#include <functional>
+#include <memory>
+
+// gen_amalgamated expanded: #include "perfetto/protozero/message_handle.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/scattered_heap_buffer.h"
+// gen_amalgamated expanded: #include "perfetto/tracing/interceptor.h"
+// gen_amalgamated expanded: #include "perfetto/tracing/internal/data_source_internal.h"
+// gen_amalgamated expanded: #include "perfetto/tracing/trace_writer_base.h"
+// gen_amalgamated expanded: #include "protos/perfetto/trace/trace_packet.pbzero.h"
+
+namespace perfetto {
+namespace internal {
+
+// A heap-backed trace writer used to reroute trace packets to an interceptor.
+class InterceptorTraceWriter : public TraceWriterBase {
+ public:
+ InterceptorTraceWriter(std::unique_ptr<InterceptorBase::ThreadLocalState> tls,
+ InterceptorBase::TracePacketCallback packet_callback,
+ DataSourceStaticState* static_state,
+ uint32_t instance_index);
+ ~InterceptorTraceWriter() override;
+
+ // TraceWriterBase implementation.
+ protozero::MessageHandle<protos::pbzero::TracePacket> NewTracePacket()
+ override;
+ void FinishTracePacket() override;
+ void Flush(std::function<void()> callback = {}) override;
+ uint64_t written() const override;
+ uint64_t drop_count() const override;
+
+ private:
+ std::unique_ptr<InterceptorBase::ThreadLocalState> tls_;
+ InterceptorBase::TracePacketCallback packet_callback_;
+
+ protozero::HeapBuffered<protos::pbzero::TracePacket> cur_packet_;
+ uint64_t bytes_written_ = 0;
+
+ // Static state of the data source we are intercepting.
+ DataSourceStaticState* const static_state_;
+
+ // Index of the data source tracing session which we are intercepting
+ // (0...kMaxDataSourceInstances - 1). Used to look up this interceptor's
+ // session state (i.e., the Interceptor class instance) in the
+ // DataSourceStaticState::instances array.
+ const uint32_t instance_index_;
+
+ const uint32_t sequence_id_;
+
+ static std::atomic<uint32_t> next_sequence_id_;
+};
+
+} // namespace internal
+} // namespace perfetto
+
+#endif // INCLUDE_PERFETTO_TRACING_INTERNAL_INTERCEPTOR_TRACE_WRITER_H_
+/*
+ * 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.
+ */
+
+// gen_amalgamated expanded: #include "perfetto/tracing/internal/interceptor_trace_writer.h"
+
+#include <atomic>
+#include <cstddef>
+#include <cstdint>
+#include <functional>
+#include <memory>
+#include <utility>
+
+// gen_amalgamated expanded: #include "perfetto/ext/tracing/core/trace_writer.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/field.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/message_handle.h"
+// gen_amalgamated expanded: #include "perfetto/tracing/interceptor.h"
+// gen_amalgamated expanded: #include "perfetto/tracing/internal/data_source_internal.h"
+
+namespace perfetto {
+namespace internal {
+
+// static
+std::atomic<uint32_t> InterceptorTraceWriter::next_sequence_id_{};
+
+InterceptorTraceWriter::InterceptorTraceWriter(
+ std::unique_ptr<InterceptorBase::ThreadLocalState> tls,
+ InterceptorBase::TracePacketCallback packet_callback,
+ DataSourceStaticState* static_state,
+ uint32_t instance_index)
+ : tls_(std::move(tls)),
+ packet_callback_(std::move(packet_callback)),
+ static_state_(static_state),
+ instance_index_(instance_index),
+ sequence_id_(++next_sequence_id_) {}
+
+InterceptorTraceWriter::~InterceptorTraceWriter() = default;
+
+protozero::MessageHandle<protos::pbzero::TracePacket>
+InterceptorTraceWriter::NewTracePacket() {
+ Flush();
+ auto packet = TraceWriter::TracePacketHandle(cur_packet_.get());
+ packet->set_trusted_packet_sequence_id(sequence_id_);
+ return packet;
+}
+
+void InterceptorTraceWriter::Flush(std::function<void()> callback) {
+ if (!cur_packet_.empty()) {
+ InterceptorBase::TracePacketCallbackArgs args{};
+ args.static_state = static_state_;
+ args.instance_index = instance_index_;
+ args.tls = tls_.get();
+
+ const auto& slices = cur_packet_.GetSlices();
+ if (slices.size() == 1) {
+ // Fast path: the current packet fits into a single slice.
+ auto slice_range = slices.begin()->GetUsedRange();
+ args.packet_data = protozero::ConstBytes{
+ slice_range.begin,
+ static_cast<size_t>(slice_range.end - slice_range.begin)};
+ bytes_written_ += static_cast<uint64_t>(args.packet_data.size);
+ packet_callback_(std::move(args));
+ } else {
+ // Fallback: stitch together multiple slices.
+ auto stitched_data = cur_packet_.SerializeAsArray();
+ args.packet_data =
+ protozero::ConstBytes{stitched_data.data(), stitched_data.size()};
+ bytes_written_ += static_cast<uint64_t>(stitched_data.size());
+ packet_callback_(std::move(args));
+ }
+ cur_packet_.Reset();
+ }
+ if (callback)
+ callback();
+}
+
+void InterceptorTraceWriter::FinishTracePacket() {}
+
+uint64_t InterceptorTraceWriter::written() const {
+ return bytes_written_;
+}
+
+uint64_t InterceptorTraceWriter::drop_count() const {
+ return 0;
+}
+
+} // namespace internal
+} // namespace perfetto
+// gen_amalgamated begin source: src/tracing/internal/tracing_backend_fake.cc
+// gen_amalgamated begin header: include/perfetto/tracing/internal/tracing_backend_fake.h
+/*
+ * Copyright (C) 2021 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_TRACING_INTERNAL_TRACING_BACKEND_FAKE_H_
+#define INCLUDE_PERFETTO_TRACING_INTERNAL_TRACING_BACKEND_FAKE_H_
+
+// gen_amalgamated expanded: #include "perfetto/base/export.h"
+// gen_amalgamated expanded: #include "perfetto/tracing/tracing_backend.h"
+
+namespace perfetto {
+namespace internal {
+
+// A built-in implementation of TracingBackend that fails any attempt to create
+// a tracing session.
+class PERFETTO_EXPORT_COMPONENT TracingBackendFake : public TracingBackend {
+ public:
+ static TracingBackend* GetInstance();
+
+ // TracingBackend implementation.
+ std::unique_ptr<ProducerEndpoint> ConnectProducer(
+ const ConnectProducerArgs&) override;
+ std::unique_ptr<ConsumerEndpoint> ConnectConsumer(
+ const ConnectConsumerArgs&) override;
+
+ private:
+ TracingBackendFake();
};
} // namespace internal
} // namespace perfetto
-#endif // INCLUDE_PERFETTO_TRACING_INTERNAL_TRACK_EVENT_INTERNED_FIELDS_H_
+#endif // INCLUDE_PERFETTO_TRACING_INTERNAL_TRACING_BACKEND_FAKE_H_
/*
- * Copyright (C) 2019 The Android Open Source Project
+ * Copyright (C) 2021 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.
@@ -44728,81 +48823,163 @@ struct PERFETTO_EXPORT_COMPONENT InternedDebugAnnotationValueTypeName
* limitations under the License.
*/
-// gen_amalgamated expanded: #include "perfetto/tracing/event_context.h"
+// gen_amalgamated expanded: #include "perfetto/tracing/internal/tracing_backend_fake.h"
-// gen_amalgamated expanded: #include "perfetto/tracing/internal/track_event_interned_fields.h"
-// gen_amalgamated expanded: #include "protos/perfetto/trace/interned_data/interned_data.pbzero.h"
-// gen_amalgamated expanded: #include "protos/perfetto/trace/track_event/track_event.pbzero.h"
+// gen_amalgamated expanded: #include "perfetto/base/task_runner.h"
+// gen_amalgamated expanded: #include "perfetto/ext/base/weak_ptr.h"
+// gen_amalgamated expanded: #include "perfetto/ext/tracing/core/consumer.h"
+// gen_amalgamated expanded: #include "perfetto/ext/tracing/core/producer.h"
+// gen_amalgamated expanded: #include "perfetto/ext/tracing/core/trace_writer.h"
+// gen_amalgamated expanded: #include "perfetto/ext/tracing/core/tracing_service.h"
namespace perfetto {
+namespace internal {
-EventContext::EventContext(
- EventContext::TracePacketHandle trace_packet,
- internal::TrackEventIncrementalState* incremental_state,
- internal::TrackEventTlsState* tls_state)
- : trace_packet_(std::move(trace_packet)),
- event_(trace_packet_->set_track_event()),
- incremental_state_(incremental_state),
- tls_state_(tls_state) {}
+namespace {
-EventContext::~EventContext() {
- if (!trace_packet_)
- return;
+class UnsupportedProducerEndpoint : public ProducerEndpoint {
+ public:
+ UnsupportedProducerEndpoint(Producer* producer, base::TaskRunner* task_runner)
+ : producer_(producer), task_runner_(task_runner) {
+ // The SDK will attempt to reconnect the producer, so instead we allow it
+ // to connect successfully, but never start any sessions.
+ auto weak_ptr = weak_ptr_factory_.GetWeakPtr();
+ task_runner_->PostTask([weak_ptr] {
+ if (weak_ptr && weak_ptr->connected_)
+ weak_ptr->producer_->OnConnect();
+ });
+ }
+ ~UnsupportedProducerEndpoint() override { Disconnect(); }
- // When the track event is finalized (i.e., the context is destroyed), we
- // should flush any newly seen interned data to the trace. The data has
- // earlier been written to a heap allocated protobuf message
- // (|serialized_interned_data|). Here we just need to flush it to the main
- // trace.
- auto& serialized_interned_data = incremental_state_->serialized_interned_data;
- if (PERFETTO_UNLIKELY(!serialized_interned_data.empty())) {
- auto ranges = serialized_interned_data.GetRanges();
- trace_packet_->AppendScatteredBytes(
- perfetto::protos::pbzero::TracePacket::kInternedDataFieldNumber,
- &ranges[0], ranges.size());
+ void Disconnect() override {
+ if (!connected_)
+ return;
+ connected_ = false;
+ producer_->OnDisconnect();
+ }
- // Reset the message but keep one buffer allocated for future use.
- serialized_interned_data.Reset();
+ void RegisterDataSource(const DataSourceDescriptor&) override {}
+ void UpdateDataSource(const DataSourceDescriptor&) override {}
+ void UnregisterDataSource(const std::string& /*name*/) override {}
+
+ void RegisterTraceWriter(uint32_t /*writer_id*/,
+ uint32_t /*target_buffer*/) override {}
+ void UnregisterTraceWriter(uint32_t /*writer_id*/) override {}
+
+ void CommitData(const CommitDataRequest&,
+ CommitDataCallback callback) override {
+ if (connected_) {
+ callback();
+ }
}
-}
-protos::pbzero::DebugAnnotation* EventContext::AddDebugAnnotation(
- const char* name) {
- auto annotation = event()->add_debug_annotations();
- annotation->set_name_iid(
- internal::InternedDebugAnnotationName::Get(this, name));
- return annotation;
-}
+ SharedMemory* shared_memory() const override { return nullptr; }
+ size_t shared_buffer_page_size_kb() const override { return 0; }
-protos::pbzero::DebugAnnotation* EventContext::AddDebugAnnotation(
- ::perfetto::DynamicString name) {
- auto annotation = event()->add_debug_annotations();
- annotation->set_name(name.value);
- return annotation;
-}
+ std::unique_ptr<TraceWriter> CreateTraceWriter(
+ BufferID /*target_buffer*/,
+ BufferExhaustedPolicy) override {
+ return nullptr;
+ }
-TrackEventTlsStateUserData* EventContext::GetTlsUserData(const void* key) {
- PERFETTO_CHECK(tls_state_);
- PERFETTO_CHECK(key);
- auto it = tls_state_->user_data.find(key);
- if (it != tls_state_->user_data.end()) {
- return it->second.get();
+ SharedMemoryArbiter* MaybeSharedMemoryArbiter() override { return nullptr; }
+ bool IsShmemProvidedByProducer() const override { return false; }
+
+ void NotifyFlushComplete(FlushRequestID) override {}
+ void NotifyDataSourceStarted(DataSourceInstanceID) override {}
+ void NotifyDataSourceStopped(DataSourceInstanceID) override {}
+ void ActivateTriggers(const std::vector<std::string>&) override {}
+
+ void Sync(std::function<void()> callback) override {
+ if (connected_) {
+ callback();
+ }
}
- return nullptr;
+
+ private:
+ Producer* const producer_;
+ base::TaskRunner* const task_runner_;
+ bool connected_ = true;
+ base::WeakPtrFactory<UnsupportedProducerEndpoint> weak_ptr_factory_{
+ this}; // Keep last.
+};
+
+class UnsupportedConsumerEndpoint : public ConsumerEndpoint {
+ public:
+ UnsupportedConsumerEndpoint(Consumer* consumer, base::TaskRunner* task_runner)
+ : consumer_(consumer), task_runner_(task_runner) {
+ // The SDK will not to reconnect the consumer, so we just disconnect it
+ // immediately, which will cancel the tracing session.
+ auto weak_this = weak_ptr_factory_.GetWeakPtr();
+ task_runner_->PostTask([weak_this] {
+ if (weak_this)
+ weak_this->consumer_->OnDisconnect();
+ });
+ }
+ ~UnsupportedConsumerEndpoint() override = default;
+
+ void EnableTracing(const TraceConfig&, base::ScopedFile) override {}
+ void ChangeTraceConfig(const TraceConfig&) override {}
+
+ void StartTracing() override {}
+ void DisableTracing() override {}
+
+ void Flush(uint32_t /*timeout_ms*/,
+ FlushCallback callback,
+ FlushFlags) override {
+ callback(/*success=*/false);
+ }
+
+ void ReadBuffers() override {}
+ void FreeBuffers() override {}
+
+ void Detach(const std::string& /*key*/) override {}
+ void Attach(const std::string& /*key*/) override {}
+
+ void GetTraceStats() override {}
+ void ObserveEvents(uint32_t /*events_mask*/) override {}
+ void QueryServiceState(QueryServiceStateArgs,
+ QueryServiceStateCallback) override {}
+ void QueryCapabilities(QueryCapabilitiesCallback) override {}
+
+ void SaveTraceForBugreport(SaveTraceForBugreportCallback) override {}
+ void CloneSession(CloneSessionArgs) override {}
+
+ private:
+ Consumer* const consumer_;
+ base::TaskRunner* const task_runner_;
+ base::WeakPtrFactory<UnsupportedConsumerEndpoint> weak_ptr_factory_{
+ this}; // Keep last.
+};
+
+} // namespace
+
+// static
+TracingBackend* TracingBackendFake::GetInstance() {
+ static auto* instance = new TracingBackendFake();
+ return instance;
}
-void EventContext::SetTlsUserData(
- const void* key,
- std::unique_ptr<TrackEventTlsStateUserData> data) {
- PERFETTO_CHECK(tls_state_);
- PERFETTO_CHECK(key);
- tls_state_->user_data[key] = std::move(data);
+TracingBackendFake::TracingBackendFake() = default;
+
+std::unique_ptr<ProducerEndpoint> TracingBackendFake::ConnectProducer(
+ const ConnectProducerArgs& args) {
+ return std::unique_ptr<ProducerEndpoint>(
+ new UnsupportedProducerEndpoint(args.producer, args.task_runner));
+}
+
+std::unique_ptr<ConsumerEndpoint> TracingBackendFake::ConnectConsumer(
+ const ConnectConsumerArgs& args) {
+ return std::unique_ptr<ConsumerEndpoint>(
+ new UnsupportedConsumerEndpoint(args.consumer, args.task_runner));
}
+} // namespace internal
} // namespace perfetto
-// gen_amalgamated begin source: src/tracing/interceptor.cc
+// gen_amalgamated begin source: src/tracing/internal/tracing_muxer_fake.cc
+// gen_amalgamated begin header: src/tracing/internal/tracing_muxer_fake.h
/*
- * Copyright (C) 2020 The Android Open Source Project
+ * Copyright (C) 2021 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.
@@ -44817,28 +48994,65 @@ void EventContext::SetTlsUserData(
* limitations under the License.
*/
-// gen_amalgamated expanded: #include "perfetto/tracing/interceptor.h"
+#ifndef SRC_TRACING_INTERNAL_TRACING_MUXER_FAKE_H_
+#define SRC_TRACING_INTERNAL_TRACING_MUXER_FAKE_H_
+// gen_amalgamated expanded: #include "perfetto/base/compiler.h"
// gen_amalgamated expanded: #include "perfetto/tracing/internal/tracing_muxer.h"
namespace perfetto {
+namespace internal {
-InterceptorBase::~InterceptorBase() = default;
-InterceptorBase::ThreadLocalState::~ThreadLocalState() = default;
+// An always-fail implementation of TracingMuxer. Before tracing has been
+// initialized, all muxer operations will route here and fail with a helpful
+// error message. This is to avoid introducing null checks in
+// performance-critical parts of the codebase.
+class TracingMuxerFake : public TracingMuxer {
+ class FakePlatform : public Platform {
+ public:
+ ~FakePlatform() override;
+ ThreadLocalObject* GetOrCreateThreadLocalObject() override;
+ std::unique_ptr<base::TaskRunner> CreateTaskRunner(
+ const CreateTaskRunnerArgs&) override;
+ std::string GetCurrentProcessName() override;
-// static
-void InterceptorBase::RegisterImpl(
- const InterceptorDescriptor& descriptor,
- std::function<std::unique_ptr<InterceptorBase>()> factory,
- InterceptorBase::TLSFactory tls_factory,
- InterceptorBase::TracePacketCallback on_trace_packet) {
- auto* tracing_impl = internal::TracingMuxer::Get();
- tracing_impl->RegisterInterceptor(descriptor, factory, tls_factory,
- on_trace_packet);
-}
+ static FakePlatform instance;
+ };
+
+ public:
+ TracingMuxerFake() : TracingMuxer(&FakePlatform::instance) {}
+ ~TracingMuxerFake() override;
+
+ static constexpr TracingMuxerFake* Get() { return &instance; }
+
+ // TracingMuxer implementation.
+ bool RegisterDataSource(const DataSourceDescriptor&,
+ DataSourceFactory,
+ DataSourceParams,
+ bool,
+ DataSourceStaticState*) override;
+ void UpdateDataSourceDescriptor(const DataSourceDescriptor&,
+ const DataSourceStaticState*) override;
+ std::unique_ptr<TraceWriterBase> CreateTraceWriter(
+ DataSourceStaticState*,
+ uint32_t data_source_instance_index,
+ DataSourceState*,
+ BufferExhaustedPolicy buffer_exhausted_policy) override;
+ void DestroyStoppedTraceWritersForCurrentThread() override;
+ void RegisterInterceptor(const InterceptorDescriptor&,
+ InterceptorFactory,
+ InterceptorBase::TLSFactory,
+ InterceptorBase::TracePacketCallback) override;
+ void ActivateTriggers(const std::vector<std::string>&, uint32_t) override;
+
+ private:
+ static TracingMuxerFake instance;
+};
+} // namespace internal
} // namespace perfetto
-// gen_amalgamated begin source: src/tracing/internal/checked_scope.cc
+
+#endif // SRC_TRACING_INTERNAL_TRACING_MUXER_FAKE_H_
/*
* Copyright (C) 2021 The Android Open Source Project
*
@@ -44855,62 +49069,88 @@ void InterceptorBase::RegisterImpl(
* limitations under the License.
*/
-// gen_amalgamated expanded: #include "perfetto/tracing/internal/checked_scope.h"
-
-#include <utility>
+// gen_amalgamated expanded: #include "src/tracing/internal/tracing_muxer_fake.h"
namespace perfetto {
namespace internal {
+namespace {
-#if PERFETTO_DCHECK_IS_ON()
-CheckedScope::CheckedScope(CheckedScope* parent_scope)
- : parent_scope_(parent_scope) {
- if (parent_scope_) {
- PERFETTO_DCHECK(parent_scope_->is_active());
- parent_scope_->set_is_active(false);
- }
+PERFETTO_NORETURN void FailUninitialized() {
+ PERFETTO_FATAL(
+ "Tracing not initialized. Call perfetto::Tracing::Initialize() first.");
}
-CheckedScope::~CheckedScope() {
- Reset();
+} // namespace
+
+// static
+PERFETTO_NO_DESTROY TracingMuxerFake::FakePlatform
+ TracingMuxerFake::FakePlatform::instance{};
+// static
+PERFETTO_NO_DESTROY TracingMuxerFake TracingMuxerFake::instance{};
+
+TracingMuxerFake::~TracingMuxerFake() = default;
+
+TracingMuxerFake::FakePlatform::~FakePlatform() = default;
+
+Platform::ThreadLocalObject*
+TracingMuxerFake::FakePlatform::GetOrCreateThreadLocalObject() {
+ FailUninitialized();
}
-void CheckedScope::Reset() {
- if (!is_active_) {
- // The only case when inactive scope could be destroyed is when Reset() was
- // called explicitly or the contents of the object were moved away.
- PERFETTO_DCHECK(deleted_);
- return;
- }
- is_active_ = false;
- deleted_ = true;
- if (parent_scope_)
- parent_scope_->set_is_active(true);
+std::unique_ptr<base::TaskRunner>
+TracingMuxerFake::FakePlatform::CreateTaskRunner(const CreateTaskRunnerArgs&) {
+ FailUninitialized();
}
-CheckedScope::CheckedScope(CheckedScope&& other) {
- *this = std::move(other);
+std::string TracingMuxerFake::FakePlatform::GetCurrentProcessName() {
+ FailUninitialized();
}
-CheckedScope& CheckedScope::operator=(CheckedScope&& other) {
- is_active_ = other.is_active_;
- parent_scope_ = other.parent_scope_;
- deleted_ = other.deleted_;
+bool TracingMuxerFake::RegisterDataSource(const DataSourceDescriptor&,
+ DataSourceFactory,
+ DataSourceParams,
+ bool,
+ DataSourceStaticState*) {
+ FailUninitialized();
+}
- other.is_active_ = false;
- other.parent_scope_ = nullptr;
- other.deleted_ = true;
+void TracingMuxerFake::UpdateDataSourceDescriptor(
+ const DataSourceDescriptor&,
+ const DataSourceStaticState*) {
+ FailUninitialized();
+}
- return *this;
+std::unique_ptr<TraceWriterBase> TracingMuxerFake::CreateTraceWriter(
+ DataSourceStaticState*,
+ uint32_t,
+ DataSourceState*,
+ BufferExhaustedPolicy) {
+ FailUninitialized();
+}
+
+void TracingMuxerFake::DestroyStoppedTraceWritersForCurrentThread() {
+ FailUninitialized();
+}
+
+void TracingMuxerFake::RegisterInterceptor(
+ const InterceptorDescriptor&,
+ InterceptorFactory,
+ InterceptorBase::TLSFactory,
+ InterceptorBase::TracePacketCallback) {
+ FailUninitialized();
+}
+
+void TracingMuxerFake::ActivateTriggers(const std::vector<std::string>&,
+ uint32_t) {
+ FailUninitialized();
}
-#endif
} // namespace internal
} // namespace perfetto
-// gen_amalgamated begin source: src/tracing/internal/interceptor_trace_writer.cc
-// gen_amalgamated begin header: include/perfetto/tracing/internal/interceptor_trace_writer.h
+// gen_amalgamated begin source: src/tracing/internal/tracing_muxer_impl.cc
+// gen_amalgamated begin header: src/tracing/internal/tracing_muxer_impl.h
/*
- * Copyright (C) 2020 The Android Open Source Project
+ * 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.
@@ -44925,386 +49165,577 @@ CheckedScope& CheckedScope::operator=(CheckedScope&& other) {
* limitations under the License.
*/
-#ifndef INCLUDE_PERFETTO_TRACING_INTERNAL_INTERCEPTOR_TRACE_WRITER_H_
-#define INCLUDE_PERFETTO_TRACING_INTERNAL_INTERCEPTOR_TRACE_WRITER_H_
+#ifndef SRC_TRACING_INTERNAL_TRACING_MUXER_IMPL_H_
+#define SRC_TRACING_INTERNAL_TRACING_MUXER_IMPL_H_
+#include <stddef.h>
+#include <stdint.h>
+
+#include <array>
#include <atomic>
-#include <cstdint>
+#include <bitset>
#include <functional>
+#include <list>
+#include <map>
#include <memory>
+#include <set>
+#include <utility>
+#include <vector>
-// gen_amalgamated expanded: #include "perfetto/protozero/message_handle.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/scattered_heap_buffer.h"
-// gen_amalgamated expanded: #include "perfetto/tracing/interceptor.h"
-// gen_amalgamated expanded: #include "perfetto/tracing/internal/data_source_internal.h"
-// gen_amalgamated expanded: #include "perfetto/tracing/trace_writer_base.h"
-// gen_amalgamated expanded: #include "protos/perfetto/trace/trace_packet.pbzero.h"
+// gen_amalgamated expanded: #include "perfetto/base/time.h"
+// gen_amalgamated expanded: #include "perfetto/ext/base/scoped_file.h"
+// gen_amalgamated expanded: #include "perfetto/ext/base/thread_checker.h"
+// gen_amalgamated expanded: #include "perfetto/ext/tracing/core/basic_types.h"
+// gen_amalgamated expanded: #include "perfetto/ext/tracing/core/consumer.h"
+// gen_amalgamated expanded: #include "perfetto/ext/tracing/core/producer.h"
+// gen_amalgamated expanded: #include "perfetto/ext/tracing/core/tracing_service.h"
+// gen_amalgamated expanded: #include "perfetto/tracing/backend_type.h"
+// gen_amalgamated expanded: #include "perfetto/tracing/core/data_source_descriptor.h"
+// gen_amalgamated expanded: #include "perfetto/tracing/core/forward_decls.h"
+// gen_amalgamated expanded: #include "perfetto/tracing/core/trace_config.h"
+// gen_amalgamated expanded: #include "perfetto/tracing/internal/basic_types.h"
+// gen_amalgamated expanded: #include "perfetto/tracing/internal/tracing_muxer.h"
+// gen_amalgamated expanded: #include "perfetto/tracing/tracing.h"
+
+// gen_amalgamated expanded: #include "protos/perfetto/common/interceptor_descriptor.gen.h"
+
+namespace perfetto {
+
+class ConsumerEndpoint;
+class DataSourceBase;
+class ProducerEndpoint;
+class TraceWriterBase;
+class TracingBackend;
+class TracingSession;
+struct TracingInitArgs;
+
+namespace base {
+class TaskRunner;
+}
+
+namespace shlib {
+void ResetForTesting();
+}
+
+namespace test {
+class TracingMuxerImplInternalsForTest;
+}
+
+namespace internal {
+
+struct DataSourceStaticState;
+
+// This class acts as a bridge between the public API and the TracingBackend(s).
+// It exposes a simplified view of the world to the API methods handling all the
+// bookkeeping to map data source instances and trace writers to the various
+// backends. It deals with N data sources, M backends (1 backend == 1 tracing
+// service == 1 producer connection) and T concurrent tracing sessions.
+//
+// Handing data source registration and start/stop flows [producer side]:
+// ----------------------------------------------------------------------
+// 1. The API client subclasses perfetto::DataSource and calls
+// DataSource::Register<MyDataSource>(). In turn this calls into the
+// TracingMuxer.
+// 2. The tracing muxer iterates through all the backends (1 backend == 1
+// service == 1 producer connection) and registers the data source on each
+// backend.
+// 3. When any (services behind a) backend starts tracing and requests to start
+// that specific data source, the TracingMuxerImpl constructs a new instance
+// of MyDataSource and calls the OnStart() method.
+//
+// Controlling trace and retrieving trace data [consumer side]:
+// ------------------------------------------------------------
+// 1. The API client calls Tracing::NewTrace(), returns a RAII TracingSession
+// object.
+// 2. NewTrace() calls into internal::TracingMuxer(Impl). TracingMuxer
+// subclasses the TracingSession object (TracingSessionImpl) and returns it.
+// 3. The tracing muxer identifies the backend (according to the args passed to
+// NewTrace), creates a new Consumer and connects to it.
+// 4. When the API client calls Start()/Stop()/ReadTrace() methods, the
+// TracingMuxer forwards them to the consumer associated to the
+// TracingSession. Likewise for callbacks coming from the consumer-side of
+// the service.
+class TracingMuxerImpl : public TracingMuxer {
+ public:
+ // This is different than TracingSessionID because it's global across all
+ // backends. TracingSessionID is global only within the scope of one service.
+ using TracingSessionGlobalID = uint64_t;
+
+ struct RegisteredDataSource {
+ DataSourceDescriptor descriptor;
+ DataSourceFactory factory{};
+ DataSourceParams params;
+ bool no_flush = false;
+ DataSourceStaticState* static_state = nullptr;
+ };
+
+ static void InitializeInstance(const TracingInitArgs&);
+ static void ResetForTesting();
+ static void Shutdown();
+
+ // TracingMuxer implementation.
+ bool RegisterDataSource(const DataSourceDescriptor&,
+ DataSourceFactory,
+ DataSourceParams,
+ bool no_flush,
+ DataSourceStaticState*) override;
+ void UpdateDataSourceDescriptor(const DataSourceDescriptor&,
+ const DataSourceStaticState*) override;
+ std::unique_ptr<TraceWriterBase> CreateTraceWriter(
+ DataSourceStaticState*,
+ uint32_t data_source_instance_index,
+ DataSourceState*,
+ BufferExhaustedPolicy buffer_exhausted_policy) override;
+ void DestroyStoppedTraceWritersForCurrentThread() override;
+ void RegisterInterceptor(const InterceptorDescriptor&,
+ InterceptorFactory,
+ InterceptorBase::TLSFactory,
+ InterceptorBase::TracePacketCallback) override;
+
+ void ActivateTriggers(const std::vector<std::string>&, uint32_t) override;
+
+ std::unique_ptr<TracingSession> CreateTracingSession(
+ BackendType,
+ TracingConsumerBackend* (*system_backend_factory)());
+ std::unique_ptr<StartupTracingSession> CreateStartupTracingSession(
+ const TraceConfig& config,
+ Tracing::SetupStartupTracingOpts);
+ std::unique_ptr<StartupTracingSession> CreateStartupTracingSessionBlocking(
+ const TraceConfig& config,
+ Tracing::SetupStartupTracingOpts);
-namespace perfetto {
-namespace internal {
+ // Producer-side bookkeeping methods.
+ void UpdateDataSourcesOnAllBackends();
+ void SetupDataSource(TracingBackendId,
+ uint32_t backend_connection_id,
+ DataSourceInstanceID,
+ const DataSourceConfig&);
+ void StartDataSource(TracingBackendId, DataSourceInstanceID);
+ void StopDataSource_AsyncBegin(TracingBackendId, DataSourceInstanceID);
+ void ClearDataSourceIncrementalState(TracingBackendId, DataSourceInstanceID);
+ void SyncProducersForTesting();
-// A heap-backed trace writer used to reroute trace packets to an interceptor.
-class InterceptorTraceWriter : public TraceWriterBase {
- public:
- InterceptorTraceWriter(std::unique_ptr<InterceptorBase::ThreadLocalState> tls,
- InterceptorBase::TracePacketCallback packet_callback,
- DataSourceStaticState* static_state,
- uint32_t instance_index);
- ~InterceptorTraceWriter() override;
+ // Consumer-side bookkeeping methods.
+ void SetupTracingSession(TracingSessionGlobalID,
+ const std::shared_ptr<TraceConfig>&,
+ base::ScopedFile trace_fd = base::ScopedFile());
+ void StartTracingSession(TracingSessionGlobalID);
+ void CloneTracingSession(TracingSessionGlobalID,
+ TracingSession::CloneTraceArgs,
+ TracingSession::CloneTraceCallback);
+ void ChangeTracingSessionConfig(TracingSessionGlobalID, const TraceConfig&);
+ void StopTracingSession(TracingSessionGlobalID);
+ void DestroyTracingSession(TracingSessionGlobalID);
+ void FlushTracingSession(TracingSessionGlobalID,
+ uint32_t,
+ std::function<void(bool)>);
+ void ReadTracingSessionData(
+ TracingSessionGlobalID,
+ std::function<void(TracingSession::ReadTraceCallbackArgs)>);
+ void GetTraceStats(TracingSessionGlobalID,
+ TracingSession::GetTraceStatsCallback);
+ void QueryServiceState(TracingSessionGlobalID,
+ TracingSession::QueryServiceStateCallback);
- // TraceWriterBase implementation.
- protozero::MessageHandle<protos::pbzero::TracePacket> NewTracePacket()
- override;
- void FinishTracePacket() override;
- void Flush(std::function<void()> callback = {}) override;
- uint64_t written() const override;
- uint64_t drop_count() const override;
+ // Sets the batching period to |batch_commits_duration_ms| on the backends
+ // with type |backend_type|.
+ void SetBatchCommitsDurationForTesting(uint32_t batch_commits_duration_ms,
+ BackendType backend_type);
- private:
- std::unique_ptr<InterceptorBase::ThreadLocalState> tls_;
- InterceptorBase::TracePacketCallback packet_callback_;
+ // Enables direct SMB patching on the backends with type |backend_type| (see
+ // SharedMemoryArbiter::EnableDirectSMBPatching). Returns true if the
+ // operation succeeded for all backends with type |backend_type|, false
+ // otherwise.
+ bool EnableDirectSMBPatchingForTesting(BackendType backend_type);
- protozero::HeapBuffered<protos::pbzero::TracePacket> cur_packet_;
- uint64_t bytes_written_ = 0;
+ void SetMaxProducerReconnectionsForTesting(uint32_t count);
- // Static state of the data source we are intercepting.
- DataSourceStaticState* const static_state_;
+ private:
+ friend class test::TracingMuxerImplInternalsForTest;
+ friend void shlib::ResetForTesting();
- // Index of the data source tracing session which we are intercepting
- // (0...kMaxDataSourceInstances - 1). Used to look up this interceptor's
- // session state (i.e., the Interceptor class instance) in the
- // DataSourceStaticState::instances array.
- const uint32_t instance_index_;
+ // For each TracingBackend we create and register one ProducerImpl instance.
+ // This talks to the producer-side of the service, gets start/stop requests
+ // from it and routes them to the registered data sources.
+ // One ProducerImpl == one backend == one tracing service.
+ // This class is needed to disambiguate callbacks coming from different
+ // services. TracingMuxerImpl can't directly implement the Producer interface
+ // because the Producer virtual methods don't allow to identify the service.
+ class ProducerImpl : public Producer {
+ public:
+ ProducerImpl(TracingMuxerImpl*,
+ TracingBackendId,
+ uint32_t shmem_batch_commits_duration_ms,
+ bool shmem_direct_patching_enabled);
+ ~ProducerImpl() override;
- const uint32_t sequence_id_;
+ void Initialize(std::unique_ptr<ProducerEndpoint> endpoint);
+ void RegisterDataSource(const DataSourceDescriptor&,
+ DataSourceFactory,
+ DataSourceStaticState*);
+ void DisposeConnection();
- static std::atomic<uint32_t> next_sequence_id_;
-};
+ // perfetto::Producer implementation.
+ void OnConnect() override;
+ void OnDisconnect() override;
+ void OnTracingSetup() override;
+ void OnStartupTracingSetup() override;
+ void SetupDataSource(DataSourceInstanceID,
+ const DataSourceConfig&) override;
+ void StartDataSource(DataSourceInstanceID,
+ const DataSourceConfig&) override;
+ void StopDataSource(DataSourceInstanceID) override;
+ void Flush(FlushRequestID,
+ const DataSourceInstanceID*,
+ size_t,
+ FlushFlags) override;
+ void ClearIncrementalState(const DataSourceInstanceID*, size_t) override;
-} // namespace internal
-} // namespace perfetto
+ bool SweepDeadServices();
+ void SendOnConnectTriggers();
+ void NotifyFlushForDataSourceDone(DataSourceInstanceID, FlushRequestID);
-#endif // INCLUDE_PERFETTO_TRACING_INTERNAL_INTERCEPTOR_TRACE_WRITER_H_
-/*
- * 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.
- */
+ PERFETTO_THREAD_CHECKER(thread_checker_)
+ TracingMuxerImpl* muxer_;
+ TracingBackendId const backend_id_;
+ bool connected_ = false;
+ bool did_setup_tracing_ = false;
+ bool did_setup_startup_tracing_ = false;
+ std::atomic<uint32_t> connection_id_{0};
+ uint16_t last_startup_target_buffer_reservation_ = 0;
+ bool is_producer_provided_smb_ = false;
+ bool producer_provided_smb_failed_ = false;
-// gen_amalgamated expanded: #include "perfetto/tracing/internal/interceptor_trace_writer.h"
+ const uint32_t shmem_batch_commits_duration_ms_ = 0;
+ const bool shmem_direct_patching_enabled_ = false;
-#include <atomic>
-#include <cstddef>
-#include <cstdint>
-#include <functional>
-#include <memory>
-#include <utility>
+ // Set of data sources that have been actually registered on this producer.
+ // This can be a subset of the global |data_sources_|, because data sources
+ // can register before the producer is fully connected.
+ std::bitset<kMaxDataSources> registered_data_sources_{};
-// gen_amalgamated expanded: #include "perfetto/ext/tracing/core/trace_writer.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/field.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/message_handle.h"
-// gen_amalgamated expanded: #include "perfetto/tracing/interceptor.h"
-// gen_amalgamated expanded: #include "perfetto/tracing/internal/data_source_internal.h"
+ // A collection of disconnected service endpoints. Since trace writers on
+ // arbitrary threads might continue writing data to disconnected services,
+ // we keep the old services around and periodically try to clean up ones
+ // that no longer have any writers (see SweepDeadServices).
+ std::list<std::shared_ptr<ProducerEndpoint>> dead_services_;
-namespace perfetto {
-namespace internal {
+ // Triggers that should be sent when the service connects (trigger_name,
+ // expiration).
+ std::list<std::pair<std::string, base::TimeMillis>> on_connect_triggers_;
-// static
-std::atomic<uint32_t> InterceptorTraceWriter::next_sequence_id_{};
+ std::map<FlushRequestID, std::set<DataSourceInstanceID>> pending_flushes_;
-InterceptorTraceWriter::InterceptorTraceWriter(
- std::unique_ptr<InterceptorBase::ThreadLocalState> tls,
- InterceptorBase::TracePacketCallback packet_callback,
- DataSourceStaticState* static_state,
- uint32_t instance_index)
- : tls_(std::move(tls)),
- packet_callback_(std::move(packet_callback)),
- static_state_(static_state),
- instance_index_(instance_index),
- sequence_id_(++next_sequence_id_) {}
+ // The currently active service endpoint is maintained as an atomic shared
+ // pointer so it won't get deleted from underneath threads that are creating
+ // trace writers. At any given time one endpoint can be shared (and thus
+ // kept alive) by the |service_| pointer, an entry in |dead_services_| and
+ // as a pointer on the stack in CreateTraceWriter() (on an arbitrary
+ // thread). The endpoint is never shared outside ProducerImpl itself.
+ //
+ // WARNING: Any *write* access to this variable or any *read* access from a
+ // non-muxer thread must be done through std::atomic_{load,store} to avoid
+ // data races.
+ std::shared_ptr<ProducerEndpoint> service_; // Keep last.
+ };
-InterceptorTraceWriter::~InterceptorTraceWriter() = default;
+ // For each TracingSession created by the API client (Tracing::NewTrace() we
+ // create and register one ConsumerImpl instance.
+ // This talks to the consumer-side of the service, gets end-of-trace and
+ // on-trace-data callbacks and routes them to the API client callbacks.
+ // This class is needed to disambiguate callbacks coming from different
+ // tracing sessions.
+ class ConsumerImpl : public Consumer {
+ public:
+ ConsumerImpl(TracingMuxerImpl*, BackendType, TracingSessionGlobalID);
+ ~ConsumerImpl() override;
-protozero::MessageHandle<protos::pbzero::TracePacket>
-InterceptorTraceWriter::NewTracePacket() {
- Flush();
- auto packet = TraceWriter::TracePacketHandle(cur_packet_.get());
- packet->set_trusted_packet_sequence_id(sequence_id_);
- return packet;
-}
+ void Initialize(std::unique_ptr<ConsumerEndpoint> endpoint);
-void InterceptorTraceWriter::Flush(std::function<void()> callback) {
- if (!cur_packet_.empty()) {
- InterceptorBase::TracePacketCallbackArgs args{};
- args.static_state = static_state_;
- args.instance_index = instance_index_;
- args.tls = tls_.get();
+ // perfetto::Consumer implementation.
+ void OnConnect() override;
+ void OnDisconnect() override;
+ void OnTracingDisabled(const std::string& error) override;
+ void OnTraceData(std::vector<TracePacket>, bool has_more) override;
+ void OnDetach(bool success) override;
+ void OnAttach(bool success, const TraceConfig&) override;
+ void OnTraceStats(bool success, const TraceStats&) override;
+ void OnObservableEvents(const ObservableEvents&) override;
+ void OnSessionCloned(const OnSessionClonedArgs&) override;
- const auto& slices = cur_packet_.GetSlices();
- if (slices.size() == 1) {
- // Fast path: the current packet fits into a single slice.
- auto slice_range = slices.begin()->GetUsedRange();
- args.packet_data = protozero::ConstBytes{
- slice_range.begin,
- static_cast<size_t>(slice_range.end - slice_range.begin)};
- bytes_written_ += static_cast<uint64_t>(args.packet_data.size);
- packet_callback_(std::move(args));
- } else {
- // Fallback: stitch together multiple slices.
- auto stitched_data = cur_packet_.SerializeAsArray();
- args.packet_data =
- protozero::ConstBytes{stitched_data.data(), stitched_data.size()};
- bytes_written_ += static_cast<uint64_t>(stitched_data.size());
- packet_callback_(std::move(args));
- }
- cur_packet_.Reset();
- }
- if (callback)
- callback();
-}
+ void NotifyStartComplete();
+ void NotifyError(const TracingError&);
+ void NotifyStopComplete();
-void InterceptorTraceWriter::FinishTracePacket() {}
+ // Will eventually inform the |muxer_| when it is safe to remove |this|.
+ void Disconnect();
-uint64_t InterceptorTraceWriter::written() const {
- return bytes_written_;
-}
+ TracingMuxerImpl* muxer_;
+ BackendType const backend_type_;
+ TracingSessionGlobalID const session_id_;
+ bool connected_ = false;
-uint64_t InterceptorTraceWriter::drop_count() const {
- return 0;
-}
+ // This is to handle the case where the Setup call from the API client
+ // arrives before the consumer has connected. In this case we keep around
+ // the config and check if we have it after connection.
+ bool start_pending_ = false;
-} // namespace internal
-} // namespace perfetto
-// gen_amalgamated begin source: src/tracing/internal/tracing_backend_fake.cc
-// gen_amalgamated begin header: include/perfetto/tracing/internal/tracing_backend_fake.h
-/*
- * Copyright (C) 2021 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.
- */
+ // Similarly if the session is stopped before the consumer was connected, we
+ // need to wait until the session has started before stopping it.
+ bool stop_pending_ = false;
-#ifndef INCLUDE_PERFETTO_TRACING_INTERNAL_TRACING_BACKEND_FAKE_H_
-#define INCLUDE_PERFETTO_TRACING_INTERNAL_TRACING_BACKEND_FAKE_H_
+ // Similarly we need to buffer a call to get trace statistics if the
+ // consumer wasn't connected yet.
+ bool get_trace_stats_pending_ = false;
-// gen_amalgamated expanded: #include "perfetto/base/export.h"
-// gen_amalgamated expanded: #include "perfetto/tracing/tracing_backend.h"
+ // Similarly we need to buffer a session cloning args if the session is
+ // cloning another sesison before the consumer was connected.
+ std::optional<ConsumerEndpoint::CloneSessionArgs> session_to_clone_;
-namespace perfetto {
-namespace internal {
+ // Whether this session was already stopped. This will happen in response to
+ // Stop{,Blocking}, but also if the service stops the session for us
+ // automatically (e.g., when there are no data sources).
+ bool stopped_ = false;
-// A built-in implementation of TracingBackend that fails any attempt to create
-// a tracing session.
-class PERFETTO_EXPORT_COMPONENT TracingBackendFake : public TracingBackend {
- public:
- static TracingBackend* GetInstance();
+ // shared_ptr because it's posted across threads. This is to avoid copying
+ // it more than once.
+ std::shared_ptr<TraceConfig> trace_config_;
+ base::ScopedFile trace_fd_;
- // TracingBackend implementation.
- std::unique_ptr<ProducerEndpoint> ConnectProducer(
- const ConnectProducerArgs&) override;
- std::unique_ptr<ConsumerEndpoint> ConnectConsumer(
- const ConnectConsumerArgs&) override;
+ // If the API client passes a callback to start, we should invoke this when
+ // NotifyStartComplete() is invoked.
+ std::function<void()> start_complete_callback_;
- private:
- TracingBackendFake();
-};
+ // An internal callback used to implement StartBlocking().
+ std::function<void()> blocking_start_complete_callback_;
-} // namespace internal
-} // namespace perfetto
+ // If the API client passes a callback to get notification about the
+ // errors, we should invoke this when NotifyError() is invoked.
+ std::function<void(TracingError)> error_callback_;
-#endif // INCLUDE_PERFETTO_TRACING_INTERNAL_TRACING_BACKEND_FAKE_H_
-/*
- * Copyright (C) 2021 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.
- */
+ // If the API client passes a callback to stop, we should invoke this when
+ // OnTracingDisabled() is invoked.
+ std::function<void()> stop_complete_callback_;
-// gen_amalgamated expanded: #include "perfetto/tracing/internal/tracing_backend_fake.h"
+ // An internal callback used to implement StopBlocking().
+ std::function<void()> blocking_stop_complete_callback_;
-// gen_amalgamated expanded: #include "perfetto/base/task_runner.h"
-// gen_amalgamated expanded: #include "perfetto/ext/base/weak_ptr.h"
-// gen_amalgamated expanded: #include "perfetto/ext/tracing/core/consumer.h"
-// gen_amalgamated expanded: #include "perfetto/ext/tracing/core/producer.h"
-// gen_amalgamated expanded: #include "perfetto/ext/tracing/core/trace_writer.h"
-// gen_amalgamated expanded: #include "perfetto/ext/tracing/core/tracing_service.h"
+ // Callback for a pending call to CloneTrace().
+ TracingSession::CloneTraceCallback clone_trace_callback_;
-namespace perfetto {
-namespace internal {
+ // Callback passed to ReadTrace().
+ std::function<void(TracingSession::ReadTraceCallbackArgs)>
+ read_trace_callback_;
-namespace {
+ // Callback passed to GetTraceStats().
+ TracingSession::GetTraceStatsCallback get_trace_stats_callback_;
-class UnsupportedProducerEndpoint : public ProducerEndpoint {
- public:
- UnsupportedProducerEndpoint(Producer* producer, base::TaskRunner* task_runner)
- : producer_(producer), task_runner_(task_runner) {
- // The SDK will attempt to reconnect the producer, so instead we allow it
- // to connect successfully, but never start any sessions.
- auto weak_ptr = weak_ptr_factory_.GetWeakPtr();
- task_runner_->PostTask([weak_ptr] {
- if (weak_ptr && weak_ptr->connected_)
- weak_ptr->producer_->OnConnect();
- });
- }
- ~UnsupportedProducerEndpoint() override { Disconnect(); }
+ // Callback for a pending call to QueryServiceState().
+ TracingSession::QueryServiceStateCallback query_service_state_callback_;
- void Disconnect() override {
- if (!connected_)
- return;
- connected_ = false;
- producer_->OnDisconnect();
- }
+ // The states of all data sources in this tracing session. |true| means the
+ // data source has started tracing.
+ using DataSourceHandle = std::pair<std::string, std::string>;
+ std::map<DataSourceHandle, bool> data_source_states_;
- void RegisterDataSource(const DataSourceDescriptor&) override {}
- void UpdateDataSource(const DataSourceDescriptor&) override {}
- void UnregisterDataSource(const std::string& /*name*/) override {}
+ std::unique_ptr<ConsumerEndpoint> service_; // Keep before last.
+ PERFETTO_THREAD_CHECKER(thread_checker_) // Keep last.
+ };
- void RegisterTraceWriter(uint32_t /*writer_id*/,
- uint32_t /*target_buffer*/) override {}
- void UnregisterTraceWriter(uint32_t /*writer_id*/) override {}
+ // This object is returned to API clients when they call
+ // Tracing::CreateTracingSession().
+ class TracingSessionImpl : public TracingSession {
+ public:
+ TracingSessionImpl(TracingMuxerImpl*, TracingSessionGlobalID, BackendType);
+ ~TracingSessionImpl() override;
+ void Setup(const TraceConfig&, int fd) override;
+ void Start() override;
+ void StartBlocking() override;
+ void CloneTrace(CloneTraceArgs args, CloneTraceCallback) override;
+ void SetOnStartCallback(std::function<void()>) override;
+ void SetOnErrorCallback(std::function<void(TracingError)>) override;
+ void Stop() override;
+ void StopBlocking() override;
+ void Flush(std::function<void(bool)>, uint32_t timeout_ms) override;
+ void ReadTrace(ReadTraceCallback) override;
+ void SetOnStopCallback(std::function<void()>) override;
+ void GetTraceStats(GetTraceStatsCallback) override;
+ void QueryServiceState(QueryServiceStateCallback) override;
+ void ChangeTraceConfig(const TraceConfig&) override;
- void CommitData(const CommitDataRequest&,
- CommitDataCallback callback) override {
- if (connected_) {
- callback();
- }
- }
+ private:
+ TracingMuxerImpl* const muxer_;
+ TracingSessionGlobalID const session_id_;
+ BackendType const backend_type_;
+ };
- SharedMemory* shared_memory() const override { return nullptr; }
- size_t shared_buffer_page_size_kb() const override { return 0; }
+ // This object is returned to API clients when they call
+ // Tracing::SetupStartupTracing().
+ class StartupTracingSessionImpl : public StartupTracingSession {
+ public:
+ StartupTracingSessionImpl(TracingMuxerImpl*,
+ TracingSessionGlobalID,
+ BackendType);
+ ~StartupTracingSessionImpl() override;
+ void Abort() override;
+ void AbortBlocking() override;
- std::unique_ptr<TraceWriter> CreateTraceWriter(
- BufferID /*target_buffer*/,
- BufferExhaustedPolicy) override {
- return nullptr;
- }
+ private:
+ TracingMuxerImpl* const muxer_;
+ TracingSessionGlobalID const session_id_;
+ BackendType backend_type_;
+ };
- SharedMemoryArbiter* MaybeSharedMemoryArbiter() override { return nullptr; }
- bool IsShmemProvidedByProducer() const override { return false; }
+ struct RegisteredInterceptor {
+ protos::gen::InterceptorDescriptor descriptor;
+ InterceptorFactory factory{};
+ InterceptorBase::TLSFactory tls_factory{};
+ InterceptorBase::TracePacketCallback packet_callback{};
+ };
- void NotifyFlushComplete(FlushRequestID) override {}
- void NotifyDataSourceStarted(DataSourceInstanceID) override {}
- void NotifyDataSourceStopped(DataSourceInstanceID) override {}
- void ActivateTriggers(const std::vector<std::string>&) override {}
+ struct RegisteredStartupSession {
+ TracingSessionID session_id = 0;
+ int num_unbound_data_sources = 0;
- void Sync(std::function<void()> callback) override {
- if (connected_) {
- callback();
- }
- }
+ bool is_aborting = false;
+ int num_aborting_data_sources = 0;
- private:
- Producer* const producer_;
- base::TaskRunner* const task_runner_;
- bool connected_ = true;
- base::WeakPtrFactory<UnsupportedProducerEndpoint> weak_ptr_factory_{
- this}; // Keep last.
-};
+ std::function<void()> on_aborted;
+ std::function<void()> on_adopted;
+ };
-class UnsupportedConsumerEndpoint : public ConsumerEndpoint {
- public:
- UnsupportedConsumerEndpoint(Consumer* consumer, base::TaskRunner* task_runner)
- : consumer_(consumer), task_runner_(task_runner) {
- // The SDK will not to reconnect the consumer, so we just disconnect it
- // immediately, which will cancel the tracing session.
- auto weak_this = weak_ptr_factory_.GetWeakPtr();
- task_runner_->PostTask([weak_this] {
- if (weak_this)
- weak_this->consumer_->OnDisconnect();
- });
- }
- ~UnsupportedConsumerEndpoint() override = default;
+ struct RegisteredProducerBackend {
+ // Backends are supposed to have static lifetime.
+ TracingProducerBackend* backend = nullptr;
+ TracingBackendId id = 0;
+ BackendType type{};
- void EnableTracing(const TraceConfig&, base::ScopedFile) override {}
- void ChangeTraceConfig(const TraceConfig&) override {}
+ TracingBackend::ConnectProducerArgs producer_conn_args;
+ std::unique_ptr<ProducerImpl> producer;
- void StartTracing() override {}
- void DisableTracing() override {}
+ std::vector<RegisteredStartupSession> startup_sessions;
+ };
- void Flush(uint32_t /*timeout_ms*/,
- FlushCallback callback,
- FlushFlags) override {
- callback(/*success=*/false);
- }
+ struct RegisteredConsumerBackend {
+ // Backends are supposed to have static lifetime.
+ TracingConsumerBackend* backend = nullptr;
+ BackendType type{};
+ // The calling code can request more than one concurrently active tracing
+ // session for the same backend. We need to create one consumer per session.
+ std::vector<std::unique_ptr<ConsumerImpl>> consumers;
+ };
- void ReadBuffers() override {}
- void FreeBuffers() override {}
+ void UpdateDataSourceOnAllBackends(RegisteredDataSource& rds,
+ bool is_changed);
+ explicit TracingMuxerImpl(const TracingInitArgs&);
+ void Initialize(const TracingInitArgs& args);
+ void AddBackends(const TracingInitArgs& args);
+ void AddConsumerBackend(TracingConsumerBackend* backend, BackendType type);
+ void AddProducerBackend(TracingProducerBackend* backend,
+ BackendType type,
+ const TracingInitArgs& args);
+ ConsumerImpl* FindConsumer(TracingSessionGlobalID session_id);
+ std::pair<ConsumerImpl*, RegisteredConsumerBackend*> FindConsumerAndBackend(
+ TracingSessionGlobalID session_id);
+ RegisteredProducerBackend* FindProducerBackendById(TracingBackendId id);
+ RegisteredProducerBackend* FindProducerBackendByType(BackendType type);
+ RegisteredConsumerBackend* FindConsumerBackendByType(BackendType type);
+ void InitializeConsumer(TracingSessionGlobalID session_id);
+ void OnConsumerDisconnected(ConsumerImpl* consumer);
+ void OnProducerDisconnected(ProducerImpl* producer);
+ void DestroyAllTraceWritersForCurrentThread();
+ // Test only method.
+ void SweepDeadBackends();
- void Detach(const std::string& /*key*/) override {}
- void Attach(const std::string& /*key*/) override {}
+ struct FindDataSourceRes {
+ FindDataSourceRes() = default;
+ FindDataSourceRes(DataSourceStaticState* a,
+ DataSourceState* b,
+ uint32_t c,
+ bool d)
+ : static_state(a),
+ internal_state(b),
+ instance_idx(c),
+ requires_callbacks_under_lock(d) {}
+ explicit operator bool() const { return !!internal_state; }
- void GetTraceStats() override {}
- void ObserveEvents(uint32_t /*events_mask*/) override {}
- void QueryServiceState(QueryServiceStateArgs,
- QueryServiceStateCallback) override {}
- void QueryCapabilities(QueryCapabilitiesCallback) override {}
+ DataSourceStaticState* static_state = nullptr;
+ DataSourceState* internal_state = nullptr;
+ uint32_t instance_idx = 0;
+ bool requires_callbacks_under_lock = false;
+ };
+ FindDataSourceRes FindDataSource(TracingBackendId, DataSourceInstanceID);
- void SaveTraceForBugreport(SaveTraceForBugreportCallback) override {}
- void CloneSession(CloneSessionArgs) override {}
+ FindDataSourceRes SetupDataSourceImpl(
+ const RegisteredDataSource&,
+ TracingBackendId,
+ uint32_t backend_connection_id,
+ DataSourceInstanceID,
+ const DataSourceConfig&,
+ TracingSessionGlobalID startup_session_id);
+ void StartDataSourceImpl(const FindDataSourceRes&);
+ void StopDataSource_AsyncBeginImpl(const FindDataSourceRes&);
+ void StopDataSource_AsyncEnd(TracingBackendId,
+ uint32_t backend_connection_id,
+ DataSourceInstanceID,
+ const FindDataSourceRes&);
+ bool FlushDataSource_AsyncBegin(TracingBackendId,
+ DataSourceInstanceID,
+ FlushRequestID,
+ FlushFlags);
+ void FlushDataSource_AsyncEnd(TracingBackendId,
+ uint32_t backend_connection_id,
+ DataSourceInstanceID,
+ const FindDataSourceRes&,
+ FlushRequestID);
+ void AbortStartupTracingSession(TracingSessionGlobalID, BackendType);
+ // When ResetForTesting() is executed, `cb` will be called on the calling
+ // thread and on the muxer thread.
+ void AppendResetForTestingCallback(std::function<void()> cb);
- private:
- Consumer* const consumer_;
- base::TaskRunner* const task_runner_;
- base::WeakPtrFactory<UnsupportedConsumerEndpoint> weak_ptr_factory_{
- this}; // Keep last.
-};
+ // WARNING: If you add new state here, be sure to update ResetForTesting.
+ std::unique_ptr<base::TaskRunner> task_runner_;
+ std::vector<RegisteredDataSource> data_sources_;
+ // These lists can only have one backend per BackendType. The elements are
+ // sorted by BackendType priority (see BackendTypePriority). They always
+ // contain a fake low-priority kUnspecifiedBackend at the end.
+ std::list<RegisteredProducerBackend> producer_backends_;
+ std::list<RegisteredConsumerBackend> consumer_backends_;
+ std::vector<RegisteredInterceptor> interceptors_;
+ TracingPolicy* policy_ = nullptr;
-} // namespace
+ // Learn more at TracingInitArgs::supports_multiple_data_source_instances
+ bool supports_multiple_data_source_instances_ = true;
-// static
-TracingBackend* TracingBackendFake::GetInstance() {
- static auto* instance = new TracingBackendFake();
- return instance;
-}
+ std::atomic<TracingSessionGlobalID> next_tracing_session_id_{};
+ std::atomic<uint32_t> next_data_source_index_{};
+ uint32_t muxer_id_for_testing_{};
-TracingBackendFake::TracingBackendFake() = default;
+ // Maximum number of times we will try to reconnect producer backend.
+ // Should only be modified for testing purposes.
+ std::atomic<uint32_t> max_producer_reconnections_{100u};
-std::unique_ptr<ProducerEndpoint> TracingBackendFake::ConnectProducer(
- const ConnectProducerArgs& args) {
- return std::unique_ptr<ProducerEndpoint>(
- new UnsupportedProducerEndpoint(args.producer, args.task_runner));
-}
+ // Test only member.
+ // After ResetForTesting() is called, holds tracing backends which needs to be
+ // kept alive until all inbound references have gone away. See
+ // SweepDeadBackends().
+ std::list<RegisteredProducerBackend> dead_backends_;
-std::unique_ptr<ConsumerEndpoint> TracingBackendFake::ConnectConsumer(
- const ConnectConsumerArgs& args) {
- return std::unique_ptr<ConsumerEndpoint>(
- new UnsupportedConsumerEndpoint(args.consumer, args.task_runner));
-}
+ // Test only member.
+ // Executes these cleanup functions on the calling thread and on the muxer
+ // thread when ResetForTesting() is called.
+ std::list<std::function<void()>> reset_callbacks_;
+
+ PERFETTO_THREAD_CHECKER(thread_checker_)
+};
} // namespace internal
} // namespace perfetto
-// gen_amalgamated begin source: src/tracing/internal/tracing_muxer_fake.cc
-// gen_amalgamated begin header: src/tracing/internal/tracing_muxer_fake.h
+
+#endif // SRC_TRACING_INTERNAL_TRACING_MUXER_IMPL_H_
+// gen_amalgamated begin header: include/perfetto/ext/tracing/core/trace_stats.h
/*
- * Copyright (C) 2021 The Android Open Source Project
+ * 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.
@@ -45319,67 +49750,21 @@ std::unique_ptr<ConsumerEndpoint> TracingBackendFake::ConnectConsumer(
* limitations under the License.
*/
-#ifndef SRC_TRACING_INTERNAL_TRACING_MUXER_FAKE_H_
-#define SRC_TRACING_INTERNAL_TRACING_MUXER_FAKE_H_
-
-// gen_amalgamated expanded: #include "perfetto/base/compiler.h"
-// gen_amalgamated expanded: #include "perfetto/tracing/internal/tracing_muxer.h"
-
-namespace perfetto {
-namespace internal {
-
-// An always-fail implementation of TracingMuxer. Before tracing has been
-// initialized, all muxer operations will route here and fail with a helpful
-// error message. This is to avoid introducing null checks in
-// performance-critical parts of the codebase.
-class TracingMuxerFake : public TracingMuxer {
- class FakePlatform : public Platform {
- public:
- ~FakePlatform() override;
- ThreadLocalObject* GetOrCreateThreadLocalObject() override;
- std::unique_ptr<base::TaskRunner> CreateTaskRunner(
- const CreateTaskRunnerArgs&) override;
- std::string GetCurrentProcessName() override;
-
- static FakePlatform instance;
- };
-
- public:
- TracingMuxerFake() : TracingMuxer(&FakePlatform::instance) {}
- ~TracingMuxerFake() override;
-
- static constexpr TracingMuxerFake* Get() { return &instance; }
-
- // TracingMuxer implementation.
- bool RegisterDataSource(const DataSourceDescriptor&,
- DataSourceFactory,
- DataSourceParams,
- bool,
- DataSourceStaticState*) override;
- void UpdateDataSourceDescriptor(const DataSourceDescriptor&,
- const DataSourceStaticState*) override;
- std::unique_ptr<TraceWriterBase> CreateTraceWriter(
- DataSourceStaticState*,
- uint32_t data_source_instance_index,
- DataSourceState*,
- BufferExhaustedPolicy buffer_exhausted_policy) override;
- void DestroyStoppedTraceWritersForCurrentThread() override;
- void RegisterInterceptor(const InterceptorDescriptor&,
- InterceptorFactory,
- InterceptorBase::TLSFactory,
- InterceptorBase::TracePacketCallback) override;
- void ActivateTriggers(const std::vector<std::string>&, uint32_t) override;
+#ifndef INCLUDE_PERFETTO_EXT_TRACING_CORE_TRACE_STATS_H_
+#define INCLUDE_PERFETTO_EXT_TRACING_CORE_TRACE_STATS_H_
- private:
- static TracingMuxerFake instance;
-};
+// Creates the aliases in the ::perfetto namespace, doing things like:
+// using ::perfetto::Foo = ::perfetto::protos::gen::Foo.
+// See comments in forward_decls.h for the historical reasons of this
+// indirection layer.
+// gen_amalgamated expanded: #include "perfetto/tracing/core/forward_decls.h"
-} // namespace internal
-} // namespace perfetto
+// gen_amalgamated expanded: #include "protos/perfetto/common/trace_stats.gen.h"
-#endif // SRC_TRACING_INTERNAL_TRACING_MUXER_FAKE_H_
+#endif // INCLUDE_PERFETTO_EXT_TRACING_CORE_TRACE_STATS_H_
+// gen_amalgamated begin header: include/perfetto/tracing/core/tracing_service_state.h
/*
- * Copyright (C) 2021 The Android Open Source Project
+ * 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.
@@ -45394,86 +49779,18 @@ class TracingMuxerFake : public TracingMuxer {
* limitations under the License.
*/
-// gen_amalgamated expanded: #include "src/tracing/internal/tracing_muxer_fake.h"
-
-namespace perfetto {
-namespace internal {
-namespace {
-
-PERFETTO_NORETURN void FailUninitialized() {
- PERFETTO_FATAL(
- "Tracing not initialized. Call perfetto::Tracing::Initialize() first.");
-}
-
-} // namespace
-
-// static
-PERFETTO_NO_DESTROY TracingMuxerFake::FakePlatform
- TracingMuxerFake::FakePlatform::instance{};
-// static
-PERFETTO_NO_DESTROY TracingMuxerFake TracingMuxerFake::instance{};
-
-TracingMuxerFake::~TracingMuxerFake() = default;
-
-TracingMuxerFake::FakePlatform::~FakePlatform() = default;
-
-Platform::ThreadLocalObject*
-TracingMuxerFake::FakePlatform::GetOrCreateThreadLocalObject() {
- FailUninitialized();
-}
-
-std::unique_ptr<base::TaskRunner>
-TracingMuxerFake::FakePlatform::CreateTaskRunner(const CreateTaskRunnerArgs&) {
- FailUninitialized();
-}
-
-std::string TracingMuxerFake::FakePlatform::GetCurrentProcessName() {
- FailUninitialized();
-}
-
-bool TracingMuxerFake::RegisterDataSource(const DataSourceDescriptor&,
- DataSourceFactory,
- DataSourceParams,
- bool,
- DataSourceStaticState*) {
- FailUninitialized();
-}
-
-void TracingMuxerFake::UpdateDataSourceDescriptor(
- const DataSourceDescriptor&,
- const DataSourceStaticState*) {
- FailUninitialized();
-}
-
-std::unique_ptr<TraceWriterBase> TracingMuxerFake::CreateTraceWriter(
- DataSourceStaticState*,
- uint32_t,
- DataSourceState*,
- BufferExhaustedPolicy) {
- FailUninitialized();
-}
-
-void TracingMuxerFake::DestroyStoppedTraceWritersForCurrentThread() {
- FailUninitialized();
-}
+#ifndef INCLUDE_PERFETTO_TRACING_CORE_TRACING_SERVICE_STATE_H_
+#define INCLUDE_PERFETTO_TRACING_CORE_TRACING_SERVICE_STATE_H_
-void TracingMuxerFake::RegisterInterceptor(
- const InterceptorDescriptor&,
- InterceptorFactory,
- InterceptorBase::TLSFactory,
- InterceptorBase::TracePacketCallback) {
- FailUninitialized();
-}
+// Creates the aliases in the ::perfetto namespace, doing things like:
+// using ::perfetto::Foo = ::perfetto::protos::gen::Foo.
+// See comments in forward_decls.h for the historical reasons of this
+// indirection layer.
+// gen_amalgamated expanded: #include "perfetto/tracing/core/forward_decls.h"
-void TracingMuxerFake::ActivateTriggers(const std::vector<std::string>&,
- uint32_t) {
- FailUninitialized();
-}
+// gen_amalgamated expanded: #include "protos/perfetto/common/tracing_service_state.gen.h"
-} // namespace internal
-} // namespace perfetto
-// gen_amalgamated begin source: src/tracing/internal/tracing_muxer_impl.cc
-// gen_amalgamated begin header: src/tracing/internal/tracing_muxer_impl.h
+#endif // INCLUDE_PERFETTO_TRACING_CORE_TRACING_SERVICE_STATE_H_
/*
* Copyright (C) 2019 The Android Open Source Project
*
@@ -45490,3476 +49807,4046 @@ void TracingMuxerFake::ActivateTriggers(const std::vector<std::string>&,
* limitations under the License.
*/
-#ifndef SRC_TRACING_INTERNAL_TRACING_MUXER_IMPL_H_
-#define SRC_TRACING_INTERNAL_TRACING_MUXER_IMPL_H_
-
-#include <stddef.h>
-#include <stdint.h>
+// gen_amalgamated expanded: #include "src/tracing/internal/tracing_muxer_impl.h"
-#include <array>
+#include <algorithm>
#include <atomic>
-#include <bitset>
-#include <functional>
-#include <list>
-#include <map>
-#include <memory>
-#include <set>
-#include <utility>
+#include <mutex>
+#include <optional>
#include <vector>
+// gen_amalgamated expanded: #include "perfetto/base/build_config.h"
+// gen_amalgamated expanded: #include "perfetto/base/logging.h"
+// gen_amalgamated expanded: #include "perfetto/base/task_runner.h"
// gen_amalgamated expanded: #include "perfetto/base/time.h"
-// gen_amalgamated expanded: #include "perfetto/ext/base/scoped_file.h"
+// gen_amalgamated expanded: #include "perfetto/ext/base/fnv_hash.h"
// gen_amalgamated expanded: #include "perfetto/ext/base/thread_checker.h"
-// gen_amalgamated expanded: #include "perfetto/ext/tracing/core/basic_types.h"
-// gen_amalgamated expanded: #include "perfetto/ext/tracing/core/consumer.h"
-// gen_amalgamated expanded: #include "perfetto/ext/tracing/core/producer.h"
+// gen_amalgamated expanded: #include "perfetto/ext/base/utils.h"
+// gen_amalgamated expanded: #include "perfetto/ext/base/uuid.h"
+// gen_amalgamated expanded: #include "perfetto/ext/base/waitable_event.h"
+// gen_amalgamated expanded: #include "perfetto/ext/tracing/core/shared_memory_arbiter.h"
+// gen_amalgamated expanded: #include "perfetto/ext/tracing/core/trace_packet.h"
+// gen_amalgamated expanded: #include "perfetto/ext/tracing/core/trace_stats.h"
+// gen_amalgamated expanded: #include "perfetto/ext/tracing/core/trace_writer.h"
// gen_amalgamated expanded: #include "perfetto/ext/tracing/core/tracing_service.h"
-// gen_amalgamated expanded: #include "perfetto/tracing/backend_type.h"
-// gen_amalgamated expanded: #include "perfetto/tracing/core/data_source_descriptor.h"
-// gen_amalgamated expanded: #include "perfetto/tracing/core/forward_decls.h"
-// gen_amalgamated expanded: #include "perfetto/tracing/core/trace_config.h"
-// gen_amalgamated expanded: #include "perfetto/tracing/internal/basic_types.h"
-// gen_amalgamated expanded: #include "perfetto/tracing/internal/tracing_muxer.h"
+// gen_amalgamated expanded: #include "perfetto/tracing/buffer_exhausted_policy.h"
+// gen_amalgamated expanded: #include "perfetto/tracing/core/data_source_config.h"
+// gen_amalgamated expanded: #include "perfetto/tracing/core/tracing_service_state.h"
+// gen_amalgamated expanded: #include "perfetto/tracing/data_source.h"
+// gen_amalgamated expanded: #include "perfetto/tracing/internal/data_source_internal.h"
+// gen_amalgamated expanded: #include "perfetto/tracing/internal/interceptor_trace_writer.h"
+// gen_amalgamated expanded: #include "perfetto/tracing/internal/tracing_backend_fake.h"
+// gen_amalgamated expanded: #include "perfetto/tracing/trace_writer_base.h"
// gen_amalgamated expanded: #include "perfetto/tracing/tracing.h"
+// gen_amalgamated expanded: #include "perfetto/tracing/tracing_backend.h"
+// gen_amalgamated expanded: #include "src/tracing/core/null_trace_writer.h"
+// gen_amalgamated expanded: #include "src/tracing/internal/tracing_muxer_fake.h"
-// gen_amalgamated expanded: #include "protos/perfetto/common/interceptor_descriptor.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/config/interceptor_config.gen.h"
+
+#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
+#include <io.h> // For dup()
+#else
+#include <unistd.h> // For dup()
+#endif
namespace perfetto {
+namespace internal {
-class ConsumerEndpoint;
-class DataSourceBase;
-class ProducerEndpoint;
-class TraceWriterBase;
-class TracingBackend;
-class TracingSession;
-struct TracingInitArgs;
+namespace {
-namespace base {
-class TaskRunner;
-}
+using RegisteredDataSource = TracingMuxerImpl::RegisteredDataSource;
-namespace shlib {
-void ResetForTesting();
+// A task runner which prevents calls to DataSource::Trace() while an operation
+// is in progress. Used to guard against unexpected re-entrancy where the
+// user-provided task runner implementation tries to enter a trace point under
+// the hood.
+class NonReentrantTaskRunner : public base::TaskRunner {
+ public:
+ NonReentrantTaskRunner(TracingMuxer* muxer,
+ std::unique_ptr<base::TaskRunner> task_runner)
+ : muxer_(muxer), task_runner_(std::move(task_runner)) {}
+
+ // base::TaskRunner implementation.
+ void PostTask(std::function<void()> task) override {
+ CallWithGuard([&] { task_runner_->PostTask(std::move(task)); });
+ }
+
+ void PostDelayedTask(std::function<void()> task, uint32_t delay_ms) override {
+ CallWithGuard(
+ [&] { task_runner_->PostDelayedTask(std::move(task), delay_ms); });
+ }
+
+ void AddFileDescriptorWatch(base::PlatformHandle fd,
+ std::function<void()> callback) override {
+ CallWithGuard(
+ [&] { task_runner_->AddFileDescriptorWatch(fd, std::move(callback)); });
+ }
+
+ void RemoveFileDescriptorWatch(base::PlatformHandle fd) override {
+ CallWithGuard([&] { task_runner_->RemoveFileDescriptorWatch(fd); });
+ }
+
+ bool RunsTasksOnCurrentThread() const override {
+ bool result;
+ CallWithGuard([&] { result = task_runner_->RunsTasksOnCurrentThread(); });
+ return result;
+ }
+
+ private:
+ template <typename T>
+ void CallWithGuard(T lambda) const {
+ auto* root_tls = muxer_->GetOrCreateTracingTLS();
+ if (PERFETTO_UNLIKELY(root_tls->is_in_trace_point)) {
+ lambda();
+ return;
+ }
+ ScopedReentrancyAnnotator scoped_annotator(*root_tls);
+ lambda();
+ }
+
+ TracingMuxer* const muxer_;
+ std::unique_ptr<base::TaskRunner> task_runner_;
+};
+
+class StopArgsImpl : public DataSourceBase::StopArgs {
+ public:
+ std::function<void()> HandleStopAsynchronously() const override {
+ auto closure = std::move(async_stop_closure);
+ async_stop_closure = std::function<void()>();
+ return closure;
+ }
+
+ mutable std::function<void()> async_stop_closure;
+};
+
+class FlushArgsImpl : public DataSourceBase::FlushArgs {
+ public:
+ std::function<void()> HandleFlushAsynchronously() const override {
+ auto closure = std::move(async_flush_closure);
+ async_flush_closure = std::function<void()>();
+ return closure;
+ }
+
+ mutable std::function<void()> async_flush_closure;
+};
+
+// Holds an earlier TracingMuxerImpl instance after ResetForTesting() is called.
+static TracingMuxerImpl* g_prev_instance{};
+
+template <typename RegisteredBackend>
+struct CompareBackendByType {
+ static int BackendTypePriority(BackendType type) {
+ switch (type) {
+ case kSystemBackend:
+ return 0;
+ case kInProcessBackend:
+ return 1;
+ case kCustomBackend:
+ return 2;
+ // The UnspecifiedBackend has the highest priority so that
+ // TracingBackendFake is the last one on the backend lists.
+ case kUnspecifiedBackend:
+ break;
+ }
+ return 3;
+ }
+ bool operator()(BackendType type, const RegisteredBackend& b) {
+ return BackendTypePriority(type) < BackendTypePriority(b.type);
+ }
+};
+
+BufferExhaustedPolicy ComputeBufferExhaustedPolicy(
+ const DataSourceConfig& cfg,
+ const DataSourceParams& params) {
+ if (!params.buffer_exhausted_policy_configurable) {
+ return params.default_buffer_exhausted_policy;
+ }
+
+ switch (cfg.buffer_exhausted_policy()) {
+ case DataSourceConfig::BUFFER_EXHAUSTED_UNSPECIFIED:
+ return params.default_buffer_exhausted_policy;
+ case DataSourceConfig::BUFFER_EXHAUSTED_DROP:
+ return BufferExhaustedPolicy::kDrop;
+ case DataSourceConfig::BUFFER_EXHAUSTED_STALL_THEN_ABORT:
+ return BufferExhaustedPolicy::kStall;
+ case DataSourceConfig::BUFFER_EXHAUSTED_STALL_THEN_DROP:
+ return BufferExhaustedPolicy::kStallThenDrop;
+ }
+
+ return params.default_buffer_exhausted_policy;
}
-namespace test {
-class TracingMuxerImplInternalsForTest;
+} // namespace
+
+// ----- Begin of TracingMuxerImpl::ProducerImpl
+TracingMuxerImpl::ProducerImpl::ProducerImpl(
+ TracingMuxerImpl* muxer,
+ TracingBackendId backend_id,
+ uint32_t shmem_batch_commits_duration_ms,
+ bool shmem_direct_patching_enabled)
+ : muxer_(muxer),
+ backend_id_(backend_id),
+ shmem_batch_commits_duration_ms_(shmem_batch_commits_duration_ms),
+ shmem_direct_patching_enabled_(shmem_direct_patching_enabled) {}
+
+TracingMuxerImpl::ProducerImpl::~ProducerImpl() {
+ muxer_ = nullptr;
}
-namespace internal {
+void TracingMuxerImpl::ProducerImpl::Initialize(
+ std::unique_ptr<ProducerEndpoint> endpoint) {
+ PERFETTO_DCHECK_THREAD(thread_checker_);
+ PERFETTO_DCHECK(!connected_);
+ connection_id_.fetch_add(1, std::memory_order_relaxed);
+ is_producer_provided_smb_ = endpoint->shared_memory();
+ last_startup_target_buffer_reservation_ = 0;
-struct DataSourceStaticState;
+ // Adopt the endpoint into a shared pointer so that we can safely share it
+ // across threads that create trace writers. The custom deleter function
+ // ensures that the endpoint is always destroyed on the muxer's thread. (Note
+ // that |task_runner| is assumed to outlive tracing sessions on all threads.)
+ auto* task_runner = muxer_->task_runner_.get();
+ auto deleter = [task_runner](ProducerEndpoint* e) {
+ if (task_runner->RunsTasksOnCurrentThread()) {
+ delete e;
+ return;
+ }
+ task_runner->PostTask([e] { delete e; });
+ };
+ std::shared_ptr<ProducerEndpoint> service(endpoint.release(), deleter);
+ // This atomic store is needed because another thread might be concurrently
+ // creating a trace writer using the previous (disconnected) |service_|. See
+ // CreateTraceWriter().
+ std::atomic_store(&service_, std::move(service));
+ // Don't try to use the service here since it may not have connected yet. See
+ // OnConnect().
+}
-// This class acts as a bridge between the public API and the TracingBackend(s).
-// It exposes a simplified view of the world to the API methods handling all the
-// bookkeeping to map data source instances and trace writers to the various
-// backends. It deals with N data sources, M backends (1 backend == 1 tracing
-// service == 1 producer connection) and T concurrent tracing sessions.
-//
-// Handing data source registration and start/stop flows [producer side]:
-// ----------------------------------------------------------------------
-// 1. The API client subclasses perfetto::DataSource and calls
-// DataSource::Register<MyDataSource>(). In turn this calls into the
-// TracingMuxer.
-// 2. The tracing muxer iterates through all the backends (1 backend == 1
-// service == 1 producer connection) and registers the data source on each
-// backend.
-// 3. When any (services behind a) backend starts tracing and requests to start
-// that specific data source, the TracingMuxerImpl constructs a new instance
-// of MyDataSource and calls the OnStart() method.
-//
-// Controlling trace and retrieving trace data [consumer side]:
-// ------------------------------------------------------------
-// 1. The API client calls Tracing::NewTrace(), returns a RAII TracingSession
-// object.
-// 2. NewTrace() calls into internal::TracingMuxer(Impl). TracingMuxer
-// subclasses the TracingSession object (TracingSessionImpl) and returns it.
-// 3. The tracing muxer identifies the backend (according to the args passed to
-// NewTrace), creates a new Consumer and connects to it.
-// 4. When the API client calls Start()/Stop()/ReadTrace() methods, the
-// TracingMuxer forwards them to the consumer associated to the
-// TracingSession. Likewise for callbacks coming from the consumer-side of
-// the service.
-class TracingMuxerImpl : public TracingMuxer {
- public:
- // This is different than TracingSessionID because it's global across all
- // backends. TracingSessionID is global only within the scope of one service.
- using TracingSessionGlobalID = uint64_t;
+void TracingMuxerImpl::ProducerImpl::OnConnect() {
+ PERFETTO_DLOG("Producer connected");
+ PERFETTO_DCHECK_THREAD(thread_checker_);
+ PERFETTO_DCHECK(!connected_);
+ if (is_producer_provided_smb_ && !service_->IsShmemProvidedByProducer()) {
+ PERFETTO_ELOG(
+ "The service likely doesn't support producer-provided SMBs. Preventing "
+ "future attempts to use producer-provided SMB again with this "
+ "backend.");
+ producer_provided_smb_failed_ = true;
+ // Will call OnDisconnect() and cause a reconnect without producer-provided
+ // SMB.
+ service_->Disconnect();
+ return;
+ }
+ connected_ = true;
+ muxer_->UpdateDataSourcesOnAllBackends();
+ SendOnConnectTriggers();
+}
- struct RegisteredDataSource {
- DataSourceDescriptor descriptor;
- DataSourceFactory factory{};
- DataSourceParams params;
- bool no_flush = false;
- DataSourceStaticState* static_state = nullptr;
- };
+void TracingMuxerImpl::ProducerImpl::OnDisconnect() {
+ PERFETTO_DCHECK_THREAD(thread_checker_);
+ // If we're being destroyed, bail out.
+ if (!muxer_)
+ return;
+ connected_ = false;
+ // Active data sources for this producer will be stopped by
+ // DestroyStoppedTraceWritersForCurrentThread() since the reconnected producer
+ // will have a different connection id (even before it has finished
+ // connecting).
+ registered_data_sources_.reset();
+ DisposeConnection();
- static void InitializeInstance(const TracingInitArgs&);
- static void ResetForTesting();
- static void Shutdown();
+ // Try reconnecting the producer.
+ muxer_->OnProducerDisconnected(this);
+}
- // TracingMuxer implementation.
- bool RegisterDataSource(const DataSourceDescriptor&,
- DataSourceFactory,
- DataSourceParams,
- bool no_flush,
- DataSourceStaticState*) override;
- void UpdateDataSourceDescriptor(const DataSourceDescriptor&,
- const DataSourceStaticState*) override;
- std::unique_ptr<TraceWriterBase> CreateTraceWriter(
- DataSourceStaticState*,
- uint32_t data_source_instance_index,
- DataSourceState*,
- BufferExhaustedPolicy buffer_exhausted_policy) override;
- void DestroyStoppedTraceWritersForCurrentThread() override;
- void RegisterInterceptor(const InterceptorDescriptor&,
- InterceptorFactory,
- InterceptorBase::TLSFactory,
- InterceptorBase::TracePacketCallback) override;
+void TracingMuxerImpl::ProducerImpl::DisposeConnection() {
+ // Keep the old service around as a dead connection in case it has active
+ // trace writers. If any tracing sessions were created, we can't clear
+ // |service_| here because other threads may be concurrently creating new
+ // trace writers. Any reconnection attempt will atomically swap the new
+ // service in place of the old one.
+ if (did_setup_tracing_ || did_setup_startup_tracing_) {
+ dead_services_.push_back(service_);
+ } else {
+ service_.reset();
+ }
+}
- void ActivateTriggers(const std::vector<std::string>&, uint32_t) override;
+void TracingMuxerImpl::ProducerImpl::OnTracingSetup() {
+ PERFETTO_DCHECK_THREAD(thread_checker_);
+ did_setup_tracing_ = true;
+ service_->MaybeSharedMemoryArbiter()->SetBatchCommitsDuration(
+ shmem_batch_commits_duration_ms_);
+ if (shmem_direct_patching_enabled_) {
+ service_->MaybeSharedMemoryArbiter()->EnableDirectSMBPatching();
+ }
+}
- std::unique_ptr<TracingSession> CreateTracingSession(
- BackendType,
- TracingConsumerBackend* (*system_backend_factory)());
- std::unique_ptr<StartupTracingSession> CreateStartupTracingSession(
- const TraceConfig& config,
- Tracing::SetupStartupTracingOpts);
- std::unique_ptr<StartupTracingSession> CreateStartupTracingSessionBlocking(
- const TraceConfig& config,
- Tracing::SetupStartupTracingOpts);
+void TracingMuxerImpl::ProducerImpl::OnStartupTracingSetup() {
+ PERFETTO_DCHECK_THREAD(thread_checker_);
+ did_setup_startup_tracing_ = true;
+}
- // Producer-side bookkeeping methods.
- void UpdateDataSourcesOnAllBackends();
- void SetupDataSource(TracingBackendId,
- uint32_t backend_connection_id,
- DataSourceInstanceID,
- const DataSourceConfig&);
- void StartDataSource(TracingBackendId, DataSourceInstanceID);
- void StopDataSource_AsyncBegin(TracingBackendId, DataSourceInstanceID);
- void ClearDataSourceIncrementalState(TracingBackendId, DataSourceInstanceID);
- void SyncProducersForTesting();
+void TracingMuxerImpl::ProducerImpl::SetupDataSource(
+ DataSourceInstanceID id,
+ const DataSourceConfig& cfg) {
+ PERFETTO_DCHECK_THREAD(thread_checker_);
+ if (!muxer_)
+ return;
+ muxer_->SetupDataSource(
+ backend_id_, connection_id_.load(std::memory_order_relaxed), id, cfg);
+}
- // Consumer-side bookkeeping methods.
- void SetupTracingSession(TracingSessionGlobalID,
- const std::shared_ptr<TraceConfig>&,
- base::ScopedFile trace_fd = base::ScopedFile());
- void StartTracingSession(TracingSessionGlobalID);
- void CloneTracingSession(TracingSessionGlobalID,
- TracingSession::CloneTraceArgs,
- TracingSession::CloneTraceCallback);
- void ChangeTracingSessionConfig(TracingSessionGlobalID, const TraceConfig&);
- void StopTracingSession(TracingSessionGlobalID);
- void DestroyTracingSession(TracingSessionGlobalID);
- void FlushTracingSession(TracingSessionGlobalID,
- uint32_t,
- std::function<void(bool)>);
- void ReadTracingSessionData(
- TracingSessionGlobalID,
- std::function<void(TracingSession::ReadTraceCallbackArgs)>);
- void GetTraceStats(TracingSessionGlobalID,
- TracingSession::GetTraceStatsCallback);
- void QueryServiceState(TracingSessionGlobalID,
- TracingSession::QueryServiceStateCallback);
+void TracingMuxerImpl::ProducerImpl::StartDataSource(DataSourceInstanceID id,
+ const DataSourceConfig&) {
+ PERFETTO_DCHECK_THREAD(thread_checker_);
+ if (!muxer_)
+ return;
+ muxer_->StartDataSource(backend_id_, id);
+ service_->NotifyDataSourceStarted(id);
+}
- // Sets the batching period to |batch_commits_duration_ms| on the backends
- // with type |backend_type|.
- void SetBatchCommitsDurationForTesting(uint32_t batch_commits_duration_ms,
- BackendType backend_type);
+void TracingMuxerImpl::ProducerImpl::StopDataSource(DataSourceInstanceID id) {
+ PERFETTO_DCHECK_THREAD(thread_checker_);
+ if (!muxer_)
+ return;
+ muxer_->StopDataSource_AsyncBegin(backend_id_, id);
+}
- // Enables direct SMB patching on the backends with type |backend_type| (see
- // SharedMemoryArbiter::EnableDirectSMBPatching). Returns true if the
- // operation succeeded for all backends with type |backend_type|, false
- // otherwise.
- bool EnableDirectSMBPatchingForTesting(BackendType backend_type);
+void TracingMuxerImpl::ProducerImpl::Flush(
+ FlushRequestID flush_id,
+ const DataSourceInstanceID* instances,
+ size_t instance_count,
+ FlushFlags flush_flags) {
+ PERFETTO_DCHECK_THREAD(thread_checker_);
+ bool all_handled = true;
+ if (muxer_) {
+ for (size_t i = 0; i < instance_count; i++) {
+ DataSourceInstanceID ds_id = instances[i];
+ bool handled = muxer_->FlushDataSource_AsyncBegin(backend_id_, ds_id,
+ flush_id, flush_flags);
+ if (!handled) {
+ pending_flushes_[flush_id].insert(ds_id);
+ all_handled = false;
+ }
+ }
+ }
- void SetMaxProducerReconnectionsForTesting(uint32_t count);
+ if (all_handled) {
+ service_->NotifyFlushComplete(flush_id);
+ }
+}
- private:
- friend class test::TracingMuxerImplInternalsForTest;
- friend void shlib::ResetForTesting();
+void TracingMuxerImpl::ProducerImpl::ClearIncrementalState(
+ const DataSourceInstanceID* instances,
+ size_t instance_count) {
+ PERFETTO_DCHECK_THREAD(thread_checker_);
+ if (!muxer_)
+ return;
+ for (size_t inst_idx = 0; inst_idx < instance_count; inst_idx++) {
+ muxer_->ClearDataSourceIncrementalState(backend_id_, instances[inst_idx]);
+ }
+}
- // For each TracingBackend we create and register one ProducerImpl instance.
- // This talks to the producer-side of the service, gets start/stop requests
- // from it and routes them to the registered data sources.
- // One ProducerImpl == one backend == one tracing service.
- // This class is needed to disambiguate callbacks coming from different
- // services. TracingMuxerImpl can't directly implement the Producer interface
- // because the Producer virtual methods don't allow to identify the service.
- class ProducerImpl : public Producer {
- public:
- ProducerImpl(TracingMuxerImpl*,
- TracingBackendId,
- uint32_t shmem_batch_commits_duration_ms,
- bool shmem_direct_patching_enabled);
- ~ProducerImpl() override;
+bool TracingMuxerImpl::ProducerImpl::SweepDeadServices() {
+ PERFETTO_DCHECK_THREAD(thread_checker_);
+ auto is_unused = [](const std::shared_ptr<ProducerEndpoint>& endpoint) {
+ auto* arbiter = endpoint->MaybeSharedMemoryArbiter();
+ return !arbiter || arbiter->TryShutdown();
+ };
+ for (auto it = dead_services_.begin(); it != dead_services_.end();) {
+ auto next_it = it;
+ next_it++;
+ if (is_unused(*it)) {
+ dead_services_.erase(it);
+ }
+ it = next_it;
+ }
+ return dead_services_.empty();
+}
- void Initialize(std::unique_ptr<ProducerEndpoint> endpoint);
- void RegisterDataSource(const DataSourceDescriptor&,
- DataSourceFactory,
- DataSourceStaticState*);
- void DisposeConnection();
+void TracingMuxerImpl::ProducerImpl::SendOnConnectTriggers() {
+ PERFETTO_DCHECK_THREAD(thread_checker_);
+ base::TimeMillis now = base::GetWallTimeMs();
+ std::vector<std::string> triggers;
+ while (!on_connect_triggers_.empty()) {
+ // Skip if we passed TTL.
+ if (on_connect_triggers_.front().second > now) {
+ triggers.push_back(std::move(on_connect_triggers_.front().first));
+ }
+ on_connect_triggers_.pop_front();
+ }
+ if (!triggers.empty()) {
+ service_->ActivateTriggers(triggers);
+ }
+}
- // perfetto::Producer implementation.
- void OnConnect() override;
- void OnDisconnect() override;
- void OnTracingSetup() override;
- void OnStartupTracingSetup() override;
- void SetupDataSource(DataSourceInstanceID,
- const DataSourceConfig&) override;
- void StartDataSource(DataSourceInstanceID,
- const DataSourceConfig&) override;
- void StopDataSource(DataSourceInstanceID) override;
- void Flush(FlushRequestID,
- const DataSourceInstanceID*,
- size_t,
- FlushFlags) override;
- void ClearIncrementalState(const DataSourceInstanceID*, size_t) override;
+void TracingMuxerImpl::ProducerImpl::NotifyFlushForDataSourceDone(
+ DataSourceInstanceID ds_id,
+ FlushRequestID flush_id) {
+ if (!connected_) {
+ return;
+ }
- bool SweepDeadServices();
- void SendOnConnectTriggers();
- void NotifyFlushForDataSourceDone(DataSourceInstanceID, FlushRequestID);
+ {
+ auto it = pending_flushes_.find(flush_id);
+ if (it == pending_flushes_.end()) {
+ return;
+ }
+ std::set<DataSourceInstanceID>& ds_ids = it->second;
+ ds_ids.erase(ds_id);
+ }
- PERFETTO_THREAD_CHECKER(thread_checker_)
- TracingMuxerImpl* muxer_;
- TracingBackendId const backend_id_;
- bool connected_ = false;
- bool did_setup_tracing_ = false;
- bool did_setup_startup_tracing_ = false;
- std::atomic<uint32_t> connection_id_{0};
- uint16_t last_startup_target_buffer_reservation_ = 0;
- bool is_producer_provided_smb_ = false;
- bool producer_provided_smb_failed_ = false;
+ std::optional<DataSourceInstanceID> biggest_flush_id;
+ for (auto it = pending_flushes_.begin(); it != pending_flushes_.end();) {
+ if (it->second.empty()) {
+ biggest_flush_id = it->first;
+ it = pending_flushes_.erase(it);
+ } else {
+ break;
+ }
+ }
- const uint32_t shmem_batch_commits_duration_ms_ = 0;
- const bool shmem_direct_patching_enabled_ = false;
+ if (biggest_flush_id) {
+ service_->NotifyFlushComplete(*biggest_flush_id);
+ }
+}
- // Set of data sources that have been actually registered on this producer.
- // This can be a subset of the global |data_sources_|, because data sources
- // can register before the producer is fully connected.
- std::bitset<kMaxDataSources> registered_data_sources_{};
+// ----- End of TracingMuxerImpl::ProducerImpl methods.
- // A collection of disconnected service endpoints. Since trace writers on
- // arbitrary threads might continue writing data to disconnected services,
- // we keep the old services around and periodically try to clean up ones
- // that no longer have any writers (see SweepDeadServices).
- std::list<std::shared_ptr<ProducerEndpoint>> dead_services_;
+// ----- Begin of TracingMuxerImpl::ConsumerImpl
+TracingMuxerImpl::ConsumerImpl::ConsumerImpl(TracingMuxerImpl* muxer,
+ BackendType backend_type,
+ TracingSessionGlobalID session_id)
+ : muxer_(muxer), backend_type_(backend_type), session_id_(session_id) {}
- // Triggers that should be sent when the service connects (trigger_name,
- // expiration).
- std::list<std::pair<std::string, base::TimeMillis>> on_connect_triggers_;
+TracingMuxerImpl::ConsumerImpl::~ConsumerImpl() {
+ muxer_ = nullptr;
+}
- std::map<FlushRequestID, std::set<DataSourceInstanceID>> pending_flushes_;
+void TracingMuxerImpl::ConsumerImpl::Initialize(
+ std::unique_ptr<ConsumerEndpoint> endpoint) {
+ PERFETTO_DCHECK_THREAD(thread_checker_);
+ service_ = std::move(endpoint);
+ // Don't try to use the service here since it may not have connected yet. See
+ // OnConnect().
+}
- // The currently active service endpoint is maintained as an atomic shared
- // pointer so it won't get deleted from underneath threads that are creating
- // trace writers. At any given time one endpoint can be shared (and thus
- // kept alive) by the |service_| pointer, an entry in |dead_services_| and
- // as a pointer on the stack in CreateTraceWriter() (on an arbitrary
- // thread). The endpoint is never shared outside ProducerImpl itself.
- //
- // WARNING: Any *write* access to this variable or any *read* access from a
- // non-muxer thread must be done through std::atomic_{load,store} to avoid
- // data races.
- std::shared_ptr<ProducerEndpoint> service_; // Keep last.
- };
+void TracingMuxerImpl::ConsumerImpl::OnConnect() {
+ PERFETTO_DCHECK_THREAD(thread_checker_);
+ PERFETTO_DCHECK(!connected_);
+ connected_ = true;
- // For each TracingSession created by the API client (Tracing::NewTrace() we
- // create and register one ConsumerImpl instance.
- // This talks to the consumer-side of the service, gets end-of-trace and
- // on-trace-data callbacks and routes them to the API client callbacks.
- // This class is needed to disambiguate callbacks coming from different
- // tracing sessions.
- class ConsumerImpl : public Consumer {
- public:
- ConsumerImpl(TracingMuxerImpl*, BackendType, TracingSessionGlobalID);
- ~ConsumerImpl() override;
+ // Observe data source instance events so we get notified when tracing starts.
+ service_->ObserveEvents(ObservableEvents::TYPE_DATA_SOURCES_INSTANCES |
+ ObservableEvents::TYPE_ALL_DATA_SOURCES_STARTED);
- void Initialize(std::unique_ptr<ConsumerEndpoint> endpoint);
+ // If the API client configured and started tracing before we connected,
+ // tell the backend about it now.
+ if (trace_config_)
+ muxer_->SetupTracingSession(session_id_, trace_config_);
+ if (start_pending_)
+ muxer_->StartTracingSession(session_id_);
+ if (get_trace_stats_pending_) {
+ auto callback = std::move(get_trace_stats_callback_);
+ get_trace_stats_callback_ = nullptr;
+ muxer_->GetTraceStats(session_id_, std::move(callback));
+ }
+ if (query_service_state_callback_) {
+ auto callback = std::move(query_service_state_callback_);
+ query_service_state_callback_ = nullptr;
+ muxer_->QueryServiceState(session_id_, std::move(callback));
+ }
+ if (session_to_clone_) {
+ service_->CloneSession(std::move(*session_to_clone_));
+ session_to_clone_ = std::nullopt;
+ }
- // perfetto::Consumer implementation.
- void OnConnect() override;
- void OnDisconnect() override;
- void OnTracingDisabled(const std::string& error) override;
- void OnTraceData(std::vector<TracePacket>, bool has_more) override;
- void OnDetach(bool success) override;
- void OnAttach(bool success, const TraceConfig&) override;
- void OnTraceStats(bool success, const TraceStats&) override;
- void OnObservableEvents(const ObservableEvents&) override;
- void OnSessionCloned(const OnSessionClonedArgs&) override;
+ if (stop_pending_)
+ muxer_->StopTracingSession(session_id_);
+}
- void NotifyStartComplete();
- void NotifyError(const TracingError&);
- void NotifyStopComplete();
+void TracingMuxerImpl::ConsumerImpl::OnDisconnect() {
+ PERFETTO_DCHECK_THREAD(thread_checker_);
+ // If we're being destroyed, bail out.
+ if (!muxer_)
+ return;
+#if PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID)
+ if (!connected_ && backend_type_ == kSystemBackend) {
+ PERFETTO_ELOG(
+ "Unable to connect to the system tracing service as a consumer. On "
+ "Android, use the \"perfetto\" command line tool instead to start "
+ "system-wide tracing sessions");
+ }
+#endif // PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID)
- // Will eventually inform the |muxer_| when it is safe to remove |this|.
- void Disconnect();
+ // Notify the client about disconnection.
+ NotifyError(TracingError{TracingError::kDisconnected, "Peer disconnected"});
- TracingMuxerImpl* muxer_;
- BackendType const backend_type_;
- TracingSessionGlobalID const session_id_;
- bool connected_ = false;
+ // Make sure the client doesn't hang in a blocking start/stop because of the
+ // disconnection.
+ NotifyStartComplete();
+ NotifyStopComplete();
- // This is to handle the case where the Setup call from the API client
- // arrives before the consumer has connected. In this case we keep around
- // the config and check if we have it after connection.
- bool start_pending_ = false;
+ // It shouldn't be necessary to call StopTracingSession. If we get this call
+ // it means that the service did shutdown before us, so there is no point
+ // trying it to ask it to stop the session. We should just remember to cleanup
+ // the consumer vector.
+ connected_ = false;
- // Similarly if the session is stopped before the consumer was connected, we
- // need to wait until the session has started before stopping it.
- bool stop_pending_ = false;
+ // Notify the muxer that it is safe to destroy |this|. This is needed because
+ // the ConsumerEndpoint stored in |service_| requires that |this| be safe to
+ // access until OnDisconnect() is called.
+ muxer_->OnConsumerDisconnected(this);
+}
- // Similarly we need to buffer a call to get trace statistics if the
- // consumer wasn't connected yet.
- bool get_trace_stats_pending_ = false;
+void TracingMuxerImpl::ConsumerImpl::Disconnect() {
+ // This is weird and deserves a comment.
+ //
+ // When we called the ConnectConsumer method on the service it returns
+ // us a ConsumerEndpoint which we stored in |service_|, however this
+ // ConsumerEndpoint holds a pointer to the ConsumerImpl pointed to by
+ // |this|. Part of the API contract to TracingService::ConnectConsumer is that
+ // the ConsumerImpl pointer has to be valid until the
+ // ConsumerImpl::OnDisconnect method is called. Therefore we reset the
+ // ConsumerEndpoint |service_|. Eventually this will call
+ // ConsumerImpl::OnDisconnect and we will inform the muxer it is safe to
+ // call the destructor of |this|.
+ service_.reset();
+}
- // Similarly we need to buffer a session cloning args if the session is
- // cloning another sesison before the consumer was connected.
- std::optional<ConsumerEndpoint::CloneSessionArgs> session_to_clone_;
+void TracingMuxerImpl::ConsumerImpl::OnTracingDisabled(
+ const std::string& error) {
+ PERFETTO_DCHECK_THREAD(thread_checker_);
+ PERFETTO_DCHECK(!stopped_);
+ stopped_ = true;
- // Whether this session was already stopped. This will happen in response to
- // Stop{,Blocking}, but also if the service stops the session for us
- // automatically (e.g., when there are no data sources).
- bool stopped_ = false;
+ if (!error.empty())
+ NotifyError(TracingError{TracingError::kTracingFailed, error});
- // shared_ptr because it's posted across threads. This is to avoid copying
- // it more than once.
- std::shared_ptr<TraceConfig> trace_config_;
- base::ScopedFile trace_fd_;
+ // If we're still waiting for the start event, fire it now. This may happen if
+ // there are no active data sources in the session.
+ NotifyStartComplete();
+ NotifyStopComplete();
+}
- // If the API client passes a callback to start, we should invoke this when
- // NotifyStartComplete() is invoked.
- std::function<void()> start_complete_callback_;
+void TracingMuxerImpl::ConsumerImpl::NotifyStartComplete() {
+ PERFETTO_DCHECK_THREAD(thread_checker_);
+ if (start_complete_callback_) {
+ muxer_->task_runner_->PostTask(std::move(start_complete_callback_));
+ start_complete_callback_ = nullptr;
+ }
+ if (blocking_start_complete_callback_) {
+ muxer_->task_runner_->PostTask(
+ std::move(blocking_start_complete_callback_));
+ blocking_start_complete_callback_ = nullptr;
+ }
+}
- // An internal callback used to implement StartBlocking().
- std::function<void()> blocking_start_complete_callback_;
+void TracingMuxerImpl::ConsumerImpl::NotifyError(const TracingError& error) {
+ PERFETTO_DCHECK_THREAD(thread_checker_);
+ if (error_callback_) {
+ muxer_->task_runner_->PostTask(
+ std::bind(std::move(error_callback_), error));
+ }
+}
- // If the API client passes a callback to get notification about the
- // errors, we should invoke this when NotifyError() is invoked.
- std::function<void(TracingError)> error_callback_;
+void TracingMuxerImpl::ConsumerImpl::NotifyStopComplete() {
+ PERFETTO_DCHECK_THREAD(thread_checker_);
+ if (stop_complete_callback_) {
+ muxer_->task_runner_->PostTask(std::move(stop_complete_callback_));
+ stop_complete_callback_ = nullptr;
+ }
+ if (blocking_stop_complete_callback_) {
+ muxer_->task_runner_->PostTask(std::move(blocking_stop_complete_callback_));
+ blocking_stop_complete_callback_ = nullptr;
+ }
+}
- // If the API client passes a callback to stop, we should invoke this when
- // OnTracingDisabled() is invoked.
- std::function<void()> stop_complete_callback_;
+void TracingMuxerImpl::ConsumerImpl::OnTraceData(
+ std::vector<TracePacket> packets,
+ bool has_more) {
+ PERFETTO_DCHECK_THREAD(thread_checker_);
+ if (!read_trace_callback_)
+ return;
- // An internal callback used to implement StopBlocking().
- std::function<void()> blocking_stop_complete_callback_;
+ size_t capacity = 0;
+ for (const auto& packet : packets) {
+ // 16 is an over-estimation of the proto preamble size
+ capacity += packet.size() + 16;
+ }
- // Callback for a pending call to CloneTrace().
- TracingSession::CloneTraceCallback clone_trace_callback_;
+ // The shared_ptr is to avoid making a copy of the buffer when PostTask-ing.
+ std::shared_ptr<std::vector<char>> buf(new std::vector<char>());
+ buf->reserve(capacity);
+ for (auto& packet : packets) {
+ char* start;
+ size_t size;
+ std::tie(start, size) = packet.GetProtoPreamble();
+ buf->insert(buf->end(), start, start + size);
+ for (auto& slice : packet.slices()) {
+ const auto* slice_data = reinterpret_cast<const char*>(slice.start);
+ buf->insert(buf->end(), slice_data, slice_data + slice.size);
+ }
+ }
- // Callback passed to ReadTrace().
- std::function<void(TracingSession::ReadTraceCallbackArgs)>
- read_trace_callback_;
+ auto callback = read_trace_callback_;
+ muxer_->task_runner_->PostTask([callback, buf, has_more] {
+ TracingSession::ReadTraceCallbackArgs callback_arg{};
+ callback_arg.data = buf->empty() ? nullptr : &(*buf)[0];
+ callback_arg.size = buf->size();
+ callback_arg.has_more = has_more;
+ callback(callback_arg);
+ });
- // Callback passed to GetTraceStats().
- TracingSession::GetTraceStatsCallback get_trace_stats_callback_;
+ if (!has_more)
+ read_trace_callback_ = nullptr;
+}
- // Callback for a pending call to QueryServiceState().
- TracingSession::QueryServiceStateCallback query_service_state_callback_;
+void TracingMuxerImpl::ConsumerImpl::OnObservableEvents(
+ const ObservableEvents& events) {
+ if (events.instance_state_changes_size()) {
+ for (const auto& state_change : events.instance_state_changes()) {
+ DataSourceHandle handle{state_change.producer_name(),
+ state_change.data_source_name()};
+ data_source_states_[handle] =
+ state_change.state() ==
+ ObservableEvents::DATA_SOURCE_INSTANCE_STATE_STARTED;
+ }
+ }
- // The states of all data sources in this tracing session. |true| means the
- // data source has started tracing.
- using DataSourceHandle = std::pair<std::string, std::string>;
- std::map<DataSourceHandle, bool> data_source_states_;
+ if (events.instance_state_changes_size() ||
+ events.all_data_sources_started()) {
+ // Data sources are first reported as being stopped before starting, so once
+ // all the data sources we know about have started we can declare tracing
+ // begun. In the case where there are no matching data sources for the
+ // session, the service will report the all_data_sources_started() event
+ // without adding any instances (only since Android S / Perfetto v10.0).
+ if (start_complete_callback_ || blocking_start_complete_callback_) {
+ bool all_data_sources_started = std::all_of(
+ data_source_states_.cbegin(), data_source_states_.cend(),
+ [](std::pair<DataSourceHandle, bool> state) { return state.second; });
+ if (all_data_sources_started)
+ NotifyStartComplete();
+ }
+ }
+}
- std::unique_ptr<ConsumerEndpoint> service_; // Keep before last.
- PERFETTO_THREAD_CHECKER(thread_checker_) // Keep last.
- };
+void TracingMuxerImpl::ConsumerImpl::OnSessionCloned(
+ const OnSessionClonedArgs& args) {
+ if (!clone_trace_callback_)
+ return;
+ TracingSession::CloneTraceCallbackArgs callback_arg{};
+ callback_arg.success = args.success;
+ callback_arg.error = std::move(args.error);
+ callback_arg.uuid_msb = args.uuid.msb();
+ callback_arg.uuid_lsb = args.uuid.lsb();
+ muxer_->task_runner_->PostTask(
+ std::bind(std::move(clone_trace_callback_), std::move(callback_arg)));
+ clone_trace_callback_ = nullptr;
+}
- // This object is returned to API clients when they call
- // Tracing::CreateTracingSession().
- class TracingSessionImpl : public TracingSession {
- public:
- TracingSessionImpl(TracingMuxerImpl*, TracingSessionGlobalID, BackendType);
- ~TracingSessionImpl() override;
- void Setup(const TraceConfig&, int fd) override;
- void Start() override;
- void StartBlocking() override;
- void CloneTrace(CloneTraceArgs args, CloneTraceCallback) override;
- void SetOnStartCallback(std::function<void()>) override;
- void SetOnErrorCallback(std::function<void(TracingError)>) override;
- void Stop() override;
- void StopBlocking() override;
- void Flush(std::function<void(bool)>, uint32_t timeout_ms) override;
- void ReadTrace(ReadTraceCallback) override;
- void SetOnStopCallback(std::function<void()>) override;
- void GetTraceStats(GetTraceStatsCallback) override;
- void QueryServiceState(QueryServiceStateCallback) override;
- void ChangeTraceConfig(const TraceConfig&) override;
+void TracingMuxerImpl::ConsumerImpl::OnTraceStats(
+ bool success,
+ const TraceStats& trace_stats) {
+ if (!get_trace_stats_callback_)
+ return;
+ TracingSession::GetTraceStatsCallbackArgs callback_arg{};
+ callback_arg.success = success;
+ callback_arg.trace_stats_data = trace_stats.SerializeAsArray();
+ muxer_->task_runner_->PostTask(
+ std::bind(std::move(get_trace_stats_callback_), std::move(callback_arg)));
+ get_trace_stats_callback_ = nullptr;
+}
- private:
- TracingMuxerImpl* const muxer_;
- TracingSessionGlobalID const session_id_;
- BackendType const backend_type_;
- };
+// The callbacks below are not used.
+void TracingMuxerImpl::ConsumerImpl::OnDetach(bool) {}
+void TracingMuxerImpl::ConsumerImpl::OnAttach(bool, const TraceConfig&) {}
+// ----- End of TracingMuxerImpl::ConsumerImpl
- // This object is returned to API clients when they call
- // Tracing::SetupStartupTracing().
- class StartupTracingSessionImpl : public StartupTracingSession {
- public:
- StartupTracingSessionImpl(TracingMuxerImpl*,
- TracingSessionGlobalID,
- BackendType);
- ~StartupTracingSessionImpl() override;
- void Abort() override;
- void AbortBlocking() override;
+// ----- Begin of TracingMuxerImpl::TracingSessionImpl
- private:
- TracingMuxerImpl* const muxer_;
- TracingSessionGlobalID const session_id_;
- BackendType backend_type_;
- };
+// TracingSessionImpl is the RAII object returned to API clients when they
+// invoke Tracing::CreateTracingSession. They use it for starting/stopping
+// tracing.
- struct RegisteredInterceptor {
- protos::gen::InterceptorDescriptor descriptor;
- InterceptorFactory factory{};
- InterceptorBase::TLSFactory tls_factory{};
- InterceptorBase::TracePacketCallback packet_callback{};
- };
+TracingMuxerImpl::TracingSessionImpl::TracingSessionImpl(
+ TracingMuxerImpl* muxer,
+ TracingSessionGlobalID session_id,
+ BackendType backend_type)
+ : muxer_(muxer), session_id_(session_id), backend_type_(backend_type) {}
- struct RegisteredStartupSession {
- TracingSessionID session_id = 0;
- int num_unbound_data_sources = 0;
+// Can be destroyed from any thread.
+TracingMuxerImpl::TracingSessionImpl::~TracingSessionImpl() {
+ auto* muxer = muxer_;
+ auto session_id = session_id_;
+ muxer->task_runner_->PostTask(
+ [muxer, session_id] { muxer->DestroyTracingSession(session_id); });
+}
- bool is_aborting = false;
- int num_aborting_data_sources = 0;
+// Can be called from any thread.
+void TracingMuxerImpl::TracingSessionImpl::Setup(const TraceConfig& cfg,
+ int fd) {
+ auto* muxer = muxer_;
+ auto session_id = session_id_;
+ std::shared_ptr<TraceConfig> trace_config(new TraceConfig(cfg));
+ if (fd >= 0) {
+ base::ignore_result(backend_type_); // For -Wunused in the amalgamation.
+#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
+ if (backend_type_ != kInProcessBackend) {
+ PERFETTO_FATAL(
+ "Passing a file descriptor to TracingSession::Setup() is only "
+ "supported with the kInProcessBackend on Windows. Use "
+ "TracingSession::ReadTrace() instead");
+ }
+#endif
+ trace_config->set_write_into_file(true);
+ fd = dup(fd);
+ }
+ muxer->task_runner_->PostTask([muxer, session_id, trace_config, fd] {
+ muxer->SetupTracingSession(session_id, trace_config, base::ScopedFile(fd));
+ });
+}
- std::function<void()> on_aborted;
- std::function<void()> on_adopted;
- };
+// Can be called from any thread.
+void TracingMuxerImpl::TracingSessionImpl::Start() {
+ auto* muxer = muxer_;
+ auto session_id = session_id_;
+ muxer->task_runner_->PostTask(
+ [muxer, session_id] { muxer->StartTracingSession(session_id); });
+}
- struct RegisteredProducerBackend {
- // Backends are supposed to have static lifetime.
- TracingProducerBackend* backend = nullptr;
- TracingBackendId id = 0;
- BackendType type{};
+void TracingMuxerImpl::TracingSessionImpl::CloneTrace(CloneTraceArgs args,
+ CloneTraceCallback cb) {
+ auto* muxer = muxer_;
+ auto session_id = session_id_;
+ muxer->task_runner_->PostTask([muxer, session_id, args, cb] {
+ muxer->CloneTracingSession(session_id, args, std::move(cb));
+ });
+}
- TracingBackend::ConnectProducerArgs producer_conn_args;
- std::unique_ptr<ProducerImpl> producer;
+// Can be called from any thread.
+void TracingMuxerImpl::TracingSessionImpl::ChangeTraceConfig(
+ const TraceConfig& cfg) {
+ auto* muxer = muxer_;
+ auto session_id = session_id_;
+ muxer->task_runner_->PostTask([muxer, session_id, cfg] {
+ muxer->ChangeTracingSessionConfig(session_id, cfg);
+ });
+}
- std::vector<RegisteredStartupSession> startup_sessions;
- };
+// Can be called from any thread except the service thread.
+void TracingMuxerImpl::TracingSessionImpl::StartBlocking() {
+ PERFETTO_DCHECK(!muxer_->task_runner_->RunsTasksOnCurrentThread());
+ auto* muxer = muxer_;
+ auto session_id = session_id_;
+ base::WaitableEvent tracing_started;
+ muxer->task_runner_->PostTask([muxer, session_id, &tracing_started] {
+ auto* consumer = muxer->FindConsumer(session_id);
+ if (!consumer) {
+ // TODO(skyostil): Signal an error to the user.
+ tracing_started.Notify();
+ return;
+ }
+ PERFETTO_DCHECK(!consumer->blocking_start_complete_callback_);
+ consumer->blocking_start_complete_callback_ = [&] {
+ tracing_started.Notify();
+ };
+ muxer->StartTracingSession(session_id);
+ });
+ tracing_started.Wait();
+}
- struct RegisteredConsumerBackend {
- // Backends are supposed to have static lifetime.
- TracingConsumerBackend* backend = nullptr;
- BackendType type{};
- // The calling code can request more than one concurrently active tracing
- // session for the same backend. We need to create one consumer per session.
- std::vector<std::unique_ptr<ConsumerImpl>> consumers;
- };
+// Can be called from any thread.
+void TracingMuxerImpl::TracingSessionImpl::Flush(
+ std::function<void(bool)> user_callback,
+ uint32_t timeout_ms) {
+ auto* muxer = muxer_;
+ auto session_id = session_id_;
+ muxer->task_runner_->PostTask([muxer, session_id, timeout_ms, user_callback] {
+ auto* consumer = muxer->FindConsumer(session_id);
+ if (!consumer) {
+ std::move(user_callback)(false);
+ return;
+ }
+ muxer->FlushTracingSession(session_id, timeout_ms,
+ std::move(user_callback));
+ });
+}
- void UpdateDataSourceOnAllBackends(RegisteredDataSource& rds,
- bool is_changed);
- explicit TracingMuxerImpl(const TracingInitArgs&);
- void Initialize(const TracingInitArgs& args);
- void AddBackends(const TracingInitArgs& args);
- void AddConsumerBackend(TracingConsumerBackend* backend, BackendType type);
- void AddProducerBackend(TracingProducerBackend* backend,
- BackendType type,
- const TracingInitArgs& args);
- ConsumerImpl* FindConsumer(TracingSessionGlobalID session_id);
- std::pair<ConsumerImpl*, RegisteredConsumerBackend*> FindConsumerAndBackend(
- TracingSessionGlobalID session_id);
- RegisteredProducerBackend* FindProducerBackendById(TracingBackendId id);
- RegisteredProducerBackend* FindProducerBackendByType(BackendType type);
- RegisteredConsumerBackend* FindConsumerBackendByType(BackendType type);
- void InitializeConsumer(TracingSessionGlobalID session_id);
- void OnConsumerDisconnected(ConsumerImpl* consumer);
- void OnProducerDisconnected(ProducerImpl* producer);
- // Test only method.
- void SweepDeadBackends();
+// Can be called from any thread.
+void TracingMuxerImpl::TracingSessionImpl::Stop() {
+ auto* muxer = muxer_;
+ auto session_id = session_id_;
+ muxer->task_runner_->PostTask(
+ [muxer, session_id] { muxer->StopTracingSession(session_id); });
+}
- struct FindDataSourceRes {
- FindDataSourceRes() = default;
- FindDataSourceRes(DataSourceStaticState* a,
- DataSourceState* b,
- uint32_t c,
- bool d)
- : static_state(a),
- internal_state(b),
- instance_idx(c),
- requires_callbacks_under_lock(d) {}
- explicit operator bool() const { return !!internal_state; }
+// Can be called from any thread except the service thread.
+void TracingMuxerImpl::TracingSessionImpl::StopBlocking() {
+ PERFETTO_DCHECK(!muxer_->task_runner_->RunsTasksOnCurrentThread());
+ auto* muxer = muxer_;
+ auto session_id = session_id_;
+ base::WaitableEvent tracing_stopped;
+ muxer->task_runner_->PostTask([muxer, session_id, &tracing_stopped] {
+ auto* consumer = muxer->FindConsumer(session_id);
+ if (!consumer) {
+ // TODO(skyostil): Signal an error to the user.
+ tracing_stopped.Notify();
+ return;
+ }
+ PERFETTO_DCHECK(!consumer->blocking_stop_complete_callback_);
+ consumer->blocking_stop_complete_callback_ = [&] {
+ tracing_stopped.Notify();
+ };
+ muxer->StopTracingSession(session_id);
+ });
+ tracing_stopped.Wait();
+}
- DataSourceStaticState* static_state = nullptr;
- DataSourceState* internal_state = nullptr;
- uint32_t instance_idx = 0;
- bool requires_callbacks_under_lock = false;
- };
- FindDataSourceRes FindDataSource(TracingBackendId, DataSourceInstanceID);
+// Can be called from any thread.
+void TracingMuxerImpl::TracingSessionImpl::ReadTrace(ReadTraceCallback cb) {
+ auto* muxer = muxer_;
+ auto session_id = session_id_;
+ muxer->task_runner_->PostTask([muxer, session_id, cb] {
+ muxer->ReadTracingSessionData(session_id, std::move(cb));
+ });
+}
- FindDataSourceRes SetupDataSourceImpl(
- const RegisteredDataSource&,
- TracingBackendId,
- uint32_t backend_connection_id,
- DataSourceInstanceID,
- const DataSourceConfig&,
- TracingSessionGlobalID startup_session_id);
- void StartDataSourceImpl(const FindDataSourceRes&);
- void StopDataSource_AsyncBeginImpl(const FindDataSourceRes&);
- void StopDataSource_AsyncEnd(TracingBackendId,
- uint32_t backend_connection_id,
- DataSourceInstanceID,
- const FindDataSourceRes&);
- bool FlushDataSource_AsyncBegin(TracingBackendId,
- DataSourceInstanceID,
- FlushRequestID,
- FlushFlags);
- void FlushDataSource_AsyncEnd(TracingBackendId,
- uint32_t backend_connection_id,
- DataSourceInstanceID,
- const FindDataSourceRes&,
- FlushRequestID);
- void AbortStartupTracingSession(TracingSessionGlobalID, BackendType);
- // When ResetForTesting() is executed, `cb` will be called on the calling
- // thread and on the muxer thread.
- void AppendResetForTestingCallback(std::function<void()> cb);
+// Can be called from any thread.
+void TracingMuxerImpl::TracingSessionImpl::SetOnStartCallback(
+ std::function<void()> cb) {
+ auto* muxer = muxer_;
+ auto session_id = session_id_;
+ muxer->task_runner_->PostTask([muxer, session_id, cb] {
+ auto* consumer = muxer->FindConsumer(session_id);
+ if (!consumer)
+ return;
+ consumer->start_complete_callback_ = cb;
+ });
+}
- // WARNING: If you add new state here, be sure to update ResetForTesting.
- std::unique_ptr<base::TaskRunner> task_runner_;
- std::vector<RegisteredDataSource> data_sources_;
- // These lists can only have one backend per BackendType. The elements are
- // sorted by BackendType priority (see BackendTypePriority). They always
- // contain a fake low-priority kUnspecifiedBackend at the end.
- std::list<RegisteredProducerBackend> producer_backends_;
- std::list<RegisteredConsumerBackend> consumer_backends_;
- std::vector<RegisteredInterceptor> interceptors_;
- TracingPolicy* policy_ = nullptr;
+// Can be called from any thread
+void TracingMuxerImpl::TracingSessionImpl::SetOnErrorCallback(
+ std::function<void(TracingError)> cb) {
+ auto* muxer = muxer_;
+ auto session_id = session_id_;
+ muxer->task_runner_->PostTask([muxer, session_id, cb] {
+ auto* consumer = muxer->FindConsumer(session_id);
+ if (!consumer) {
+ // Notify the client about concurrent disconnection of the session.
+ if (cb)
+ cb(TracingError{TracingError::kDisconnected, "Peer disconnected"});
+ return;
+ }
+ consumer->error_callback_ = cb;
+ });
+}
+
+// Can be called from any thread.
+void TracingMuxerImpl::TracingSessionImpl::SetOnStopCallback(
+ std::function<void()> cb) {
+ auto* muxer = muxer_;
+ auto session_id = session_id_;
+ muxer->task_runner_->PostTask([muxer, session_id, cb] {
+ auto* consumer = muxer->FindConsumer(session_id);
+ if (!consumer)
+ return;
+ consumer->stop_complete_callback_ = cb;
+ });
+}
- // Learn more at TracingInitArgs::supports_multiple_data_source_instances
- bool supports_multiple_data_source_instances_ = true;
+// Can be called from any thread.
+void TracingMuxerImpl::TracingSessionImpl::GetTraceStats(
+ GetTraceStatsCallback cb) {
+ auto* muxer = muxer_;
+ auto session_id = session_id_;
+ muxer->task_runner_->PostTask([muxer, session_id, cb] {
+ muxer->GetTraceStats(session_id, std::move(cb));
+ });
+}
- std::atomic<TracingSessionGlobalID> next_tracing_session_id_{};
- std::atomic<uint32_t> next_data_source_index_{};
- uint32_t muxer_id_for_testing_{};
+// Can be called from any thread.
+void TracingMuxerImpl::TracingSessionImpl::QueryServiceState(
+ QueryServiceStateCallback cb) {
+ auto* muxer = muxer_;
+ auto session_id = session_id_;
+ muxer->task_runner_->PostTask([muxer, session_id, cb] {
+ muxer->QueryServiceState(session_id, std::move(cb));
+ });
+}
- // Maximum number of times we will try to reconnect producer backend.
- // Should only be modified for testing purposes.
- std::atomic<uint32_t> max_producer_reconnections_{100u};
+// ----- End of TracingMuxerImpl::TracingSessionImpl
- // Test only member.
- // After ResetForTesting() is called, holds tracing backends which needs to be
- // kept alive until all inbound references have gone away. See
- // SweepDeadBackends().
- std::list<RegisteredProducerBackend> dead_backends_;
+// ----- Begin of TracingMuxerImpl::StartupTracingSessionImpl
- // Test only member.
- // Executes these cleanup functions on the calling thread and on the muxer
- // thread when ResetForTesting() is called.
- std::list<std::function<void()>> reset_callbacks_;
+TracingMuxerImpl::StartupTracingSessionImpl::StartupTracingSessionImpl(
+ TracingMuxerImpl* muxer,
+ TracingSessionGlobalID session_id,
+ BackendType backend_type)
+ : muxer_(muxer), session_id_(session_id), backend_type_(backend_type) {}
- PERFETTO_THREAD_CHECKER(thread_checker_)
-};
+// Can be destroyed from any thread.
+TracingMuxerImpl::StartupTracingSessionImpl::~StartupTracingSessionImpl() =
+ default;
-} // namespace internal
-} // namespace perfetto
+void TracingMuxerImpl::StartupTracingSessionImpl::Abort() {
+ auto* muxer = muxer_;
+ auto session_id = session_id_;
+ auto backend_type = backend_type_;
+ muxer->task_runner_->PostTask([muxer, session_id, backend_type] {
+ muxer->AbortStartupTracingSession(session_id, backend_type);
+ });
+}
-#endif // SRC_TRACING_INTERNAL_TRACING_MUXER_IMPL_H_
-// gen_amalgamated begin header: include/perfetto/ext/tracing/core/trace_stats.h
-/*
- * 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.
- */
+// Must not be called from the SDK's internal thread.
+void TracingMuxerImpl::StartupTracingSessionImpl::AbortBlocking() {
+ auto* muxer = muxer_;
+ auto session_id = session_id_;
+ auto backend_type = backend_type_;
+ PERFETTO_CHECK(!muxer->task_runner_->RunsTasksOnCurrentThread());
+ base::WaitableEvent event;
+ muxer->task_runner_->PostTask([muxer, session_id, backend_type, &event] {
+ muxer->AbortStartupTracingSession(session_id, backend_type);
+ event.Notify();
+ });
+ event.Wait();
+}
-#ifndef INCLUDE_PERFETTO_EXT_TRACING_CORE_TRACE_STATS_H_
-#define INCLUDE_PERFETTO_EXT_TRACING_CORE_TRACE_STATS_H_
+// ----- End of TracingMuxerImpl::StartupTracingSessionImpl
-// Creates the aliases in the ::perfetto namespace, doing things like:
-// using ::perfetto::Foo = ::perfetto::protos::gen::Foo.
-// See comments in forward_decls.h for the historical reasons of this
-// indirection layer.
-// gen_amalgamated expanded: #include "perfetto/tracing/core/forward_decls.h"
+// static
+TracingMuxer* TracingMuxer::instance_ = TracingMuxerFake::Get();
-// gen_amalgamated expanded: #include "protos/perfetto/common/trace_stats.gen.h"
+// This is called by perfetto::Tracing::Initialize().
+// Can be called on any thread. Typically, but not necessarily, that will be
+// the embedder's main thread.
+TracingMuxerImpl::TracingMuxerImpl(const TracingInitArgs& args)
+ : TracingMuxer(args.platform ? args.platform
+ : Platform::GetDefaultPlatform()) {
+ PERFETTO_DETACH_FROM_THREAD(thread_checker_);
+ instance_ = this;
-#endif // INCLUDE_PERFETTO_EXT_TRACING_CORE_TRACE_STATS_H_
-// gen_amalgamated begin header: include/perfetto/tracing/core/tracing_service_state.h
-/*
- * 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.
- */
+ // Create the thread where muxer, producers and service will live.
+ Platform::CreateTaskRunnerArgs tr_args{/*name_for_debugging=*/"TracingMuxer"};
+ task_runner_.reset(new NonReentrantTaskRunner(
+ this, platform_->CreateTaskRunner(std::move(tr_args))));
-#ifndef INCLUDE_PERFETTO_TRACING_CORE_TRACING_SERVICE_STATE_H_
-#define INCLUDE_PERFETTO_TRACING_CORE_TRACING_SERVICE_STATE_H_
+ // Run the initializer on that thread.
+ task_runner_->PostTask([this, args] {
+ Initialize(args);
+ AddBackends(args);
+ });
+}
-// Creates the aliases in the ::perfetto namespace, doing things like:
-// using ::perfetto::Foo = ::perfetto::protos::gen::Foo.
-// See comments in forward_decls.h for the historical reasons of this
-// indirection layer.
-// gen_amalgamated expanded: #include "perfetto/tracing/core/forward_decls.h"
+void TracingMuxerImpl::Initialize(const TracingInitArgs& args) {
+ PERFETTO_DCHECK_THREAD(thread_checker_); // Rebind the thread checker.
-// gen_amalgamated expanded: #include "protos/perfetto/common/tracing_service_state.gen.h"
+ policy_ = args.tracing_policy;
+ supports_multiple_data_source_instances_ =
+ args.supports_multiple_data_source_instances;
-#endif // INCLUDE_PERFETTO_TRACING_CORE_TRACING_SERVICE_STATE_H_
-/*
- * 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.
- */
+ // Fallback backend for producer creation for an unsupported backend type.
+ PERFETTO_CHECK(producer_backends_.empty());
+ AddProducerBackend(internal::TracingBackendFake::GetInstance(),
+ BackendType::kUnspecifiedBackend, args);
+ // Fallback backend for consumer creation for an unsupported backend type.
+ // This backend simply fails any attempt to start a tracing session.
+ PERFETTO_CHECK(consumer_backends_.empty());
+ AddConsumerBackend(internal::TracingBackendFake::GetInstance(),
+ BackendType::kUnspecifiedBackend);
+}
-// gen_amalgamated expanded: #include "src/tracing/internal/tracing_muxer_impl.h"
+void TracingMuxerImpl::AddConsumerBackend(TracingConsumerBackend* backend,
+ BackendType type) {
+ if (!backend) {
+ // We skip the log in release builds because the *_backend_fake.cc code
+ // has already an ELOG before returning a nullptr.
+ PERFETTO_DLOG("Consumer backend creation failed, type %d",
+ static_cast<int>(type));
+ return;
+ }
+ // Keep the backends sorted by type.
+ auto it =
+ std::upper_bound(consumer_backends_.begin(), consumer_backends_.end(),
+ type, CompareBackendByType<RegisteredConsumerBackend>());
+ it = consumer_backends_.emplace(it);
-#include <algorithm>
-#include <atomic>
-#include <mutex>
-#include <optional>
-#include <vector>
+ RegisteredConsumerBackend& rb = *it;
+ rb.backend = backend;
+ rb.type = type;
+}
-// gen_amalgamated expanded: #include "perfetto/base/build_config.h"
-// gen_amalgamated expanded: #include "perfetto/base/logging.h"
-// gen_amalgamated expanded: #include "perfetto/base/task_runner.h"
-// gen_amalgamated expanded: #include "perfetto/base/time.h"
-// gen_amalgamated expanded: #include "perfetto/ext/base/fnv_hash.h"
-// gen_amalgamated expanded: #include "perfetto/ext/base/thread_checker.h"
-// gen_amalgamated expanded: #include "perfetto/ext/base/utils.h"
-// gen_amalgamated expanded: #include "perfetto/ext/base/waitable_event.h"
-// gen_amalgamated expanded: #include "perfetto/ext/tracing/core/shared_memory_arbiter.h"
-// gen_amalgamated expanded: #include "perfetto/ext/tracing/core/trace_packet.h"
-// gen_amalgamated expanded: #include "perfetto/ext/tracing/core/trace_stats.h"
-// gen_amalgamated expanded: #include "perfetto/ext/tracing/core/trace_writer.h"
-// gen_amalgamated expanded: #include "perfetto/ext/tracing/core/tracing_service.h"
-// gen_amalgamated expanded: #include "perfetto/tracing/buffer_exhausted_policy.h"
-// gen_amalgamated expanded: #include "perfetto/tracing/core/data_source_config.h"
-// gen_amalgamated expanded: #include "perfetto/tracing/core/tracing_service_state.h"
-// gen_amalgamated expanded: #include "perfetto/tracing/data_source.h"
-// gen_amalgamated expanded: #include "perfetto/tracing/internal/data_source_internal.h"
-// gen_amalgamated expanded: #include "perfetto/tracing/internal/interceptor_trace_writer.h"
-// gen_amalgamated expanded: #include "perfetto/tracing/internal/tracing_backend_fake.h"
-// gen_amalgamated expanded: #include "perfetto/tracing/trace_writer_base.h"
-// gen_amalgamated expanded: #include "perfetto/tracing/tracing.h"
-// gen_amalgamated expanded: #include "perfetto/tracing/tracing_backend.h"
-// gen_amalgamated expanded: #include "src/tracing/core/null_trace_writer.h"
-// gen_amalgamated expanded: #include "src/tracing/internal/tracing_muxer_fake.h"
+void TracingMuxerImpl::AddProducerBackend(TracingProducerBackend* backend,
+ BackendType type,
+ const TracingInitArgs& args) {
+ if (!backend) {
+ // We skip the log in release builds because the *_backend_fake.cc code
+ // has already an ELOG before returning a nullptr.
+ PERFETTO_DLOG("Producer backend creation failed, type %d",
+ static_cast<int>(type));
+ return;
+ }
+ TracingBackendId backend_id = producer_backends_.size();
+ // Keep the backends sorted by type.
+ auto it =
+ std::upper_bound(producer_backends_.begin(), producer_backends_.end(),
+ type, CompareBackendByType<RegisteredProducerBackend>());
+ it = producer_backends_.emplace(it);
-// gen_amalgamated expanded: #include "protos/perfetto/config/interceptor_config.gen.h"
+ RegisteredProducerBackend& rb = *it;
+ rb.backend = backend;
+ rb.id = backend_id;
+ rb.type = type;
+ rb.producer.reset(new ProducerImpl(this, backend_id,
+ args.shmem_batch_commits_duration_ms,
+ args.shmem_direct_patching_enabled));
+ rb.producer_conn_args.producer = rb.producer.get();
+ rb.producer_conn_args.producer_name = platform_->GetCurrentProcessName();
+ rb.producer_conn_args.task_runner = task_runner_.get();
+ rb.producer_conn_args.shmem_size_hint_bytes = args.shmem_size_hint_kb * 1024;
+ rb.producer_conn_args.shmem_page_size_hint_bytes =
+ args.shmem_page_size_hint_kb * 1024;
+ rb.producer_conn_args.create_socket_async = args.create_socket_async;
+ rb.producer_conn_args.machine_id = args.machine_id;
+ rb.producer->Initialize(rb.backend->ConnectProducer(rb.producer_conn_args));
+}
-#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
-#include <io.h> // For dup()
-#else
-#include <unistd.h> // For dup()
-#endif
+TracingMuxerImpl::RegisteredProducerBackend*
+TracingMuxerImpl::FindProducerBackendById(TracingBackendId id) {
+ for (RegisteredProducerBackend& b : producer_backends_) {
+ if (b.id == id) {
+ return &b;
+ }
+ }
+ return nullptr;
+}
-namespace perfetto {
-namespace internal {
+TracingMuxerImpl::RegisteredProducerBackend*
+TracingMuxerImpl::FindProducerBackendByType(BackendType type) {
+ for (RegisteredProducerBackend& b : producer_backends_) {
+ if (b.type == type) {
+ return &b;
+ }
+ }
+ return nullptr;
+}
-namespace {
+TracingMuxerImpl::RegisteredConsumerBackend*
+TracingMuxerImpl::FindConsumerBackendByType(BackendType type) {
+ for (RegisteredConsumerBackend& b : consumer_backends_) {
+ if (b.type == type) {
+ return &b;
+ }
+ }
+ return nullptr;
+}
-using RegisteredDataSource = TracingMuxerImpl::RegisteredDataSource;
+void TracingMuxerImpl::AddBackends(const TracingInitArgs& args) {
+ if (args.backends & kSystemBackend) {
+ PERFETTO_CHECK(args.system_producer_backend_factory_);
+ if (FindProducerBackendByType(kSystemBackend) == nullptr) {
+ AddProducerBackend(args.system_producer_backend_factory_(),
+ kSystemBackend, args);
+ }
+ if (args.enable_system_consumer) {
+ PERFETTO_CHECK(args.system_consumer_backend_factory_);
+ if (FindConsumerBackendByType(kSystemBackend) == nullptr) {
+ AddConsumerBackend(args.system_consumer_backend_factory_(),
+ kSystemBackend);
+ }
+ }
+ }
-// A task runner which prevents calls to DataSource::Trace() while an operation
-// is in progress. Used to guard against unexpected re-entrancy where the
-// user-provided task runner implementation tries to enter a trace point under
-// the hood.
-class NonReentrantTaskRunner : public base::TaskRunner {
- public:
- NonReentrantTaskRunner(TracingMuxer* muxer,
- std::unique_ptr<base::TaskRunner> task_runner)
- : muxer_(muxer), task_runner_(std::move(task_runner)) {}
+ if (args.backends & kInProcessBackend) {
+ TracingBackend* b = nullptr;
+ if (FindProducerBackendByType(kInProcessBackend) == nullptr) {
+ if (!b) {
+ PERFETTO_CHECK(args.in_process_backend_factory_);
+ b = args.in_process_backend_factory_();
+ }
+ AddProducerBackend(b, kInProcessBackend, args);
+ }
+ if (FindConsumerBackendByType(kInProcessBackend) == nullptr) {
+ if (!b) {
+ PERFETTO_CHECK(args.in_process_backend_factory_);
+ b = args.in_process_backend_factory_();
+ }
+ AddConsumerBackend(b, kInProcessBackend);
+ }
+ }
- // base::TaskRunner implementation.
- void PostTask(std::function<void()> task) override {
- CallWithGuard([&] { task_runner_->PostTask(std::move(task)); });
+ if (args.backends & kCustomBackend) {
+ PERFETTO_CHECK(args.custom_backend);
+ if (FindProducerBackendByType(kCustomBackend) == nullptr) {
+ AddProducerBackend(args.custom_backend, kCustomBackend, args);
+ }
+ if (FindConsumerBackendByType(kCustomBackend) == nullptr) {
+ AddConsumerBackend(args.custom_backend, kCustomBackend);
+ }
}
- void PostDelayedTask(std::function<void()> task, uint32_t delay_ms) override {
- CallWithGuard(
- [&] { task_runner_->PostDelayedTask(std::move(task), delay_ms); });
+ if (args.backends & ~(kSystemBackend | kInProcessBackend | kCustomBackend)) {
+ PERFETTO_FATAL("Unsupported tracing backend type");
}
+}
- void AddFileDescriptorWatch(base::PlatformHandle fd,
- std::function<void()> callback) override {
- CallWithGuard(
- [&] { task_runner_->AddFileDescriptorWatch(fd, std::move(callback)); });
+// Can be called from any thread (but not concurrently).
+bool TracingMuxerImpl::RegisterDataSource(
+ const DataSourceDescriptor& descriptor,
+ DataSourceFactory factory,
+ DataSourceParams params,
+ bool no_flush,
+ DataSourceStaticState* static_state) {
+ // Ignore repeated registrations.
+ if (static_state->index != kMaxDataSources) {
+ PERFETTO_ELOG(
+ "Data source \"%s\" registration ignored: this data source type is "
+ "already registered. See "
+ "https://perfetto.dev/docs/instrumentation/"
+ "tracing-sdk#reporting-many-similar-things",
+ descriptor.name().c_str());
+ return true;
}
- void RemoveFileDescriptorWatch(base::PlatformHandle fd) override {
- CallWithGuard([&] { task_runner_->RemoveFileDescriptorWatch(fd); });
+ uint32_t new_index = next_data_source_index_++;
+ if (new_index >= kMaxDataSources) {
+ PERFETTO_DLOG(
+ "RegisterDataSource failed: too many data sources already registered");
+ return false;
}
- bool RunsTasksOnCurrentThread() const override {
- bool result;
- CallWithGuard([&] { result = task_runner_->RunsTasksOnCurrentThread(); });
- return result;
- }
+ // Initialize the static state.
+ static_assert(sizeof(static_state->instances[0]) >= sizeof(DataSourceState),
+ "instances[] size mismatch");
+ for (size_t i = 0; i < static_state->instances.size(); i++)
+ new (&static_state->instances[i]) DataSourceState{};
+
+ static_state->index = new_index;
+
+ // Generate a semi-unique id for this data source.
+ uint64_t digest = base::FnvHasher::Combine(
+ reinterpret_cast<intptr_t>(static_state), base::GetWallTimeNs().count());
+ static_state->id = digest ? digest : 1;
+
+ task_runner_->PostTask(
+ [this, descriptor, factory, static_state, params, no_flush] {
+ data_sources_.emplace_back();
+ RegisteredDataSource& rds = data_sources_.back();
+ rds.descriptor = descriptor;
+ rds.factory = factory;
+ rds.params = params;
+ if (!supports_multiple_data_source_instances_) {
+ rds.params.supports_multiple_instances = false;
+ }
+ rds.static_state = static_state;
+ rds.no_flush = no_flush;
+
+ UpdateDataSourceOnAllBackends(rds, /*is_changed=*/false);
+ });
+ return true;
+}
+
+// Can be called from any thread (but not concurrently).
+void TracingMuxerImpl::UpdateDataSourceDescriptor(
+ const DataSourceDescriptor& descriptor,
+ const DataSourceStaticState* static_state) {
+ task_runner_->PostTask([this, descriptor, static_state] {
+ for (auto& rds : data_sources_) {
+ if (rds.static_state == static_state) {
+ PERFETTO_CHECK(rds.descriptor.name() == descriptor.name());
+ rds.descriptor = descriptor;
+ rds.descriptor.set_id(static_state->id);
+ UpdateDataSourceOnAllBackends(rds, /*is_changed=*/true);
+ return;
+ }
+ }
+ });
+}
+
+// Can be called from any thread (but not concurrently).
+void TracingMuxerImpl::RegisterInterceptor(
+ const InterceptorDescriptor& descriptor,
+ InterceptorFactory factory,
+ InterceptorBase::TLSFactory tls_factory,
+ InterceptorBase::TracePacketCallback packet_callback) {
+ task_runner_->PostTask([this, descriptor, factory, tls_factory,
+ packet_callback] {
+ // Ignore repeated registrations.
+ for (const auto& interceptor : interceptors_) {
+ if (interceptor.descriptor.name() == descriptor.name()) {
+ PERFETTO_DCHECK(interceptor.tls_factory == tls_factory);
+ PERFETTO_DCHECK(interceptor.packet_callback == packet_callback);
+ return;
+ }
+ }
+ // Only allow certain interceptors for now.
+ if (descriptor.name() != "test_interceptor" &&
+ descriptor.name() != "console" && descriptor.name() != "etwexport") {
+ PERFETTO_ELOG(
+ "Interceptors are experimental. If you want to use them, please "
+ "get in touch with the project maintainers "
+ "(https://perfetto.dev/docs/contributing/"
+ "getting-started#community).");
+ return;
+ }
+ interceptors_.emplace_back();
+ RegisteredInterceptor& interceptor = interceptors_.back();
+ interceptor.descriptor = descriptor;
+ interceptor.factory = factory;
+ interceptor.tls_factory = tls_factory;
+ interceptor.packet_callback = packet_callback;
+ });
+}
+
+void TracingMuxerImpl::ActivateTriggers(
+ const std::vector<std::string>& triggers,
+ uint32_t ttl_ms) {
+ base::TimeMillis expire_time =
+ base::GetWallTimeMs() + base::TimeMillis(ttl_ms);
+ task_runner_->PostTask([this, triggers, expire_time] {
+ for (RegisteredProducerBackend& backend : producer_backends_) {
+ if (backend.producer->connected_) {
+ backend.producer->service_->ActivateTriggers(triggers);
+ } else {
+ for (const std::string& trigger : triggers) {
+ backend.producer->on_connect_triggers_.emplace_back(trigger,
+ expire_time);
+ }
+ }
+ }
+ });
+}
+
+// Checks if there is any matching startup tracing data source instance for a
+// new SetupDataSource call. If so, moves the data source to this tracing
+// session (and its target buffer) and returns true, otherwise returns false.
+static bool MaybeAdoptStartupTracingInDataSource(
+ TracingBackendId backend_id,
+ uint32_t backend_connection_id,
+ DataSourceInstanceID instance_id,
+ const DataSourceConfig& cfg,
+ const std::vector<RegisteredDataSource>& data_sources) {
+ for (const auto& rds : data_sources) {
+ DataSourceStaticState* static_state = rds.static_state;
+ for (uint32_t i = 0; i < kMaxDataSourceInstances; i++) {
+ auto* internal_state = static_state->TryGet(i);
+
+ if (internal_state &&
+ internal_state->startup_target_buffer_reservation.load(
+ std::memory_order_relaxed) &&
+ internal_state->data_source_instance_id == 0 &&
+ internal_state->backend_id == backend_id &&
+ internal_state->backend_connection_id == backend_connection_id &&
+ internal_state->config &&
+ internal_state->data_source->CanAdoptStartupSession(
+ *internal_state->config, cfg)) {
+ PERFETTO_DLOG("Setting up data source %" PRIu64
+ " %s by adopting it from a startup tracing session",
+ instance_id, cfg.name().c_str());
+
+ std::lock_guard<std::recursive_mutex> lock(internal_state->lock);
+ // Set the associations. The actual takeover happens in
+ // StartDataSource().
+ internal_state->data_source_instance_id = instance_id;
+ internal_state->buffer_id =
+ static_cast<internal::BufferId>(cfg.target_buffer());
+ internal_state->buffer_exhausted_policy =
+ ComputeBufferExhaustedPolicy(cfg, rds.params);
+ internal_state->config.reset(new DataSourceConfig(cfg));
+
+ // TODO(eseckler): Should the data source config provided by the service
+ // be allowed to specify additional interceptors / additional data
+ // source params?
- private:
- template <typename T>
- void CallWithGuard(T lambda) const {
- auto* root_tls = muxer_->GetOrCreateTracingTLS();
- if (PERFETTO_UNLIKELY(root_tls->is_in_trace_point)) {
- lambda();
- return;
+ return true;
+ }
}
- ScopedReentrancyAnnotator scoped_annotator(*root_tls);
- lambda();
- }
-
- TracingMuxer* const muxer_;
- std::unique_ptr<base::TaskRunner> task_runner_;
-};
-
-class StopArgsImpl : public DataSourceBase::StopArgs {
- public:
- std::function<void()> HandleStopAsynchronously() const override {
- auto closure = std::move(async_stop_closure);
- async_stop_closure = std::function<void()>();
- return closure;
}
+ return false;
+}
- mutable std::function<void()> async_stop_closure;
-};
+// Called by the service of one of the backends.
+void TracingMuxerImpl::SetupDataSource(TracingBackendId backend_id,
+ uint32_t backend_connection_id,
+ DataSourceInstanceID instance_id,
+ const DataSourceConfig& cfg) {
+ PERFETTO_DLOG("Setting up data source %" PRIu64 " %s", instance_id,
+ cfg.name().c_str());
+ PERFETTO_DCHECK_THREAD(thread_checker_);
-class FlushArgsImpl : public DataSourceBase::FlushArgs {
- public:
- std::function<void()> HandleFlushAsynchronously() const override {
- auto closure = std::move(async_flush_closure);
- async_flush_closure = std::function<void()>();
- return closure;
+ // First check if there is any matching startup tracing data source instance.
+ if (MaybeAdoptStartupTracingInDataSource(backend_id, backend_connection_id,
+ instance_id, cfg, data_sources_)) {
+ return;
}
- mutable std::function<void()> async_flush_closure;
-};
-
-// Holds an earlier TracingMuxerImpl instance after ResetForTesting() is called.
-static TracingMuxerImpl* g_prev_instance{};
+ for (const auto& rds : data_sources_) {
+ if (rds.descriptor.name() != cfg.name())
+ continue;
+ DataSourceStaticState& static_state = *rds.static_state;
-template <typename RegisteredBackend>
-struct CompareBackendByType {
- static int BackendTypePriority(BackendType type) {
- switch (type) {
- case kSystemBackend:
- return 0;
- case kInProcessBackend:
- return 1;
- case kCustomBackend:
- return 2;
- // The UnspecifiedBackend has the highest priority so that
- // TracingBackendFake is the last one on the backend lists.
- case kUnspecifiedBackend:
+ // If this data source is already active for this exact config, don't start
+ // another instance. This happens when we have several data sources with the
+ // same name, in which case the service sends one SetupDataSource event for
+ // each one. Since we can't map which event maps to which data source, we
+ // ensure each event only starts one data source instance.
+ // TODO(skyostil): Register a unique id with each data source to the service
+ // to disambiguate.
+ bool active_for_config = false;
+ for (uint32_t i = 0; i < kMaxDataSourceInstances; i++) {
+ if (!static_state.TryGet(i))
+ continue;
+ auto* internal_state =
+ reinterpret_cast<DataSourceState*>(&static_state.instances[i]);
+ if (internal_state->backend_id == backend_id &&
+ internal_state->backend_connection_id == backend_connection_id &&
+ internal_state->config && *internal_state->config == cfg) {
+ active_for_config = true;
break;
+ }
}
- return 3;
- }
- bool operator()(BackendType type, const RegisteredBackend& b) {
- return BackendTypePriority(type) < BackendTypePriority(b.type);
+ if (active_for_config) {
+ PERFETTO_DLOG(
+ "Data source %s is already active with this config, skipping",
+ cfg.name().c_str());
+ continue;
+ }
+
+ SetupDataSourceImpl(rds, backend_id, backend_connection_id, instance_id,
+ cfg, /*startup_session_id=*/0);
+ return;
}
-};
+}
-BufferExhaustedPolicy ComputeBufferExhaustedPolicy(
+TracingMuxerImpl::FindDataSourceRes TracingMuxerImpl::SetupDataSourceImpl(
+ const RegisteredDataSource& rds,
+ TracingBackendId backend_id,
+ uint32_t backend_connection_id,
+ DataSourceInstanceID instance_id,
const DataSourceConfig& cfg,
- const DataSourceParams& params) {
- if (!params.buffer_exhausted_policy_configurable) {
- return params.default_buffer_exhausted_policy;
- }
+ TracingSessionGlobalID startup_session_id) {
+ PERFETTO_DCHECK_THREAD(thread_checker_);
+ DataSourceStaticState& static_state = *rds.static_state;
- switch (cfg.buffer_exhausted_policy()) {
- case DataSourceConfig::BUFFER_EXHAUSTED_UNSPECIFIED:
- return params.default_buffer_exhausted_policy;
- case DataSourceConfig::BUFFER_EXHAUSTED_DROP:
- return BufferExhaustedPolicy::kDrop;
- case DataSourceConfig::BUFFER_EXHAUSTED_STALL_THEN_ABORT:
- return BufferExhaustedPolicy::kStall;
- case DataSourceConfig::BUFFER_EXHAUSTED_STALL_THEN_DROP:
- return BufferExhaustedPolicy::kStallThenDrop;
+ // If any bit is set in `static_state.valid_instances` then at least one
+ // other instance of data source is running.
+ if (!rds.params.supports_multiple_instances &&
+ static_state.valid_instances.load(std::memory_order_acquire) != 0) {
+ PERFETTO_ELOG(
+ "Failed to setup data source because some another instance of this "
+ "data source is already active");
+ return FindDataSourceRes();
}
- return params.default_buffer_exhausted_policy;
-}
+ for (uint32_t i = 0; i < kMaxDataSourceInstances; i++) {
+ // Find a free slot.
+ if (static_state.TryGet(i))
+ continue;
-} // namespace
+ auto* internal_state =
+ reinterpret_cast<DataSourceState*>(&static_state.instances[i]);
+ std::unique_lock<std::recursive_mutex> lock(internal_state->lock);
+ static_assert(
+ std::is_same<decltype(internal_state->data_source_instance_id),
+ DataSourceInstanceID>::value,
+ "data_source_instance_id type mismatch");
+ internal_state->muxer_id_for_testing = muxer_id_for_testing_;
+ RegisteredProducerBackend& backend = *FindProducerBackendById(backend_id);
-// ----- Begin of TracingMuxerImpl::ProducerImpl
-TracingMuxerImpl::ProducerImpl::ProducerImpl(
- TracingMuxerImpl* muxer,
- TracingBackendId backend_id,
- uint32_t shmem_batch_commits_duration_ms,
- bool shmem_direct_patching_enabled)
- : muxer_(muxer),
- backend_id_(backend_id),
- shmem_batch_commits_duration_ms_(shmem_batch_commits_duration_ms),
- shmem_direct_patching_enabled_(shmem_direct_patching_enabled) {}
+ if (startup_session_id) {
+ uint16_t& last_reservation =
+ backend.producer->last_startup_target_buffer_reservation_;
+ if (last_reservation == std::numeric_limits<uint16_t>::max()) {
+ PERFETTO_ELOG(
+ "Startup buffer reservations exhausted, dropping data source");
+ return FindDataSourceRes();
+ }
+ internal_state->startup_target_buffer_reservation.store(
+ ++last_reservation, std::memory_order_relaxed);
+ } else {
+ internal_state->startup_target_buffer_reservation.store(
+ 0, std::memory_order_relaxed);
+ }
-TracingMuxerImpl::ProducerImpl::~ProducerImpl() {
- muxer_ = nullptr;
-}
+ internal_state->backend_id = backend_id;
+ internal_state->backend_connection_id = backend_connection_id;
+ internal_state->data_source_instance_id = instance_id;
+ internal_state->buffer_id =
+ static_cast<internal::BufferId>(cfg.target_buffer());
+ internal_state->buffer_exhausted_policy =
+ ComputeBufferExhaustedPolicy(cfg, rds.params);
+ internal_state->config.reset(new DataSourceConfig(cfg));
+ internal_state->startup_session_id = startup_session_id;
+ internal_state->data_source = rds.factory();
+ internal_state->interceptor = nullptr;
+ internal_state->interceptor_id = 0;
+ internal_state->will_notify_on_stop = rds.descriptor.will_notify_on_stop();
-void TracingMuxerImpl::ProducerImpl::Initialize(
- std::unique_ptr<ProducerEndpoint> endpoint) {
- PERFETTO_DCHECK_THREAD(thread_checker_);
- PERFETTO_DCHECK(!connected_);
- connection_id_.fetch_add(1, std::memory_order_relaxed);
- is_producer_provided_smb_ = endpoint->shared_memory();
- last_startup_target_buffer_reservation_ = 0;
+ if (cfg.has_interceptor_config()) {
+ for (size_t j = 0; j < interceptors_.size(); j++) {
+ if (cfg.interceptor_config().name() ==
+ interceptors_[j].descriptor.name()) {
+ PERFETTO_DLOG("Intercepting data source %" PRIu64
+ " \"%s\" into \"%s\"",
+ instance_id, cfg.name().c_str(),
+ cfg.interceptor_config().name().c_str());
+ internal_state->interceptor_id = static_cast<uint32_t>(j + 1);
+ internal_state->interceptor = interceptors_[j].factory();
+ internal_state->interceptor->OnSetup({cfg});
+ break;
+ }
+ }
+ if (!internal_state->interceptor_id) {
+ PERFETTO_ELOG("Unknown interceptor configured for data source: %s",
+ cfg.interceptor_config().name().c_str());
+ }
+ }
- // Adopt the endpoint into a shared pointer so that we can safely share it
- // across threads that create trace writers. The custom deleter function
- // ensures that the endpoint is always destroyed on the muxer's thread. (Note
- // that |task_runner| is assumed to outlive tracing sessions on all threads.)
- auto* task_runner = muxer_->task_runner_.get();
- auto deleter = [task_runner](ProducerEndpoint* e) {
- if (task_runner->RunsTasksOnCurrentThread()) {
- delete e;
- return;
+ // Select v1 or v2 once, so that all writers of this instance agree.
+ // A startup instance keeps v1, also after adoption.
+ // An intercepted instance takes its writer from the interceptor.
+ internal_state->use_tracing_v2 =
+ !startup_session_id && !internal_state->interceptor_id &&
+ rds.params.supports_tracing_v2 && cfg.supports_tracing_v2();
+ const uint32_t probability =
+ cfg.experimental_tracing_v2().use_v2_probability_percent();
+ if (internal_state->use_tracing_v2 && probability < 100) {
+ internal_state->use_tracing_v2 =
+ static_cast<uint64_t>(base::Uuidv4().lsb()) % 100 < probability;
}
- task_runner->PostTask([e] { delete e; });
- };
- std::shared_ptr<ProducerEndpoint> service(endpoint.release(), deleter);
- // This atomic store is needed because another thread might be concurrently
- // creating a trace writer using the previous (disconnected) |service_|. See
- // CreateTraceWriter().
- std::atomic_store(&service_, std::move(service));
- // Don't try to use the service here since it may not have connected yet. See
- // OnConnect().
-}
+ // Complete initialization before writer threads can observe this instance.
+ if (internal_state->use_tracing_v2)
+ backend.producer->service_->InitializeV2RingBuffer(cfg);
-void TracingMuxerImpl::ProducerImpl::OnConnect() {
- PERFETTO_DLOG("Producer connected");
- PERFETTO_DCHECK_THREAD(thread_checker_);
- PERFETTO_DCHECK(!connected_);
- if (is_producer_provided_smb_ && !service_->IsShmemProvidedByProducer()) {
- PERFETTO_ELOG(
- "The service likely doesn't support producer-provided SMBs. Preventing "
- "future attempts to use producer-provided SMB again with this "
- "backend.");
- producer_provided_smb_failed_ = true;
- // Will call OnDisconnect() and cause a reconnect without producer-provided
- // SMB.
- service_->Disconnect();
- return;
- }
- connected_ = true;
- muxer_->UpdateDataSourcesOnAllBackends();
- SendOnConnectTriggers();
-}
+ // This must be made at the end. See matching acquire-load in
+ // DataSource::Trace().
+ static_state.valid_instances.fetch_or(1 << i, std::memory_order_release);
-void TracingMuxerImpl::ProducerImpl::OnDisconnect() {
- PERFETTO_DCHECK_THREAD(thread_checker_);
- // If we're being destroyed, bail out.
- if (!muxer_)
- return;
- connected_ = false;
- // Active data sources for this producer will be stopped by
- // DestroyStoppedTraceWritersForCurrentThread() since the reconnected producer
- // will have a different connection id (even before it has finished
- // connecting).
- registered_data_sources_.reset();
- DisposeConnection();
+ DataSourceBase::SetupArgs setup_args;
+ setup_args.config = &cfg;
+ setup_args.backend_type = backend.type;
+ setup_args.internal_instance_index = i;
- // Try reconnecting the producer.
- muxer_->OnProducerDisconnected(this);
-}
+ if (!rds.params.requires_callbacks_under_lock)
+ lock.unlock();
+ internal_state->data_source->OnSetup(setup_args);
-void TracingMuxerImpl::ProducerImpl::DisposeConnection() {
- // Keep the old service around as a dead connection in case it has active
- // trace writers. If any tracing sessions were created, we can't clear
- // |service_| here because other threads may be concurrently creating new
- // trace writers. Any reconnection attempt will atomically swap the new
- // service in place of the old one.
- if (did_setup_tracing_ || did_setup_startup_tracing_) {
- dead_services_.push_back(service_);
- } else {
- service_.reset();
+ return FindDataSourceRes(&static_state, internal_state, i,
+ rds.params.requires_callbacks_under_lock);
}
+ PERFETTO_ELOG(
+ "Maximum number of data source instances exhausted. "
+ "Dropping data source %" PRIu64,
+ instance_id);
+ return FindDataSourceRes();
}
-void TracingMuxerImpl::ProducerImpl::OnTracingSetup() {
+// Called by the service of one of the backends.
+void TracingMuxerImpl::StartDataSource(TracingBackendId backend_id,
+ DataSourceInstanceID instance_id) {
+ PERFETTO_DLOG("Starting data source %" PRIu64, instance_id);
PERFETTO_DCHECK_THREAD(thread_checker_);
- did_setup_tracing_ = true;
- service_->MaybeSharedMemoryArbiter()->SetBatchCommitsDuration(
- shmem_batch_commits_duration_ms_);
- if (shmem_direct_patching_enabled_) {
- service_->MaybeSharedMemoryArbiter()->EnableDirectSMBPatching();
+
+ auto ds = FindDataSource(backend_id, instance_id);
+ if (!ds) {
+ PERFETTO_ELOG("Could not find data source to start");
+ return;
}
-}
-void TracingMuxerImpl::ProducerImpl::OnStartupTracingSetup() {
- PERFETTO_DCHECK_THREAD(thread_checker_);
- did_setup_startup_tracing_ = true;
-}
+ // Check if the data source was already started for startup tracing.
+ uint16_t startup_reservation =
+ ds.internal_state->startup_target_buffer_reservation.load(
+ std::memory_order_relaxed);
+ if (startup_reservation) {
+ RegisteredProducerBackend& backend = *FindProducerBackendById(backend_id);
+ TracingSessionGlobalID session_id = ds.internal_state->startup_session_id;
+ auto session_it = std::find_if(
+ backend.startup_sessions.begin(), backend.startup_sessions.end(),
+ [session_id](const RegisteredStartupSession& session) {
+ return session.session_id == session_id;
+ });
+ PERFETTO_DCHECK(session_it != backend.startup_sessions.end());
-void TracingMuxerImpl::ProducerImpl::SetupDataSource(
- DataSourceInstanceID id,
- const DataSourceConfig& cfg) {
- PERFETTO_DCHECK_THREAD(thread_checker_);
- if (!muxer_)
- return;
- muxer_->SetupDataSource(
- backend_id_, connection_id_.load(std::memory_order_relaxed), id, cfg);
-}
+ if (session_it->is_aborting) {
+ PERFETTO_DLOG("Data source %" PRIu64
+ " was already aborted for startup tracing, not starting it",
+ instance_id);
+ return;
+ }
-void TracingMuxerImpl::ProducerImpl::StartDataSource(DataSourceInstanceID id,
- const DataSourceConfig&) {
- PERFETTO_DCHECK_THREAD(thread_checker_);
- if (!muxer_)
- return;
- muxer_->StartDataSource(backend_id_, id);
- service_->NotifyDataSourceStarted(id);
-}
+ PERFETTO_DLOG(
+ "Data source %" PRIu64
+ " was already started for startup tracing, binding its target buffer",
+ instance_id);
-void TracingMuxerImpl::ProducerImpl::StopDataSource(DataSourceInstanceID id) {
- PERFETTO_DCHECK_THREAD(thread_checker_);
- if (!muxer_)
+ backend.producer->service_->MaybeSharedMemoryArbiter()
+ ->BindStartupTargetBuffer(startup_reservation,
+ ds.internal_state->buffer_id);
+
+ // The reservation ID can be used even after binding it, so there's no need
+ // for any barriers here - we just need atomicity.
+ ds.internal_state->startup_target_buffer_reservation.store(
+ 0, std::memory_order_relaxed);
+
+ // TODO(eseckler): Should we reset incremental state at this point, or
+ // notify the data source some other way?
+
+ // The session should not have been fully bound yet (or aborted).
+ PERFETTO_DCHECK(session_it->num_unbound_data_sources > 0);
+
+ session_it->num_unbound_data_sources--;
+ if (session_it->num_unbound_data_sources == 0) {
+ if (session_it->on_adopted)
+ task_runner_->PostTask(session_it->on_adopted);
+ backend.startup_sessions.erase(session_it);
+ }
return;
- muxer_->StopDataSource_AsyncBegin(backend_id_, id);
+ }
+
+ StartDataSourceImpl(ds);
}
-void TracingMuxerImpl::ProducerImpl::Flush(
- FlushRequestID flush_id,
- const DataSourceInstanceID* instances,
- size_t instance_count,
- FlushFlags flush_flags) {
+void TracingMuxerImpl::StartDataSourceImpl(const FindDataSourceRes& ds) {
PERFETTO_DCHECK_THREAD(thread_checker_);
- bool all_handled = true;
- if (muxer_) {
- for (size_t i = 0; i < instance_count; i++) {
- DataSourceInstanceID ds_id = instances[i];
- bool handled = muxer_->FlushDataSource_AsyncBegin(backend_id_, ds_id,
- flush_id, flush_flags);
- if (!handled) {
- pending_flushes_[flush_id].insert(ds_id);
- all_handled = false;
- }
- }
- }
- if (all_handled) {
- service_->NotifyFlushComplete(flush_id);
- }
+ DataSourceBase::StartArgs start_args{};
+ start_args.internal_instance_index = ds.instance_idx;
+
+ std::unique_lock<std::recursive_mutex> lock(ds.internal_state->lock);
+ if (ds.internal_state->interceptor)
+ ds.internal_state->interceptor->OnStart({});
+ ds.internal_state->trace_lambda_enabled.store(true,
+ std::memory_order_relaxed);
+ PERFETTO_DCHECK(ds.internal_state->data_source != nullptr);
+
+ if (!ds.requires_callbacks_under_lock)
+ lock.unlock();
+ ds.internal_state->data_source->OnStart(start_args);
}
-void TracingMuxerImpl::ProducerImpl::ClearIncrementalState(
- const DataSourceInstanceID* instances,
- size_t instance_count) {
+// Called by the service of one of the backends.
+void TracingMuxerImpl::StopDataSource_AsyncBegin(
+ TracingBackendId backend_id,
+ DataSourceInstanceID instance_id) {
+ PERFETTO_DLOG("Stopping data source %" PRIu64, instance_id);
PERFETTO_DCHECK_THREAD(thread_checker_);
- if (!muxer_)
+
+ auto ds = FindDataSource(backend_id, instance_id);
+ if (!ds) {
+ PERFETTO_ELOG("Could not find data source to stop");
return;
- for (size_t inst_idx = 0; inst_idx < instance_count; inst_idx++) {
- muxer_->ClearDataSourceIncrementalState(backend_id_, instances[inst_idx]);
}
+
+ StopDataSource_AsyncBeginImpl(ds);
}
-bool TracingMuxerImpl::ProducerImpl::SweepDeadServices() {
- PERFETTO_DCHECK_THREAD(thread_checker_);
- auto is_unused = [](const std::shared_ptr<ProducerEndpoint>& endpoint) {
- auto* arbiter = endpoint->MaybeSharedMemoryArbiter();
- return !arbiter || arbiter->TryShutdown();
+void TracingMuxerImpl::StopDataSource_AsyncBeginImpl(
+ const FindDataSourceRes& ds) {
+ TracingBackendId backend_id = ds.internal_state->backend_id;
+ uint32_t backend_connection_id = ds.internal_state->backend_connection_id;
+ DataSourceInstanceID instance_id = ds.internal_state->data_source_instance_id;
+
+ StopArgsImpl stop_args{};
+ stop_args.internal_instance_index = ds.instance_idx;
+ stop_args.async_stop_closure = [this, backend_id, backend_connection_id,
+ instance_id, ds] {
+ // TracingMuxerImpl is long lived, capturing |this| is okay.
+ // The notification closure can be moved out of the StopArgs by the
+ // embedder to handle stop asynchronously. The embedder might then
+ // call the closure on a different thread than the current one, hence
+ // this nested PostTask().
+ task_runner_->PostTask(
+ [this, backend_id, backend_connection_id, instance_id, ds] {
+ StopDataSource_AsyncEnd(backend_id, backend_connection_id,
+ instance_id, ds);
+ });
};
- for (auto it = dead_services_.begin(); it != dead_services_.end();) {
- auto next_it = it;
- next_it++;
- if (is_unused(*it)) {
- dead_services_.erase(it);
- }
- it = next_it;
- }
- return dead_services_.empty();
-}
-void TracingMuxerImpl::ProducerImpl::SendOnConnectTriggers() {
- PERFETTO_DCHECK_THREAD(thread_checker_);
- base::TimeMillis now = base::GetWallTimeMs();
- std::vector<std::string> triggers;
- while (!on_connect_triggers_.empty()) {
- // Skip if we passed TTL.
- if (on_connect_triggers_.front().second > now) {
- triggers.push_back(std::move(on_connect_triggers_.front().first));
- }
- on_connect_triggers_.pop_front();
- }
- if (!triggers.empty()) {
- service_->ActivateTriggers(triggers);
+ {
+ std::unique_lock<std::recursive_mutex> lock(ds.internal_state->lock);
+
+ // Don't call OnStop again if the datasource is already stopping.
+ if (ds.internal_state->async_stop_in_progress)
+ return;
+ ds.internal_state->async_stop_in_progress = true;
+
+ if (ds.internal_state->interceptor)
+ ds.internal_state->interceptor->OnStop({});
+
+ if (!ds.requires_callbacks_under_lock)
+ lock.unlock();
+ ds.internal_state->data_source->OnStop(stop_args);
}
+
+ // If the embedder hasn't called StopArgs.HandleStopAsynchronously() run the
+ // async closure here. In theory we could avoid the PostTask and call
+ // straight into CompleteDataSourceAsyncStop(). We keep that to reduce
+ // divergencies between the deferred-stop vs non-deferred-stop code paths.
+ if (stop_args.async_stop_closure)
+ std::move(stop_args.async_stop_closure)();
}
-void TracingMuxerImpl::ProducerImpl::NotifyFlushForDataSourceDone(
- DataSourceInstanceID ds_id,
- FlushRequestID flush_id) {
- if (!connected_) {
+void TracingMuxerImpl::StopDataSource_AsyncEnd(TracingBackendId backend_id,
+ uint32_t backend_connection_id,
+ DataSourceInstanceID instance_id,
+ const FindDataSourceRes& ds) {
+ PERFETTO_DLOG("Ending async stop of data source %" PRIu64, instance_id);
+ PERFETTO_DCHECK_THREAD(thread_checker_);
+
+ // Check that the data source instance is still active and was not modified
+ // while it was being stopped.
+ if (!ds.static_state->TryGet(ds.instance_idx) ||
+ ds.internal_state->backend_id != backend_id ||
+ ds.internal_state->backend_connection_id != backend_connection_id ||
+ ds.internal_state->data_source_instance_id != instance_id) {
+ PERFETTO_ELOG(
+ "Async stop of data source %" PRIu64
+ " failed. This might be due to calling the async_stop_closure twice.",
+ instance_id);
return;
}
+ const uint32_t mask = ~(1U << ds.instance_idx);
+ ds.static_state->valid_instances.fetch_and(mask, std::memory_order_acq_rel);
+
+ bool will_notify_on_stop;
+ // Take the mutex to prevent that the data source is in the middle of
+ // a Trace() execution where it called GetDataSourceLocked() while we
+ // destroy it.
+ uint16_t startup_buffer_reservation;
+ TracingSessionGlobalID startup_session_id;
{
- auto it = pending_flushes_.find(flush_id);
- if (it == pending_flushes_.end()) {
- return;
- }
- std::set<DataSourceInstanceID>& ds_ids = it->second;
- ds_ids.erase(ds_id);
+ std::lock_guard<std::recursive_mutex> guard(ds.internal_state->lock);
+ ds.internal_state->trace_lambda_enabled.store(false,
+ std::memory_order_relaxed);
+ ds.internal_state->data_source.reset();
+ ds.internal_state->interceptor.reset();
+ ds.internal_state->config.reset();
+ ds.internal_state->async_stop_in_progress = false;
+ will_notify_on_stop = ds.internal_state->will_notify_on_stop;
+ startup_buffer_reservation =
+ ds.internal_state->startup_target_buffer_reservation.load(
+ std::memory_order_relaxed);
+ startup_session_id = ds.internal_state->startup_session_id;
}
- std::optional<DataSourceInstanceID> biggest_flush_id;
- for (auto it = pending_flushes_.begin(); it != pending_flushes_.end();) {
- if (it->second.empty()) {
- biggest_flush_id = it->first;
- it = pending_flushes_.erase(it);
- } else {
- break;
- }
- }
+ // The other fields of internal_state are deliberately *not* cleared.
+ // See races-related comments of DataSource::Trace().
- if (biggest_flush_id) {
- service_->NotifyFlushComplete(*biggest_flush_id);
- }
-}
+ TracingMuxer::generation_++;
-// ----- End of TracingMuxerImpl::ProducerImpl methods.
+ // |producer_backends_| is append-only, Backend instances are always valid.
+ PERFETTO_CHECK(backend_id < producer_backends_.size());
+ RegisteredProducerBackend& backend = *FindProducerBackendById(backend_id);
+ ProducerImpl* producer = backend.producer.get();
+ if (!producer)
+ return;
-// ----- Begin of TracingMuxerImpl::ConsumerImpl
-TracingMuxerImpl::ConsumerImpl::ConsumerImpl(TracingMuxerImpl* muxer,
- BackendType backend_type,
- TracingSessionGlobalID session_id)
- : muxer_(muxer), backend_type_(backend_type), session_id_(session_id) {}
+ // If the data source instance still has a startup buffer reservation, it was
+ // only active for startup tracing and never started by the service. Discard
+ // the startup buffer reservation.
+ if (startup_buffer_reservation) {
+ PERFETTO_DCHECK(startup_session_id);
-TracingMuxerImpl::ConsumerImpl::~ConsumerImpl() {
- muxer_ = nullptr;
-}
+ if (producer->service_ && producer->service_->MaybeSharedMemoryArbiter()) {
+ producer->service_->MaybeSharedMemoryArbiter()
+ ->AbortStartupTracingForReservation(startup_buffer_reservation);
+ }
-void TracingMuxerImpl::ConsumerImpl::Initialize(
- std::unique_ptr<ConsumerEndpoint> endpoint) {
- PERFETTO_DCHECK_THREAD(thread_checker_);
- service_ = std::move(endpoint);
- // Don't try to use the service here since it may not have connected yet. See
- // OnConnect().
-}
+ auto session_it = std::find_if(
+ backend.startup_sessions.begin(), backend.startup_sessions.end(),
+ [startup_session_id](const RegisteredStartupSession& session) {
+ return session.session_id == startup_session_id;
+ });
-void TracingMuxerImpl::ConsumerImpl::OnConnect() {
- PERFETTO_DCHECK_THREAD(thread_checker_);
- PERFETTO_DCHECK(!connected_);
- connected_ = true;
+ // Session should not be removed until abortion of all data source instances
+ // is complete.
+ PERFETTO_DCHECK(session_it != backend.startup_sessions.end());
- // Observe data source instance events so we get notified when tracing starts.
- service_->ObserveEvents(ObservableEvents::TYPE_DATA_SOURCES_INSTANCES |
- ObservableEvents::TYPE_ALL_DATA_SOURCES_STARTED);
+ session_it->num_aborting_data_sources--;
+ if (session_it->num_aborting_data_sources == 0) {
+ if (session_it->on_aborted)
+ task_runner_->PostTask(session_it->on_aborted);
- // If the API client configured and started tracing before we connected,
- // tell the backend about it now.
- if (trace_config_)
- muxer_->SetupTracingSession(session_id_, trace_config_);
- if (start_pending_)
- muxer_->StartTracingSession(session_id_);
- if (get_trace_stats_pending_) {
- auto callback = std::move(get_trace_stats_callback_);
- get_trace_stats_callback_ = nullptr;
- muxer_->GetTraceStats(session_id_, std::move(callback));
- }
- if (query_service_state_callback_) {
- auto callback = std::move(query_service_state_callback_);
- query_service_state_callback_ = nullptr;
- muxer_->QueryServiceState(session_id_, std::move(callback));
- }
- if (session_to_clone_) {
- service_->CloneSession(std::move(*session_to_clone_));
- session_to_clone_ = std::nullopt;
+ backend.startup_sessions.erase(session_it);
+ }
}
- if (stop_pending_)
- muxer_->StopTracingSession(session_id_);
+ if (producer->connected_ &&
+ backend.producer->connection_id_.load(std::memory_order_relaxed) ==
+ backend_connection_id) {
+ // Flush any commits that might have been batched by SharedMemoryArbiter.
+ producer->service_->MaybeSharedMemoryArbiter()
+ ->FlushPendingCommitDataRequests();
+ if (instance_id && will_notify_on_stop)
+ producer->service_->NotifyDataSourceStopped(instance_id);
+ }
+ producer->SweepDeadServices();
+ base::MaybeReleaseAllocatorMemToOS();
}
-void TracingMuxerImpl::ConsumerImpl::OnDisconnect() {
+void TracingMuxerImpl::ClearDataSourceIncrementalState(
+ TracingBackendId backend_id,
+ DataSourceInstanceID instance_id) {
PERFETTO_DCHECK_THREAD(thread_checker_);
- // If we're being destroyed, bail out.
- if (!muxer_)
+ PERFETTO_DLOG("Clearing incremental state for data source %" PRIu64,
+ instance_id);
+ auto ds = FindDataSource(backend_id, instance_id);
+ if (!ds) {
+ PERFETTO_ELOG("Could not find data source to clear incremental state for");
return;
-#if PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID)
- if (!connected_ && backend_type_ == kSystemBackend) {
- PERFETTO_ELOG(
- "Unable to connect to the system tracing service as a consumer. On "
- "Android, use the \"perfetto\" command line tool instead to start "
- "system-wide tracing sessions");
}
-#endif // PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID)
-
- // Notify the client about disconnection.
- NotifyError(TracingError{TracingError::kDisconnected, "Peer disconnected"});
-
- // Make sure the client doesn't hang in a blocking start/stop because of the
- // disconnection.
- NotifyStartComplete();
- NotifyStopComplete();
- // It shouldn't be necessary to call StopTracingSession. If we get this call
- // it means that the service did shutdown before us, so there is no point
- // trying it to ask it to stop the session. We should just remember to cleanup
- // the consumer vector.
- connected_ = false;
+ DataSourceBase::ClearIncrementalStateArgs clear_incremental_state_args;
+ clear_incremental_state_args.internal_instance_index = ds.instance_idx;
+ {
+ std::unique_lock<std::recursive_mutex> lock;
+ if (ds.requires_callbacks_under_lock)
+ lock = std::unique_lock<std::recursive_mutex>(ds.internal_state->lock);
+ ds.internal_state->data_source->WillClearIncrementalState(
+ clear_incremental_state_args);
+ }
- // Notify the muxer that it is safe to destroy |this|. This is needed because
- // the ConsumerEndpoint stored in |service_| requires that |this| be safe to
- // access until OnDisconnect() is called.
- muxer_->OnConsumerDisconnected(this);
+ // Make DataSource::TraceContext::GetIncrementalState() eventually notice that
+ // the incremental state should be cleared.
+ ds.static_state->GetUnsafe(ds.instance_idx)
+ ->incremental_state_generation.fetch_add(1, std::memory_order_relaxed);
}
-void TracingMuxerImpl::ConsumerImpl::Disconnect() {
- // This is weird and deserves a comment.
- //
- // When we called the ConnectConsumer method on the service it returns
- // us a ConsumerEndpoint which we stored in |service_|, however this
- // ConsumerEndpoint holds a pointer to the ConsumerImpl pointed to by
- // |this|. Part of the API contract to TracingService::ConnectConsumer is that
- // the ConsumerImpl pointer has to be valid until the
- // ConsumerImpl::OnDisconnect method is called. Therefore we reset the
- // ConsumerEndpoint |service_|. Eventually this will call
- // ConsumerImpl::OnDisconnect and we will inform the muxer it is safe to
- // call the destructor of |this|.
- service_.reset();
-}
+bool TracingMuxerImpl::FlushDataSource_AsyncBegin(
+ TracingBackendId backend_id,
+ DataSourceInstanceID instance_id,
+ FlushRequestID flush_id,
+ FlushFlags flush_flags) {
+ PERFETTO_DLOG("Flushing data source %" PRIu64, instance_id);
+ auto ds = FindDataSource(backend_id, instance_id);
+ if (!ds) {
+ PERFETTO_ELOG("Could not find data source to flush");
+ return true;
+ }
-void TracingMuxerImpl::ConsumerImpl::OnTracingDisabled(
- const std::string& error) {
- PERFETTO_DCHECK_THREAD(thread_checker_);
- PERFETTO_DCHECK(!stopped_);
- stopped_ = true;
+ uint32_t backend_connection_id = ds.internal_state->backend_connection_id;
- if (!error.empty())
- NotifyError(TracingError{TracingError::kTracingFailed, error});
+ FlushArgsImpl flush_args;
+ flush_args.flush_flags = flush_flags;
+ flush_args.internal_instance_index = ds.instance_idx;
+ flush_args.async_flush_closure = [this, backend_id, backend_connection_id,
+ instance_id, ds, flush_id] {
+ // TracingMuxerImpl is long lived, capturing |this| is okay.
+ // The notification closure can be moved out of the StopArgs by the
+ // embedder to handle stop asynchronously. The embedder might then
+ // call the closure on a different thread than the current one, hence
+ // this nested PostTask().
+ task_runner_->PostTask(
+ [this, backend_id, backend_connection_id, instance_id, ds, flush_id] {
+ FlushDataSource_AsyncEnd(backend_id, backend_connection_id,
+ instance_id, ds, flush_id);
+ });
+ };
+ {
+ std::unique_lock<std::recursive_mutex> lock;
+ if (ds.requires_callbacks_under_lock)
+ lock = std::unique_lock<std::recursive_mutex>(ds.internal_state->lock);
+ ds.internal_state->data_source->OnFlush(flush_args);
+ }
- // If we're still waiting for the start event, fire it now. This may happen if
- // there are no active data sources in the session.
- NotifyStartComplete();
- NotifyStopComplete();
+ // |async_flush_closure| is moved out of |flush_args| if the producer
+ // requested to handle the flush asynchronously.
+ bool handled = static_cast<bool>(flush_args.async_flush_closure);
+ return handled;
}
-void TracingMuxerImpl::ConsumerImpl::NotifyStartComplete() {
+void TracingMuxerImpl::FlushDataSource_AsyncEnd(
+ TracingBackendId backend_id,
+ uint32_t backend_connection_id,
+ DataSourceInstanceID instance_id,
+ const FindDataSourceRes& ds,
+ FlushRequestID flush_id) {
+ PERFETTO_DLOG("Ending async flush of data source %" PRIu64, instance_id);
PERFETTO_DCHECK_THREAD(thread_checker_);
- if (start_complete_callback_) {
- muxer_->task_runner_->PostTask(std::move(start_complete_callback_));
- start_complete_callback_ = nullptr;
- }
- if (blocking_start_complete_callback_) {
- muxer_->task_runner_->PostTask(
- std::move(blocking_start_complete_callback_));
- blocking_start_complete_callback_ = nullptr;
- }
-}
-void TracingMuxerImpl::ConsumerImpl::NotifyError(const TracingError& error) {
- PERFETTO_DCHECK_THREAD(thread_checker_);
- if (error_callback_) {
- muxer_->task_runner_->PostTask(
- std::bind(std::move(error_callback_), error));
+ // Check that the data source instance is still active and was not modified
+ // while it was being flushed.
+ if (!ds.static_state->TryGet(ds.instance_idx) ||
+ ds.internal_state->backend_id != backend_id ||
+ ds.internal_state->backend_connection_id != backend_connection_id ||
+ ds.internal_state->data_source_instance_id != instance_id) {
+ PERFETTO_ELOG("Async flush of data source %" PRIu64
+ " failed. This might be due to the data source being stopped "
+ "in the meantime",
+ instance_id);
+ return;
}
-}
-void TracingMuxerImpl::ConsumerImpl::NotifyStopComplete() {
- PERFETTO_DCHECK_THREAD(thread_checker_);
- if (stop_complete_callback_) {
- muxer_->task_runner_->PostTask(std::move(stop_complete_callback_));
- stop_complete_callback_ = nullptr;
- }
- if (blocking_stop_complete_callback_) {
- muxer_->task_runner_->PostTask(std::move(blocking_stop_complete_callback_));
- blocking_stop_complete_callback_ = nullptr;
- }
-}
+ // |producer_backends_| is append-only, Backend instances are always valid.
+ PERFETTO_CHECK(backend_id < producer_backends_.size());
+ RegisteredProducerBackend& backend = *FindProducerBackendById(backend_id);
-void TracingMuxerImpl::ConsumerImpl::OnTraceData(
- std::vector<TracePacket> packets,
- bool has_more) {
- PERFETTO_DCHECK_THREAD(thread_checker_);
- if (!read_trace_callback_)
+ ProducerImpl* producer = backend.producer.get();
+ if (!producer)
return;
- size_t capacity = 0;
- for (const auto& packet : packets) {
- // 16 is an over-estimation of the proto preamble size
- capacity += packet.size() + 16;
- }
-
- // The shared_ptr is to avoid making a copy of the buffer when PostTask-ing.
- std::shared_ptr<std::vector<char>> buf(new std::vector<char>());
- buf->reserve(capacity);
- for (auto& packet : packets) {
- char* start;
- size_t size;
- std::tie(start, size) = packet.GetProtoPreamble();
- buf->insert(buf->end(), start, start + size);
- for (auto& slice : packet.slices()) {
- const auto* slice_data = reinterpret_cast<const char*>(slice.start);
- buf->insert(buf->end(), slice_data, slice_data + slice.size);
- }
+ // If the tracing service disconnects and reconnects while a data source is
+ // handling a flush request, there's no point is sending the flush reply to
+ // the newly reconnected producer.
+ if (producer->connected_ &&
+ backend.producer->connection_id_.load(std::memory_order_relaxed) ==
+ backend_connection_id) {
+ producer->NotifyFlushForDataSourceDone(instance_id, flush_id);
}
+}
- auto callback = read_trace_callback_;
- muxer_->task_runner_->PostTask([callback, buf, has_more] {
- TracingSession::ReadTraceCallbackArgs callback_arg{};
- callback_arg.data = buf->empty() ? nullptr : &(*buf)[0];
- callback_arg.size = buf->size();
- callback_arg.has_more = has_more;
- callback(callback_arg);
- });
+void TracingMuxerImpl::SyncProducersForTesting() {
+ std::mutex mutex;
+ std::condition_variable cv;
- if (!has_more)
- read_trace_callback_ = nullptr;
-}
+ // IPC-based producers don't report connection errors explicitly for each
+ // command, but instead with an asynchronous callback
+ // (ProducerImpl::OnDisconnected). This means that the sync command below
+ // may have completed but failed to reach the service because of a
+ // disconnection, but we can't tell until the disconnection message comes
+ // through. To guard against this, we run two whole rounds of sync round-trips
+ // before returning; the first one will detect any disconnected producers and
+ // the second one will ensure any reconnections have completed and all data
+ // sources are registered in the service again.
+ for (size_t i = 0; i < 2; i++) {
+ size_t countdown = std::numeric_limits<size_t>::max();
+ task_runner_->PostTask([this, &mutex, &cv, &countdown] {
+ {
+ std::unique_lock<std::mutex> countdown_lock(mutex);
+ countdown = producer_backends_.size();
+ }
+ for (auto& backend : producer_backends_) {
+ auto* producer = backend.producer.get();
+ producer->service_->Sync([&mutex, &cv, &countdown] {
+ std::unique_lock<std::mutex> countdown_lock(mutex);
+ countdown--;
+ cv.notify_one();
+ });
+ }
+ });
-void TracingMuxerImpl::ConsumerImpl::OnObservableEvents(
- const ObservableEvents& events) {
- if (events.instance_state_changes_size()) {
- for (const auto& state_change : events.instance_state_changes()) {
- DataSourceHandle handle{state_change.producer_name(),
- state_change.data_source_name()};
- data_source_states_[handle] =
- state_change.state() ==
- ObservableEvents::DATA_SOURCE_INSTANCE_STATE_STARTED;
+ {
+ std::unique_lock<std::mutex> countdown_lock(mutex);
+ cv.wait(countdown_lock, [&countdown] { return !countdown; });
}
}
- if (events.instance_state_changes_size() ||
- events.all_data_sources_started()) {
- // Data sources are first reported as being stopped before starting, so once
- // all the data sources we know about have started we can declare tracing
- // begun. In the case where there are no matching data sources for the
- // session, the service will report the all_data_sources_started() event
- // without adding any instances (only since Android S / Perfetto v10.0).
- if (start_complete_callback_ || blocking_start_complete_callback_) {
- bool all_data_sources_started = std::all_of(
- data_source_states_.cbegin(), data_source_states_.cend(),
- [](std::pair<DataSourceHandle, bool> state) { return state.second; });
- if (all_data_sources_started)
- NotifyStartComplete();
- }
- }
-}
+ // Check that all producers are indeed connected.
+ bool done = false;
+ bool all_producers_connected = true;
+ task_runner_->PostTask([this, &mutex, &cv, &done, &all_producers_connected] {
+ for (auto& backend : producer_backends_)
+ all_producers_connected &= backend.producer->connected_;
+ std::unique_lock<std::mutex> lock(mutex);
+ done = true;
+ cv.notify_one();
+ });
-void TracingMuxerImpl::ConsumerImpl::OnSessionCloned(
- const OnSessionClonedArgs& args) {
- if (!clone_trace_callback_)
- return;
- TracingSession::CloneTraceCallbackArgs callback_arg{};
- callback_arg.success = args.success;
- callback_arg.error = std::move(args.error);
- callback_arg.uuid_msb = args.uuid.msb();
- callback_arg.uuid_lsb = args.uuid.lsb();
- muxer_->task_runner_->PostTask(
- std::bind(std::move(clone_trace_callback_), std::move(callback_arg)));
- clone_trace_callback_ = nullptr;
+ {
+ std::unique_lock<std::mutex> lock(mutex);
+ cv.wait(lock, [&done] { return done; });
+ }
+ PERFETTO_DCHECK(all_producers_connected);
}
-void TracingMuxerImpl::ConsumerImpl::OnTraceStats(
- bool success,
- const TraceStats& trace_stats) {
- if (!get_trace_stats_callback_)
- return;
- TracingSession::GetTraceStatsCallbackArgs callback_arg{};
- callback_arg.success = success;
- callback_arg.trace_stats_data = trace_stats.SerializeAsArray();
- muxer_->task_runner_->PostTask(
- std::bind(std::move(get_trace_stats_callback_), std::move(callback_arg)));
- get_trace_stats_callback_ = nullptr;
+void TracingMuxerImpl::DestroyAllTraceWritersForCurrentThread() {
+ // Forcefully reset all trace writers on the current thread, regardless of
+ // whether their data source instances are stopped.
+ auto* root_tls = GetOrCreateTracingTLS();
+ auto destroy_all_instances = [](DataSourceThreadLocalState& tls) {
+ for (auto& ds_tls : tls.per_instance) {
+ ds_tls.Reset();
+ }
+ };
+ for (auto& tls : root_tls->data_sources_tls)
+ destroy_all_instances(tls);
+ destroy_all_instances(root_tls->track_event_tls);
+ // Unlike DestroyStoppedTraceWritersForCurrentThread(), we deliberately don't
+ // sync |root_tls->generation|: this only runs at shutdown, after which any
+ // trace point on this thread aborts in TracingMuxerFake anyway.
}
-// The callbacks below are not used.
-void TracingMuxerImpl::ConsumerImpl::OnDetach(bool) {}
-void TracingMuxerImpl::ConsumerImpl::OnAttach(bool, const TraceConfig&) {}
-// ----- End of TracingMuxerImpl::ConsumerImpl
-
-// ----- Begin of TracingMuxerImpl::TracingSessionImpl
+void TracingMuxerImpl::DestroyStoppedTraceWritersForCurrentThread() {
+ // Iterate across all possible data source types.
+ auto cur_generation = generation_.load(std::memory_order_acquire);
+ auto* root_tls = GetOrCreateTracingTLS();
-// TracingSessionImpl is the RAII object returned to API clients when they
-// invoke Tracing::CreateTracingSession. They use it for starting/stopping
-// tracing.
+ auto destroy_stopped_instances = [](DataSourceThreadLocalState& tls) {
+ // |tls| has a vector of per-data-source-instance thread-local state.
+ DataSourceStaticState* static_state = tls.static_state;
+ if (!static_state)
+ return; // Slot not used.
-TracingMuxerImpl::TracingSessionImpl::TracingSessionImpl(
- TracingMuxerImpl* muxer,
- TracingSessionGlobalID session_id,
- BackendType backend_type)
- : muxer_(muxer), session_id_(session_id), backend_type_(backend_type) {}
+ // Iterate across all possible instances for this data source.
+ for (uint32_t inst = 0; inst < kMaxDataSourceInstances; inst++) {
+ DataSourceInstanceThreadLocalState& ds_tls = tls.per_instance[inst];
+ if (!ds_tls.trace_writer)
+ continue;
-// Can be destroyed from any thread.
-TracingMuxerImpl::TracingSessionImpl::~TracingSessionImpl() {
- auto* muxer = muxer_;
- auto session_id = session_id_;
- muxer->task_runner_->PostTask(
- [muxer, session_id] { muxer->DestroyTracingSession(session_id); });
-}
+ DataSourceState* ds_state = static_state->TryGet(inst);
+ if (ds_state &&
+ ds_state->muxer_id_for_testing == ds_tls.muxer_id_for_testing &&
+ ds_state->backend_id == ds_tls.backend_id &&
+ ds_state->backend_connection_id == ds_tls.backend_connection_id &&
+ ds_state->startup_target_buffer_reservation.load(
+ std::memory_order_relaxed) ==
+ ds_tls.startup_target_buffer_reservation &&
+ ds_state->buffer_id == ds_tls.buffer_id &&
+ ds_state->data_source_instance_id == ds_tls.data_source_instance_id) {
+ continue;
+ }
-// Can be called from any thread.
-void TracingMuxerImpl::TracingSessionImpl::Setup(const TraceConfig& cfg,
- int fd) {
- auto* muxer = muxer_;
- auto session_id = session_id_;
- std::shared_ptr<TraceConfig> trace_config(new TraceConfig(cfg));
- if (fd >= 0) {
- base::ignore_result(backend_type_); // For -Wunused in the amalgamation.
-#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
- if (backend_type_ != kInProcessBackend) {
- PERFETTO_FATAL(
- "Passing a file descriptor to TracingSession::Setup() is only "
- "supported with the kInProcessBackend on Windows. Use "
- "TracingSession::ReadTrace() instead");
+ // The DataSource instance has been destroyed or recycled.
+ ds_tls.Reset(); // Will also destroy the |ds_tls.trace_writer|.
}
-#endif
- trace_config->set_write_into_file(true);
- fd = dup(fd);
+ };
+
+ for (size_t ds_idx = 0; ds_idx < kMaxDataSources; ds_idx++) {
+ // |tls| has a vector of per-data-source-instance thread-local state.
+ DataSourceThreadLocalState& tls = root_tls->data_sources_tls[ds_idx];
+ destroy_stopped_instances(tls);
}
- muxer->task_runner_->PostTask([muxer, session_id, trace_config, fd] {
- muxer->SetupTracingSession(session_id, trace_config, base::ScopedFile(fd));
- });
+ destroy_stopped_instances(root_tls->track_event_tls);
+ root_tls->generation = cur_generation;
}
-// Can be called from any thread.
-void TracingMuxerImpl::TracingSessionImpl::Start() {
- auto* muxer = muxer_;
- auto session_id = session_id_;
- muxer->task_runner_->PostTask(
- [muxer, session_id] { muxer->StartTracingSession(session_id); });
+// Called both when a new data source is registered or when a new backend
+// connects. In both cases we want to be sure we reflected the data source
+// registrations on the backends.
+void TracingMuxerImpl::UpdateDataSourcesOnAllBackends() {
+ PERFETTO_DCHECK_THREAD(thread_checker_);
+ for (RegisteredDataSource& rds : data_sources_) {
+ UpdateDataSourceOnAllBackends(rds, /*is_changed=*/false);
+ }
}
-void TracingMuxerImpl::TracingSessionImpl::CloneTrace(CloneTraceArgs args,
- CloneTraceCallback cb) {
- auto* muxer = muxer_;
- auto session_id = session_id_;
- muxer->task_runner_->PostTask([muxer, session_id, args, cb] {
- muxer->CloneTracingSession(session_id, args, std::move(cb));
- });
-}
+void TracingMuxerImpl::UpdateDataSourceOnAllBackends(RegisteredDataSource& rds,
+ bool is_changed) {
+ PERFETTO_DCHECK_THREAD(thread_checker_);
+ for (RegisteredProducerBackend& backend : producer_backends_) {
+ // We cannot call RegisterDataSource on the backend before it connects.
+ if (!backend.producer->connected_)
+ continue;
-// Can be called from any thread.
-void TracingMuxerImpl::TracingSessionImpl::ChangeTraceConfig(
- const TraceConfig& cfg) {
- auto* muxer = muxer_;
- auto session_id = session_id_;
- muxer->task_runner_->PostTask([muxer, session_id, cfg] {
- muxer->ChangeTracingSessionConfig(session_id, cfg);
- });
-}
+ PERFETTO_DCHECK(rds.static_state->index < kMaxDataSources);
+ bool is_registered = backend.producer->registered_data_sources_.test(
+ rds.static_state->index);
+ if (is_registered && !is_changed)
+ continue;
-// Can be called from any thread except the service thread.
-void TracingMuxerImpl::TracingSessionImpl::StartBlocking() {
- PERFETTO_DCHECK(!muxer_->task_runner_->RunsTasksOnCurrentThread());
- auto* muxer = muxer_;
- auto session_id = session_id_;
- base::WaitableEvent tracing_started;
- muxer->task_runner_->PostTask([muxer, session_id, &tracing_started] {
- auto* consumer = muxer->FindConsumer(session_id);
- if (!consumer) {
- // TODO(skyostil): Signal an error to the user.
- tracing_started.Notify();
- return;
+ if (!rds.descriptor.no_flush()) {
+ rds.descriptor.set_no_flush(rds.no_flush);
}
- PERFETTO_DCHECK(!consumer->blocking_start_complete_callback_);
- consumer->blocking_start_complete_callback_ = [&] {
- tracing_started.Notify();
- };
- muxer->StartTracingSession(session_id);
- });
- tracing_started.Wait();
-}
-
-// Can be called from any thread.
-void TracingMuxerImpl::TracingSessionImpl::Flush(
- std::function<void(bool)> user_callback,
- uint32_t timeout_ms) {
- auto* muxer = muxer_;
- auto session_id = session_id_;
- muxer->task_runner_->PostTask([muxer, session_id, timeout_ms, user_callback] {
- auto* consumer = muxer->FindConsumer(session_id);
- if (!consumer) {
- std::move(user_callback)(false);
- return;
+ rds.descriptor.set_will_notify_on_start(true);
+ if (!rds.descriptor.has_will_notify_on_stop()) {
+ rds.descriptor.set_will_notify_on_stop(true);
}
- muxer->FlushTracingSession(session_id, timeout_ms,
- std::move(user_callback));
- });
-}
-
-// Can be called from any thread.
-void TracingMuxerImpl::TracingSessionImpl::Stop() {
- auto* muxer = muxer_;
- auto session_id = session_id_;
- muxer->task_runner_->PostTask(
- [muxer, session_id] { muxer->StopTracingSession(session_id); });
-}
-// Can be called from any thread except the service thread.
-void TracingMuxerImpl::TracingSessionImpl::StopBlocking() {
- PERFETTO_DCHECK(!muxer_->task_runner_->RunsTasksOnCurrentThread());
- auto* muxer = muxer_;
- auto session_id = session_id_;
- base::WaitableEvent tracing_stopped;
- muxer->task_runner_->PostTask([muxer, session_id, &tracing_stopped] {
- auto* consumer = muxer->FindConsumer(session_id);
- if (!consumer) {
- // TODO(skyostil): Signal an error to the user.
- tracing_stopped.Notify();
- return;
+ rds.descriptor.set_handles_incremental_state_clear(true);
+ rds.descriptor.set_id(rds.static_state->id);
+ if (is_registered) {
+ backend.producer->service_->UpdateDataSource(rds.descriptor);
+ } else {
+ backend.producer->service_->RegisterDataSource(rds.descriptor);
}
- PERFETTO_DCHECK(!consumer->blocking_stop_complete_callback_);
- consumer->blocking_stop_complete_callback_ = [&] {
- tracing_stopped.Notify();
- };
- muxer->StopTracingSession(session_id);
- });
- tracing_stopped.Wait();
+ backend.producer->registered_data_sources_.set(rds.static_state->index);
+ }
}
-// Can be called from any thread.
-void TracingMuxerImpl::TracingSessionImpl::ReadTrace(ReadTraceCallback cb) {
- auto* muxer = muxer_;
- auto session_id = session_id_;
- muxer->task_runner_->PostTask([muxer, session_id, cb] {
- muxer->ReadTracingSessionData(session_id, std::move(cb));
- });
-}
+void TracingMuxerImpl::SetupTracingSession(
+ TracingSessionGlobalID session_id,
+ const std::shared_ptr<TraceConfig>& trace_config,
+ base::ScopedFile trace_fd) {
+ PERFETTO_DCHECK_THREAD(thread_checker_);
+ PERFETTO_CHECK(!trace_fd || trace_config->write_into_file());
-// Can be called from any thread.
-void TracingMuxerImpl::TracingSessionImpl::SetOnStartCallback(
- std::function<void()> cb) {
- auto* muxer = muxer_;
- auto session_id = session_id_;
- muxer->task_runner_->PostTask([muxer, session_id, cb] {
- auto* consumer = muxer->FindConsumer(session_id);
- if (!consumer)
- return;
- consumer->start_complete_callback_ = cb;
- });
-}
+ auto* consumer = FindConsumer(session_id);
+ if (!consumer)
+ return;
-// Can be called from any thread
-void TracingMuxerImpl::TracingSessionImpl::SetOnErrorCallback(
- std::function<void(TracingError)> cb) {
- auto* muxer = muxer_;
- auto session_id = session_id_;
- muxer->task_runner_->PostTask([muxer, session_id, cb] {
- auto* consumer = muxer->FindConsumer(session_id);
- if (!consumer) {
- // Notify the client about concurrent disconnection of the session.
- if (cb)
- cb(TracingError{TracingError::kDisconnected, "Peer disconnected"});
- return;
- }
- consumer->error_callback_ = cb;
- });
-}
+ consumer->trace_config_ = trace_config;
+ if (trace_fd)
+ consumer->trace_fd_ = std::move(trace_fd);
-// Can be called from any thread.
-void TracingMuxerImpl::TracingSessionImpl::SetOnStopCallback(
- std::function<void()> cb) {
- auto* muxer = muxer_;
- auto session_id = session_id_;
- muxer->task_runner_->PostTask([muxer, session_id, cb] {
- auto* consumer = muxer->FindConsumer(session_id);
- if (!consumer)
- return;
- consumer->stop_complete_callback_ = cb;
- });
-}
+ if (!consumer->connected_)
+ return;
-// Can be called from any thread.
-void TracingMuxerImpl::TracingSessionImpl::GetTraceStats(
- GetTraceStatsCallback cb) {
- auto* muxer = muxer_;
- auto session_id = session_id_;
- muxer->task_runner_->PostTask([muxer, session_id, cb] {
- muxer->GetTraceStats(session_id, std::move(cb));
- });
+ // Only used in the deferred start mode.
+ if (trace_config->deferred_start()) {
+ consumer->service_->EnableTracing(*trace_config,
+ std::move(consumer->trace_fd_));
+ }
}
-// Can be called from any thread.
-void TracingMuxerImpl::TracingSessionImpl::QueryServiceState(
- QueryServiceStateCallback cb) {
- auto* muxer = muxer_;
- auto session_id = session_id_;
- muxer->task_runner_->PostTask([muxer, session_id, cb] {
- muxer->QueryServiceState(session_id, std::move(cb));
- });
-}
+void TracingMuxerImpl::StartTracingSession(TracingSessionGlobalID session_id) {
+ PERFETTO_DCHECK_THREAD(thread_checker_);
-// ----- End of TracingMuxerImpl::TracingSessionImpl
+ auto* consumer = FindConsumer(session_id);
-// ----- Begin of TracingMuxerImpl::StartupTracingSessionImpl
+ if (!consumer)
+ return;
-TracingMuxerImpl::StartupTracingSessionImpl::StartupTracingSessionImpl(
- TracingMuxerImpl* muxer,
- TracingSessionGlobalID session_id,
- BackendType backend_type)
- : muxer_(muxer), session_id_(session_id), backend_type_(backend_type) {}
+ if (!consumer->trace_config_) {
+ PERFETTO_ELOG("Must call Setup(config) first");
+ return;
+ }
-// Can be destroyed from any thread.
-TracingMuxerImpl::StartupTracingSessionImpl::~StartupTracingSessionImpl() =
- default;
+ if (!consumer->connected_) {
+ consumer->start_pending_ = true;
+ return;
+ }
-void TracingMuxerImpl::StartupTracingSessionImpl::Abort() {
- auto* muxer = muxer_;
- auto session_id = session_id_;
- auto backend_type = backend_type_;
- muxer->task_runner_->PostTask([muxer, session_id, backend_type] {
- muxer->AbortStartupTracingSession(session_id, backend_type);
- });
+ consumer->start_pending_ = false;
+ if (consumer->trace_config_->deferred_start()) {
+ consumer->service_->StartTracing();
+ } else {
+ consumer->service_->EnableTracing(*consumer->trace_config_,
+ std::move(consumer->trace_fd_));
+ }
+
+ // TODO implement support for the deferred-start + fast-triggering case.
}
-// Must not be called from the SDK's internal thread.
-void TracingMuxerImpl::StartupTracingSessionImpl::AbortBlocking() {
- auto* muxer = muxer_;
- auto session_id = session_id_;
- auto backend_type = backend_type_;
- PERFETTO_CHECK(!muxer->task_runner_->RunsTasksOnCurrentThread());
- base::WaitableEvent event;
- muxer->task_runner_->PostTask([muxer, session_id, backend_type, &event] {
- muxer->AbortStartupTracingSession(session_id, backend_type);
- event.Notify();
- });
- event.Wait();
+void TracingMuxerImpl::CloneTracingSession(
+ TracingSessionGlobalID session_id,
+ TracingSession::CloneTraceArgs args,
+ TracingSession::CloneTraceCallback callback) {
+ PERFETTO_DCHECK_THREAD(thread_checker_);
+ auto* consumer = FindConsumer(session_id);
+ if (!consumer) {
+ TracingSession::CloneTraceCallbackArgs callback_arg{};
+ callback_arg.success = false;
+ callback_arg.error = "Tracing session not found";
+ callback(callback_arg);
+ return;
+ }
+ // Multiple concurrent cloning isn't supported.
+ PERFETTO_DCHECK(!consumer->clone_trace_callback_);
+ consumer->clone_trace_callback_ = std::move(callback);
+ ConsumerEndpoint::CloneSessionArgs consumer_args;
+ consumer_args.unique_session_name = args.unique_session_name;
+ if (!consumer->connected_) {
+ consumer->session_to_clone_ = std::move(consumer_args);
+ return;
+ }
+ consumer->session_to_clone_ = std::nullopt;
+ consumer->service_->CloneSession(std::move(consumer_args));
}
-// ----- End of TracingMuxerImpl::StartupTracingSessionImpl
+void TracingMuxerImpl::ChangeTracingSessionConfig(
+ TracingSessionGlobalID session_id,
+ const TraceConfig& trace_config) {
+ PERFETTO_DCHECK_THREAD(thread_checker_);
-// static
-TracingMuxer* TracingMuxer::instance_ = TracingMuxerFake::Get();
+ auto* consumer = FindConsumer(session_id);
-// This is called by perfetto::Tracing::Initialize().
-// Can be called on any thread. Typically, but not necessarily, that will be
-// the embedder's main thread.
-TracingMuxerImpl::TracingMuxerImpl(const TracingInitArgs& args)
- : TracingMuxer(args.platform ? args.platform
- : Platform::GetDefaultPlatform()) {
- PERFETTO_DETACH_FROM_THREAD(thread_checker_);
- instance_ = this;
+ if (!consumer)
+ return;
- // Create the thread where muxer, producers and service will live.
- Platform::CreateTaskRunnerArgs tr_args{/*name_for_debugging=*/"TracingMuxer"};
- task_runner_.reset(new NonReentrantTaskRunner(
- this, platform_->CreateTaskRunner(std::move(tr_args))));
+ if (!consumer->trace_config_) {
+ // Changing the config is only supported for started sessions.
+ PERFETTO_ELOG("Must call Setup(config) and Start() first");
+ return;
+ }
- // Run the initializer on that thread.
- task_runner_->PostTask([this, args] {
- Initialize(args);
- AddBackends(args);
- });
+ consumer->trace_config_ = std::make_shared<TraceConfig>(trace_config);
+ if (consumer->connected_)
+ consumer->service_->ChangeTraceConfig(trace_config);
}
-void TracingMuxerImpl::Initialize(const TracingInitArgs& args) {
- PERFETTO_DCHECK_THREAD(thread_checker_); // Rebind the thread checker.
-
- policy_ = args.tracing_policy;
- supports_multiple_data_source_instances_ =
- args.supports_multiple_data_source_instances;
+void TracingMuxerImpl::FlushTracingSession(TracingSessionGlobalID session_id,
+ uint32_t timeout_ms,
+ std::function<void(bool)> callback) {
+ PERFETTO_DCHECK_THREAD(thread_checker_);
+ auto* consumer = FindConsumer(session_id);
+ if (!consumer || consumer->start_pending_ || consumer->stop_pending_ ||
+ !consumer->trace_config_) {
+ PERFETTO_ELOG("Flush() can be called only after Start() and before Stop()");
+ std::move(callback)(false);
+ return;
+ }
- // Fallback backend for producer creation for an unsupported backend type.
- PERFETTO_CHECK(producer_backends_.empty());
- AddProducerBackend(internal::TracingBackendFake::GetInstance(),
- BackendType::kUnspecifiedBackend, args);
- // Fallback backend for consumer creation for an unsupported backend type.
- // This backend simply fails any attempt to start a tracing session.
- PERFETTO_CHECK(consumer_backends_.empty());
- AddConsumerBackend(internal::TracingBackendFake::GetInstance(),
- BackendType::kUnspecifiedBackend);
+ // For now we don't want to expose the flush reason to the consumer-side SDK
+ // users to avoid misuses until there is a strong need.
+ consumer->service_->Flush(timeout_ms, std::move(callback),
+ FlushFlags(FlushFlags::Initiator::kConsumerSdk,
+ FlushFlags::Reason::kExplicit));
}
-void TracingMuxerImpl::AddConsumerBackend(TracingConsumerBackend* backend,
- BackendType type) {
- if (!backend) {
- // We skip the log in release builds because the *_backend_fake.cc code
- // has already an ELOG before returning a nullptr.
- PERFETTO_DLOG("Consumer backend creation failed, type %d",
- static_cast<int>(type));
+void TracingMuxerImpl::StopTracingSession(TracingSessionGlobalID session_id) {
+ PERFETTO_DCHECK_THREAD(thread_checker_);
+ auto* consumer = FindConsumer(session_id);
+ if (!consumer)
+ return;
+
+ if (consumer->start_pending_) {
+ // If the session hasn't started yet, wait until it does before stopping.
+ consumer->stop_pending_ = true;
return;
}
- // Keep the backends sorted by type.
- auto it =
- std::upper_bound(consumer_backends_.begin(), consumer_backends_.end(),
- type, CompareBackendByType<RegisteredConsumerBackend>());
- it = consumer_backends_.emplace(it);
- RegisteredConsumerBackend& rb = *it;
- rb.backend = backend;
- rb.type = type;
+ consumer->stop_pending_ = false;
+ if (consumer->stopped_) {
+ // If the session was already stopped (e.g., it failed to start), don't try
+ // stopping again.
+ consumer->NotifyStopComplete();
+ } else if (!consumer->trace_config_) {
+ PERFETTO_ELOG("Must call Setup(config) and Start() first");
+ return;
+ } else {
+ consumer->service_->DisableTracing();
+ }
+
+ consumer->trace_config_.reset();
}
-void TracingMuxerImpl::AddProducerBackend(TracingProducerBackend* backend,
- BackendType type,
- const TracingInitArgs& args) {
- if (!backend) {
- // We skip the log in release builds because the *_backend_fake.cc code
- // has already an ELOG before returning a nullptr.
- PERFETTO_DLOG("Producer backend creation failed, type %d",
- static_cast<int>(type));
+void TracingMuxerImpl::DestroyTracingSession(
+ TracingSessionGlobalID session_id) {
+ PERFETTO_DCHECK_THREAD(thread_checker_);
+ for (RegisteredConsumerBackend& backend : consumer_backends_) {
+ // We need to find the consumer (if any) and call Disconnect as we destroy
+ // the tracing session. We can't call Disconnect() inside this for loop
+ // because in the in-process case this will end up to a synchronous call to
+ // OnConsumerDisconnect which will invalidate all the iterators to
+ // |backend.consumers|.
+ ConsumerImpl* consumer = nullptr;
+ for (auto& con : backend.consumers) {
+ if (con->session_id_ == session_id) {
+ consumer = con.get();
+ break;
+ }
+ }
+ if (consumer) {
+ // We broke out of the loop above on the assumption that each backend will
+ // only have a single consumer per session. This DCHECK ensures that
+ // this is the case.
+ PERFETTO_DCHECK(
+ std::count_if(backend.consumers.begin(), backend.consumers.end(),
+ [session_id](const std::unique_ptr<ConsumerImpl>& con) {
+ return con->session_id_ == session_id;
+ }) == 1u);
+ consumer->Disconnect();
+ }
+ }
+}
+
+void TracingMuxerImpl::ReadTracingSessionData(
+ TracingSessionGlobalID session_id,
+ std::function<void(TracingSession::ReadTraceCallbackArgs)> callback) {
+ PERFETTO_DCHECK_THREAD(thread_checker_);
+ auto* consumer = FindConsumer(session_id);
+ if (!consumer) {
+ // TODO(skyostil): Signal an error to the user.
+ TracingSession::ReadTraceCallbackArgs callback_arg{};
+ callback(callback_arg);
return;
}
- TracingBackendId backend_id = producer_backends_.size();
- // Keep the backends sorted by type.
- auto it =
- std::upper_bound(producer_backends_.begin(), producer_backends_.end(),
- type, CompareBackendByType<RegisteredProducerBackend>());
- it = producer_backends_.emplace(it);
+ PERFETTO_DCHECK(!consumer->read_trace_callback_);
+ consumer->read_trace_callback_ = std::move(callback);
+ consumer->service_->ReadBuffers();
+}
- RegisteredProducerBackend& rb = *it;
- rb.backend = backend;
- rb.id = backend_id;
- rb.type = type;
- rb.producer.reset(new ProducerImpl(this, backend_id,
- args.shmem_batch_commits_duration_ms,
- args.shmem_direct_patching_enabled));
- rb.producer_conn_args.producer = rb.producer.get();
- rb.producer_conn_args.producer_name = platform_->GetCurrentProcessName();
- rb.producer_conn_args.task_runner = task_runner_.get();
- rb.producer_conn_args.shmem_size_hint_bytes = args.shmem_size_hint_kb * 1024;
- rb.producer_conn_args.shmem_page_size_hint_bytes =
- args.shmem_page_size_hint_kb * 1024;
- rb.producer_conn_args.create_socket_async = args.create_socket_async;
- rb.producer_conn_args.machine_id = args.machine_id;
- rb.producer->Initialize(rb.backend->ConnectProducer(rb.producer_conn_args));
+void TracingMuxerImpl::GetTraceStats(
+ TracingSessionGlobalID session_id,
+ TracingSession::GetTraceStatsCallback callback) {
+ PERFETTO_DCHECK_THREAD(thread_checker_);
+ auto* consumer = FindConsumer(session_id);
+ if (!consumer) {
+ TracingSession::GetTraceStatsCallbackArgs callback_arg{};
+ callback_arg.success = false;
+ callback(std::move(callback_arg));
+ return;
+ }
+ PERFETTO_DCHECK(!consumer->get_trace_stats_callback_);
+ consumer->get_trace_stats_callback_ = std::move(callback);
+ if (!consumer->connected_) {
+ consumer->get_trace_stats_pending_ = true;
+ return;
+ }
+ consumer->get_trace_stats_pending_ = false;
+ consumer->service_->GetTraceStats();
+}
+
+void TracingMuxerImpl::QueryServiceState(
+ TracingSessionGlobalID session_id,
+ TracingSession::QueryServiceStateCallback callback) {
+ PERFETTO_DCHECK_THREAD(thread_checker_);
+ auto* consumer = FindConsumer(session_id);
+ if (!consumer) {
+ TracingSession::QueryServiceStateCallbackArgs callback_arg{};
+ callback_arg.success = false;
+ callback(std::move(callback_arg));
+ return;
+ }
+ PERFETTO_DCHECK(!consumer->query_service_state_callback_);
+ if (!consumer->connected_) {
+ consumer->query_service_state_callback_ = std::move(callback);
+ return;
+ }
+ auto callback_wrapper = [callback](bool success,
+ protos::gen::TracingServiceState state) {
+ TracingSession::QueryServiceStateCallbackArgs callback_arg{};
+ callback_arg.success = success;
+ callback_arg.service_state_data = state.SerializeAsArray();
+ callback(std::move(callback_arg));
+ };
+ consumer->service_->QueryServiceState({}, std::move(callback_wrapper));
}
-TracingMuxerImpl::RegisteredProducerBackend*
-TracingMuxerImpl::FindProducerBackendById(TracingBackendId id) {
- for (RegisteredProducerBackend& b : producer_backends_) {
- if (b.id == id) {
- return &b;
+void TracingMuxerImpl::SetBatchCommitsDurationForTesting(
+ uint32_t batch_commits_duration_ms,
+ BackendType backend_type) {
+ for (RegisteredProducerBackend& backend : producer_backends_) {
+ if (backend.producer && backend.producer->connected_ &&
+ backend.type == backend_type) {
+ backend.producer->service_->MaybeSharedMemoryArbiter()
+ ->SetBatchCommitsDuration(batch_commits_duration_ms);
}
}
- return nullptr;
}
-TracingMuxerImpl::RegisteredProducerBackend*
-TracingMuxerImpl::FindProducerBackendByType(BackendType type) {
- for (RegisteredProducerBackend& b : producer_backends_) {
- if (b.type == type) {
- return &b;
+bool TracingMuxerImpl::EnableDirectSMBPatchingForTesting(
+ BackendType backend_type) {
+ for (RegisteredProducerBackend& backend : producer_backends_) {
+ if (backend.producer && backend.producer->connected_ &&
+ backend.type == backend_type &&
+ !backend.producer->service_->MaybeSharedMemoryArbiter()
+ ->EnableDirectSMBPatching()) {
+ return false;
}
}
- return nullptr;
+ return true;
}
-TracingMuxerImpl::RegisteredConsumerBackend*
-TracingMuxerImpl::FindConsumerBackendByType(BackendType type) {
- for (RegisteredConsumerBackend& b : consumer_backends_) {
- if (b.type == type) {
- return &b;
- }
- }
- return nullptr;
+TracingMuxerImpl::ConsumerImpl* TracingMuxerImpl::FindConsumer(
+ TracingSessionGlobalID session_id) {
+ PERFETTO_DCHECK_THREAD(thread_checker_);
+ return FindConsumerAndBackend(session_id).first;
}
-void TracingMuxerImpl::AddBackends(const TracingInitArgs& args) {
- if (args.backends & kSystemBackend) {
- PERFETTO_CHECK(args.system_producer_backend_factory_);
- if (FindProducerBackendByType(kSystemBackend) == nullptr) {
- AddProducerBackend(args.system_producer_backend_factory_(),
- kSystemBackend, args);
- }
- if (args.enable_system_consumer) {
- PERFETTO_CHECK(args.system_consumer_backend_factory_);
- if (FindConsumerBackendByType(kSystemBackend) == nullptr) {
- AddConsumerBackend(args.system_consumer_backend_factory_(),
- kSystemBackend);
+std::pair<TracingMuxerImpl::ConsumerImpl*,
+ TracingMuxerImpl::RegisteredConsumerBackend*>
+TracingMuxerImpl::FindConsumerAndBackend(TracingSessionGlobalID session_id) {
+ PERFETTO_DCHECK_THREAD(thread_checker_);
+ for (RegisteredConsumerBackend& backend : consumer_backends_) {
+ for (auto& consumer : backend.consumers) {
+ if (consumer->session_id_ == session_id) {
+ return {consumer.get(), &backend};
}
}
}
+ return {nullptr, nullptr};
+}
- if (args.backends & kInProcessBackend) {
- TracingBackend* b = nullptr;
- if (FindProducerBackendByType(kInProcessBackend) == nullptr) {
- if (!b) {
- PERFETTO_CHECK(args.in_process_backend_factory_);
- b = args.in_process_backend_factory_();
- }
- AddProducerBackend(b, kInProcessBackend, args);
- }
- if (FindConsumerBackendByType(kInProcessBackend) == nullptr) {
- if (!b) {
- PERFETTO_CHECK(args.in_process_backend_factory_);
- b = args.in_process_backend_factory_();
- }
- AddConsumerBackend(b, kInProcessBackend);
- }
- }
+void TracingMuxerImpl::InitializeConsumer(TracingSessionGlobalID session_id) {
+ PERFETTO_DCHECK_THREAD(thread_checker_);
- if (args.backends & kCustomBackend) {
- PERFETTO_CHECK(args.custom_backend);
- if (FindProducerBackendByType(kCustomBackend) == nullptr) {
- AddProducerBackend(args.custom_backend, kCustomBackend, args);
- }
- if (FindConsumerBackendByType(kCustomBackend) == nullptr) {
- AddConsumerBackend(args.custom_backend, kCustomBackend);
- }
- }
+ auto res = FindConsumerAndBackend(session_id);
+ if (!res.first || !res.second)
+ return;
+ TracingMuxerImpl::ConsumerImpl* consumer = res.first;
+ RegisteredConsumerBackend& backend = *res.second;
- if (args.backends & ~(kSystemBackend | kInProcessBackend | kCustomBackend)) {
- PERFETTO_FATAL("Unsupported tracing backend type");
- }
+ TracingBackend::ConnectConsumerArgs conn_args;
+ conn_args.consumer = consumer;
+ conn_args.task_runner = task_runner_.get();
+ consumer->Initialize(backend.backend->ConnectConsumer(conn_args));
}
-// Can be called from any thread (but not concurrently).
-bool TracingMuxerImpl::RegisterDataSource(
- const DataSourceDescriptor& descriptor,
- DataSourceFactory factory,
- DataSourceParams params,
- bool no_flush,
- DataSourceStaticState* static_state) {
- // Ignore repeated registrations.
- if (static_state->index != kMaxDataSources) {
- PERFETTO_ELOG(
- "Data source \"%s\" registration ignored: this data source type is "
- "already registered. See "
- "https://perfetto.dev/docs/instrumentation/"
- "tracing-sdk#reporting-many-similar-things",
- descriptor.name().c_str());
- return true;
- }
-
- uint32_t new_index = next_data_source_index_++;
- if (new_index >= kMaxDataSources) {
- PERFETTO_DLOG(
- "RegisterDataSource failed: too many data sources already registered");
- return false;
+void TracingMuxerImpl::OnConsumerDisconnected(ConsumerImpl* consumer) {
+ PERFETTO_DCHECK_THREAD(thread_checker_);
+ for (RegisteredConsumerBackend& backend : consumer_backends_) {
+ auto pred = [consumer](const std::unique_ptr<ConsumerImpl>& con) {
+ return con.get() == consumer;
+ };
+ backend.consumers.erase(std::remove_if(backend.consumers.begin(),
+ backend.consumers.end(), pred),
+ backend.consumers.end());
}
+}
- // Initialize the static state.
- static_assert(sizeof(static_state->instances[0]) >= sizeof(DataSourceState),
- "instances[] size mismatch");
- for (size_t i = 0; i < static_state->instances.size(); i++)
- new (&static_state->instances[i]) DataSourceState{};
-
- static_state->index = new_index;
+void TracingMuxerImpl::SetMaxProducerReconnectionsForTesting(uint32_t count) {
+ max_producer_reconnections_.store(count);
+}
- // Generate a semi-unique id for this data source.
- uint64_t digest = base::FnvHasher::Combine(
- reinterpret_cast<intptr_t>(static_state), base::GetWallTimeNs().count());
- static_state->id = digest ? digest : 1;
+void TracingMuxerImpl::OnProducerDisconnected(ProducerImpl* producer) {
+ PERFETTO_DCHECK_THREAD(thread_checker_);
+ for (RegisteredProducerBackend& backend : producer_backends_) {
+ if (backend.producer.get() != producer)
+ continue;
- task_runner_->PostTask(
- [this, descriptor, factory, static_state, params, no_flush] {
- data_sources_.emplace_back();
- RegisteredDataSource& rds = data_sources_.back();
- rds.descriptor = descriptor;
- rds.factory = factory;
- rds.params = params;
- if (!supports_multiple_data_source_instances_) {
- rds.params.supports_multiple_instances = false;
+ // The tracing service is disconnected. It does not make sense to keep
+ // tracing (we wouldn't be able to commit). On reconnection, the tracing
+ // service will restart the data sources.
+ for (const auto& rds : data_sources_) {
+ DataSourceStaticState* static_state = rds.static_state;
+ for (uint32_t i = 0; i < kMaxDataSourceInstances; i++) {
+ auto* internal_state = static_state->TryGet(i);
+ if (internal_state && internal_state->backend_id == backend.id &&
+ internal_state->backend_connection_id ==
+ backend.producer->connection_id_.load(
+ std::memory_order_relaxed)) {
+ StopDataSource_AsyncBeginImpl(
+ FindDataSourceRes(static_state, internal_state, i,
+ rds.params.requires_callbacks_under_lock));
}
- rds.static_state = static_state;
- rds.no_flush = no_flush;
-
- UpdateDataSourceOnAllBackends(rds, /*is_changed=*/false);
- });
- return true;
-}
-
-// Can be called from any thread (but not concurrently).
-void TracingMuxerImpl::UpdateDataSourceDescriptor(
- const DataSourceDescriptor& descriptor,
- const DataSourceStaticState* static_state) {
- task_runner_->PostTask([this, descriptor, static_state] {
- for (auto& rds : data_sources_) {
- if (rds.static_state == static_state) {
- PERFETTO_CHECK(rds.descriptor.name() == descriptor.name());
- rds.descriptor = descriptor;
- rds.descriptor.set_id(static_state->id);
- UpdateDataSourceOnAllBackends(rds, /*is_changed=*/true);
- return;
}
}
- });
-}
-// Can be called from any thread (but not concurrently).
-void TracingMuxerImpl::RegisterInterceptor(
- const InterceptorDescriptor& descriptor,
- InterceptorFactory factory,
- InterceptorBase::TLSFactory tls_factory,
- InterceptorBase::TracePacketCallback packet_callback) {
- task_runner_->PostTask([this, descriptor, factory, tls_factory,
- packet_callback] {
- // Ignore repeated registrations.
- for (const auto& interceptor : interceptors_) {
- if (interceptor.descriptor.name() == descriptor.name()) {
- PERFETTO_DCHECK(interceptor.tls_factory == tls_factory);
- PERFETTO_DCHECK(interceptor.packet_callback == packet_callback);
- return;
- }
- }
- // Only allow certain interceptors for now.
- if (descriptor.name() != "test_interceptor" &&
- descriptor.name() != "console" && descriptor.name() != "etwexport") {
- PERFETTO_ELOG(
- "Interceptors are experimental. If you want to use them, please "
- "get in touch with the project maintainers "
- "(https://perfetto.dev/docs/contributing/"
- "getting-started#community).");
- return;
+ // Try reconnecting the disconnected producer. If the connection succeeds,
+ // all the data sources will be automatically re-registered.
+ if (producer->connection_id_.load(std::memory_order_relaxed) >
+ max_producer_reconnections_.load()) {
+ // Avoid reconnecting a failing producer too many times. Instead we just
+ // leak the producer instead of trying to avoid further complicating
+ // cross-thread trace writer creation.
+ PERFETTO_ELOG("Producer disconnected too many times; not reconnecting");
+ continue;
}
- interceptors_.emplace_back();
- RegisteredInterceptor& interceptor = interceptors_.back();
- interceptor.descriptor = descriptor;
- interceptor.factory = factory;
- interceptor.tls_factory = tls_factory;
- interceptor.packet_callback = packet_callback;
- });
+
+ backend.producer->Initialize(
+ backend.backend->ConnectProducer(backend.producer_conn_args));
+ // Don't use producer-provided SMBs for the next connection unless startup
+ // tracing requires it again.
+ backend.producer_conn_args.use_producer_provided_smb = false;
+ }
}
-void TracingMuxerImpl::ActivateTriggers(
- const std::vector<std::string>& triggers,
- uint32_t ttl_ms) {
- base::TimeMillis expire_time =
- base::GetWallTimeMs() + base::TimeMillis(ttl_ms);
- task_runner_->PostTask([this, triggers, expire_time] {
- for (RegisteredProducerBackend& backend : producer_backends_) {
- if (backend.producer->connected_) {
- backend.producer->service_->ActivateTriggers(triggers);
- } else {
- for (const std::string& trigger : triggers) {
- backend.producer->on_connect_triggers_.emplace_back(trigger,
- expire_time);
- }
- }
- }
- });
+void TracingMuxerImpl::SweepDeadBackends() {
+ PERFETTO_DCHECK_THREAD(thread_checker_);
+ for (auto it = dead_backends_.begin(); it != dead_backends_.end();) {
+ auto next_it = it;
+ next_it++;
+ if (it->producer->SweepDeadServices())
+ dead_backends_.erase(it);
+ it = next_it;
+ }
}
-// Checks if there is any matching startup tracing data source instance for a
-// new SetupDataSource call. If so, moves the data source to this tracing
-// session (and its target buffer) and returns true, otherwise returns false.
-static bool MaybeAdoptStartupTracingInDataSource(
+TracingMuxerImpl::FindDataSourceRes TracingMuxerImpl::FindDataSource(
TracingBackendId backend_id,
- uint32_t backend_connection_id,
- DataSourceInstanceID instance_id,
- const DataSourceConfig& cfg,
- const std::vector<RegisteredDataSource>& data_sources) {
- for (const auto& rds : data_sources) {
+ DataSourceInstanceID instance_id) {
+ PERFETTO_DCHECK_THREAD(thread_checker_);
+ // 0 is the sentinel id for unadopted startup data sources; never match it.
+ if (instance_id == 0)
+ return FindDataSourceRes();
+ RegisteredProducerBackend& backend = *FindProducerBackendById(backend_id);
+ for (const auto& rds : data_sources_) {
DataSourceStaticState* static_state = rds.static_state;
for (uint32_t i = 0; i < kMaxDataSourceInstances; i++) {
auto* internal_state = static_state->TryGet(i);
-
- if (internal_state &&
- internal_state->startup_target_buffer_reservation.load(
- std::memory_order_relaxed) &&
- internal_state->data_source_instance_id == 0 &&
- internal_state->backend_id == backend_id &&
- internal_state->backend_connection_id == backend_connection_id &&
- internal_state->config &&
- internal_state->data_source->CanAdoptStartupSession(
- *internal_state->config, cfg)) {
- PERFETTO_DLOG("Setting up data source %" PRIu64
- " %s by adopting it from a startup tracing session",
- instance_id, cfg.name().c_str());
-
- std::lock_guard<std::recursive_mutex> lock(internal_state->lock);
- // Set the associations. The actual takeover happens in
- // StartDataSource().
- internal_state->data_source_instance_id = instance_id;
- internal_state->buffer_id =
- static_cast<internal::BufferId>(cfg.target_buffer());
- internal_state->buffer_exhausted_policy =
- ComputeBufferExhaustedPolicy(cfg, rds.params);
- internal_state->config.reset(new DataSourceConfig(cfg));
-
- // TODO(eseckler): Should the data source config provided by the service
- // be allowed to specify additional interceptors / additional data
- // source params?
-
- return true;
+ if (internal_state && internal_state->backend_id == backend_id &&
+ internal_state->backend_connection_id ==
+ backend.producer->connection_id_.load(
+ std::memory_order_relaxed) &&
+ internal_state->data_source_instance_id == instance_id) {
+ return FindDataSourceRes(static_state, internal_state, i,
+ rds.params.requires_callbacks_under_lock);
}
}
}
- return false;
+ return FindDataSourceRes();
}
-// Called by the service of one of the backends.
-void TracingMuxerImpl::SetupDataSource(TracingBackendId backend_id,
- uint32_t backend_connection_id,
- DataSourceInstanceID instance_id,
- const DataSourceConfig& cfg) {
- PERFETTO_DLOG("Setting up data source %" PRIu64 " %s", instance_id,
- cfg.name().c_str());
- PERFETTO_DCHECK_THREAD(thread_checker_);
+// Can be called from any thread.
+std::unique_ptr<TraceWriterBase> TracingMuxerImpl::CreateTraceWriter(
+ DataSourceStaticState* static_state,
+ uint32_t data_source_instance_index,
+ DataSourceState* data_source,
+ BufferExhaustedPolicy buffer_exhausted_policy) {
+ if (PERFETTO_UNLIKELY(data_source->interceptor_id)) {
+ // If the session is being intercepted, return a heap-backed trace writer
+ // instead. This is safe because all the data given to the interceptor is
+ // either thread-local (|instance_index|), statically allocated
+ // (|static_state|) or constant after initialization (|interceptor|). Access
+ // to the interceptor instance itself through |data_source| is protected by
+ // a statically allocated lock (similarly to the data source instance).
+ auto& interceptor = interceptors_[data_source->interceptor_id - 1];
+ return std::unique_ptr<TraceWriterBase>(new InterceptorTraceWriter(
+ interceptor.tls_factory(static_state, data_source_instance_index),
+ interceptor.packet_callback, static_state, data_source_instance_index));
+ }
+ ProducerImpl* producer =
+ FindProducerBackendById(data_source->backend_id)->producer.get();
+ // Atomically load the current service endpoint. We keep the pointer as a
+ // shared pointer on the stack to guard against it from being concurrently
+ // modified on the thread by ProducerImpl::Initialize() swapping in a
+ // reconnected service on the muxer task runner thread.
+ //
+ // The endpoint may also be concurrently modified by SweepDeadServices()
+ // clearing out old disconnected services. We guard against that by
+ // SharedMemoryArbiter keeping track of any outstanding trace writers. After
+ // shutdown has started, the trace writer created below will be a null one
+ // which will drop any written data. See SharedMemoryArbiter::TryShutdown().
+ //
+ // We use an atomic pointer instead of holding a lock because
+ // CreateTraceWriter posts tasks under the hood.
+ std::shared_ptr<ProducerEndpoint> service =
+ std::atomic_load(&producer->service_);
- // First check if there is any matching startup tracing data source instance.
- if (MaybeAdoptStartupTracingInDataSource(backend_id, backend_connection_id,
- instance_id, cfg, data_sources_)) {
- return;
+ // The service may have been disconnected and reconnected concurrently after
+ // the data source was enabled, in which case we may not have an arbiter, or
+ // would be creating a TraceWriter for the wrong (a newer) connection / SMB.
+ // Instead, early-out now. A relaxed load is fine here because the atomic_load
+ // above ensures that the |service| isn't newer.
+ if (producer->connection_id_.load(std::memory_order_relaxed) !=
+ data_source->backend_connection_id) {
+ return std::unique_ptr<TraceWriter>(new NullTraceWriter());
}
- for (const auto& rds : data_sources_) {
- if (rds.descriptor.name() != cfg.name())
- continue;
- DataSourceStaticState& static_state = *rds.static_state;
+ // We just need a relaxed atomic read here: We can use the reservation ID even
+ // after the buffer was bound, we just need to be sure to read it atomically.
+ uint16_t startup_buffer_reservation =
+ data_source->startup_target_buffer_reservation.load(
+ std::memory_order_relaxed);
+ if (startup_buffer_reservation) {
+ return service->MaybeSharedMemoryArbiter()->CreateStartupTraceWriter(
+ startup_buffer_reservation);
+ }
- // If this data source is already active for this exact config, don't start
- // another instance. This happens when we have several data sources with the
- // same name, in which case the service sends one SetupDataSource event for
- // each one. Since we can't map which event maps to which data source, we
- // ensure each event only starts one data source instance.
- // TODO(skyostil): Register a unique id with each data source to the service
- // to disambiguate.
- bool active_for_config = false;
- for (uint32_t i = 0; i < kMaxDataSourceInstances; i++) {
- if (!static_state.TryGet(i))
+ return data_source->use_tracing_v2
+ ? service->CreateTraceWriterV2(data_source->buffer_id,
+ buffer_exhausted_policy)
+ : service->CreateTraceWriter(data_source->buffer_id,
+ buffer_exhausted_policy);
+}
+
+// This is called via the public API Tracing::NewTrace().
+// Can be called from any thread.
+std::unique_ptr<TracingSession> TracingMuxerImpl::CreateTracingSession(
+ BackendType requested_backend_type,
+ TracingConsumerBackend* (*system_backend_factory)()) {
+ TracingSessionGlobalID session_id = ++next_tracing_session_id_;
+
+ // |backend_type| can only specify one backend, not an OR-ed mask.
+ PERFETTO_CHECK((requested_backend_type & (requested_backend_type - 1)) == 0);
+
+ // Capturing |this| is fine because the TracingMuxer is a leaky singleton.
+ task_runner_->PostTask([this, requested_backend_type, session_id,
+ system_backend_factory] {
+ if (requested_backend_type == kSystemBackend && system_backend_factory &&
+ !FindConsumerBackendByType(kSystemBackend)) {
+ AddConsumerBackend(system_backend_factory(), kSystemBackend);
+ }
+ for (RegisteredConsumerBackend& backend : consumer_backends_) {
+ if (requested_backend_type && backend.type &&
+ backend.type != requested_backend_type) {
continue;
- auto* internal_state =
- reinterpret_cast<DataSourceState*>(&static_state.instances[i]);
- if (internal_state->backend_id == backend_id &&
- internal_state->backend_connection_id == backend_connection_id &&
- internal_state->config && *internal_state->config == cfg) {
- active_for_config = true;
- break;
}
+
+ // Create the consumer now, even if we have to ask the embedder below, so
+ // that any other tasks executing after this one can find the consumer and
+ // change its pending attributes.
+ backend.consumers.emplace_back(
+ new ConsumerImpl(this, backend.type, session_id));
+
+ // The last registered backend in |consumer_backends_| is the unsupported
+ // backend without a valid type.
+ if (!backend.type) {
+ PERFETTO_ELOG(
+ "No tracing backend ready for type=%u, consumer will disconnect",
+ requested_backend_type);
+ InitializeConsumer(session_id);
+ return;
+ }
+
+ // Check if the embedder wants to be asked for permission before
+ // connecting the consumer.
+ if (!policy_) {
+ InitializeConsumer(session_id);
+ return;
+ }
+
+ BackendType type = backend.type;
+ TracingPolicy::ShouldAllowConsumerSessionArgs args;
+ args.backend_type = backend.type;
+ args.result_callback = [this, type, session_id](bool allow) {
+ task_runner_->PostTask([this, type, session_id, allow] {
+ if (allow) {
+ InitializeConsumer(session_id);
+ return;
+ }
+
+ PERFETTO_ELOG(
+ "Consumer session for backend type type=%u forbidden, "
+ "consumer will disconnect",
+ type);
+
+ auto* consumer = FindConsumer(session_id);
+ if (!consumer)
+ return;
+
+ consumer->OnDisconnect();
+ });
+ };
+ policy_->ShouldAllowConsumerSession(args);
+ return;
}
- if (active_for_config) {
- PERFETTO_DLOG(
- "Data source %s is already active with this config, skipping",
- cfg.name().c_str());
- continue;
- }
+ PERFETTO_DFATAL("Not reached");
+ });
- SetupDataSourceImpl(rds, backend_id, backend_connection_id, instance_id,
- cfg, /*startup_session_id=*/0);
- return;
- }
+ return std::unique_ptr<TracingSession>(
+ new TracingSessionImpl(this, session_id, requested_backend_type));
}
-TracingMuxerImpl::FindDataSourceRes TracingMuxerImpl::SetupDataSourceImpl(
- const RegisteredDataSource& rds,
- TracingBackendId backend_id,
- uint32_t backend_connection_id,
- DataSourceInstanceID instance_id,
- const DataSourceConfig& cfg,
- TracingSessionGlobalID startup_session_id) {
- PERFETTO_DCHECK_THREAD(thread_checker_);
- DataSourceStaticState& static_state = *rds.static_state;
+// static
+// This is called via the public API Tracing::SetupStartupTracing().
+// Can be called from any thread.
+std::unique_ptr<StartupTracingSession>
+TracingMuxerImpl::CreateStartupTracingSession(
+ const TraceConfig& config,
+ Tracing::SetupStartupTracingOpts opts) {
+ BackendType backend_type = opts.backend;
+ // |backend_type| can only specify one backend, not an OR-ed mask.
+ PERFETTO_CHECK((backend_type & (backend_type - 1)) == 0);
+ // The in-process backend doesn't support startup tracing.
+ PERFETTO_CHECK(backend_type != BackendType::kInProcessBackend);
- // If any bit is set in `static_state.valid_instances` then at least one
- // other instance of data source is running.
- if (!rds.params.supports_multiple_instances &&
- static_state.valid_instances.load(std::memory_order_acquire) != 0) {
- PERFETTO_ELOG(
- "Failed to setup data source because some another instance of this "
- "data source is already active");
- return FindDataSourceRes();
- }
+ TracingSessionGlobalID session_id = ++next_tracing_session_id_;
- for (uint32_t i = 0; i < kMaxDataSourceInstances; i++) {
- // Find a free slot.
- if (static_state.TryGet(i))
- continue;
+ // Capturing |this| is fine because the TracingMuxer is a leaky singleton.
+ task_runner_->PostTask([this, config, opts, backend_type, session_id] {
+ for (RegisteredProducerBackend& backend : producer_backends_) {
+ if (backend_type && backend.type && backend.type != backend_type) {
+ continue;
+ }
- auto* internal_state =
- reinterpret_cast<DataSourceState*>(&static_state.instances[i]);
- std::unique_lock<std::recursive_mutex> lock(internal_state->lock);
- static_assert(
- std::is_same<decltype(internal_state->data_source_instance_id),
- DataSourceInstanceID>::value,
- "data_source_instance_id type mismatch");
- internal_state->muxer_id_for_testing = muxer_id_for_testing_;
- RegisteredProducerBackend& backend = *FindProducerBackendById(backend_id);
+ TracingBackendId backend_id = backend.id;
- if (startup_session_id) {
- uint16_t& last_reservation =
- backend.producer->last_startup_target_buffer_reservation_;
- if (last_reservation == std::numeric_limits<uint16_t>::max()) {
+ // The last registered backend in |producer_backends_| is the unsupported
+ // backend without a valid type.
+ if (!backend.type) {
PERFETTO_ELOG(
- "Startup buffer reservations exhausted, dropping data source");
- return FindDataSourceRes();
+ "No tracing backend initialized for type=%u, startup tracing "
+ "failed",
+ backend_type);
+ if (opts.on_setup)
+ opts.on_setup(Tracing::OnStartupTracingSetupCallbackArgs{
+ 0 /* num_data_sources_started */});
+ return;
}
- internal_state->startup_target_buffer_reservation.store(
- ++last_reservation, std::memory_order_relaxed);
- } else {
- internal_state->startup_target_buffer_reservation.store(
- 0, std::memory_order_relaxed);
- }
- internal_state->backend_id = backend_id;
- internal_state->backend_connection_id = backend_connection_id;
- internal_state->data_source_instance_id = instance_id;
- internal_state->buffer_id =
- static_cast<internal::BufferId>(cfg.target_buffer());
- internal_state->buffer_exhausted_policy =
- ComputeBufferExhaustedPolicy(cfg, rds.params);
- internal_state->config.reset(new DataSourceConfig(cfg));
- internal_state->startup_session_id = startup_session_id;
- internal_state->data_source = rds.factory();
- internal_state->interceptor = nullptr;
- internal_state->interceptor_id = 0;
- internal_state->will_notify_on_stop = rds.descriptor.will_notify_on_stop();
+ if (!backend.producer->service_ ||
+ !backend.producer->service_->shared_memory()) {
+ // If we unsuccessfully attempted to use a producer-provided SMB in the
+ // past, don't try again.
+ if (backend.producer->producer_provided_smb_failed_) {
+ PERFETTO_ELOG(
+ "Backend %zu doesn't seem to support producer-provided "
+ "SMBs, startup tracing failed",
+ backend_id);
+ if (opts.on_setup)
+ opts.on_setup(Tracing::OnStartupTracingSetupCallbackArgs{
+ 0 /* num_data_sources_started */});
+ return;
+ }
- if (cfg.has_interceptor_config()) {
- for (size_t j = 0; j < interceptors_.size(); j++) {
- if (cfg.interceptor_config().name() ==
- interceptors_[j].descriptor.name()) {
- PERFETTO_DLOG("Intercepting data source %" PRIu64
- " \"%s\" into \"%s\"",
- instance_id, cfg.name().c_str(),
- cfg.interceptor_config().name().c_str());
- internal_state->interceptor_id = static_cast<uint32_t>(j + 1);
- internal_state->interceptor = interceptors_[j].factory();
- internal_state->interceptor->OnSetup({cfg});
- break;
+ PERFETTO_DLOG("Reconnecting backend %zu for startup tracing",
+ backend_id);
+ backend.producer_conn_args.use_producer_provided_smb = true;
+ backend.producer->service_->Disconnect(); // Causes a reconnect.
+ PERFETTO_DCHECK(backend.producer->service_ &&
+ backend.producer->service_->MaybeSharedMemoryArbiter());
+ }
+
+ RegisteredStartupSession session;
+ session.session_id = session_id;
+ session.on_aborted = opts.on_aborted;
+ session.on_adopted = opts.on_adopted;
+
+ for (const TraceConfig::DataSource& ds_cfg : config.data_sources()) {
+ // Find all matching data sources and start one instance of each.
+ for (const auto& rds : data_sources_) {
+ if (rds.descriptor.name() != ds_cfg.config().name())
+ continue;
+
+ PERFETTO_DLOG(
+ "Setting up data source %s for startup tracing with target "
+ "buffer reservation %" PRIi32,
+ rds.descriptor.name().c_str(),
+ backend.producer->last_startup_target_buffer_reservation_ + 1);
+ auto ds = SetupDataSourceImpl(
+ rds, backend_id,
+ backend.producer->connection_id_.load(std::memory_order_relaxed),
+ /*instance_id=*/0, ds_cfg.config(),
+ /*startup_session_id=*/session_id);
+ if (ds) {
+ StartDataSourceImpl(ds);
+ session.num_unbound_data_sources++;
+ }
}
}
- if (!internal_state->interceptor_id) {
- PERFETTO_ELOG("Unknown interceptor configured for data source: %s",
- cfg.interceptor_config().name().c_str());
+
+ int num_ds = session.num_unbound_data_sources;
+ auto on_setup = opts.on_setup;
+ if (on_setup) {
+ backend.producer->OnStartupTracingSetup();
+ task_runner_->PostTask([on_setup, num_ds] {
+ on_setup(Tracing::OnStartupTracingSetupCallbackArgs{num_ds});
+ });
}
- }
- // This must be made at the end. See matching acquire-load in
- // DataSource::Trace().
- static_state.valid_instances.fetch_or(1 << i, std::memory_order_release);
+ if (num_ds > 0) {
+ backend.startup_sessions.push_back(std::move(session));
- DataSourceBase::SetupArgs setup_args;
- setup_args.config = &cfg;
- setup_args.backend_type = backend.type;
- setup_args.internal_instance_index = i;
+ if (opts.timeout_ms > 0) {
+ task_runner_->PostDelayedTask(
+ [this, session_id, backend_type] {
+ AbortStartupTracingSession(session_id, backend_type);
+ },
+ opts.timeout_ms);
+ }
+ }
+ return;
+ }
+ PERFETTO_DFATAL("Invalid startup tracing session backend");
+ });
- if (!rds.params.requires_callbacks_under_lock)
- lock.unlock();
- internal_state->data_source->OnSetup(setup_args);
+ return std::unique_ptr<StartupTracingSession>(
+ new StartupTracingSessionImpl(this, session_id, backend_type));
+}
- return FindDataSourceRes(&static_state, internal_state, i,
- rds.params.requires_callbacks_under_lock);
- }
- PERFETTO_ELOG(
- "Maximum number of data source instances exhausted. "
- "Dropping data source %" PRIu64,
- instance_id);
- return FindDataSourceRes();
+// Must not be called from the SDK's internal thread.
+std::unique_ptr<StartupTracingSession>
+TracingMuxerImpl::CreateStartupTracingSessionBlocking(
+ const TraceConfig& config,
+ Tracing::SetupStartupTracingOpts opts) {
+ auto previous_on_setup = std::move(opts.on_setup);
+ PERFETTO_CHECK(!task_runner_->RunsTasksOnCurrentThread());
+ base::WaitableEvent event;
+ // It is safe to capture by reference because once on_setup is called only
+ // once before this method returns.
+ opts.on_setup = [&](Tracing::OnStartupTracingSetupCallbackArgs args) {
+ if (previous_on_setup) {
+ previous_on_setup(std::move(args));
+ }
+ event.Notify();
+ };
+ auto session = CreateStartupTracingSession(config, std::move(opts));
+ event.Wait();
+ return session;
}
-// Called by the service of one of the backends.
-void TracingMuxerImpl::StartDataSource(TracingBackendId backend_id,
- DataSourceInstanceID instance_id) {
- PERFETTO_DLOG("Starting data source %" PRIu64, instance_id);
+void TracingMuxerImpl::AbortStartupTracingSession(
+ TracingSessionGlobalID session_id,
+ BackendType backend_type) {
PERFETTO_DCHECK_THREAD(thread_checker_);
- auto ds = FindDataSource(backend_id, instance_id);
- if (!ds) {
- PERFETTO_ELOG("Could not find data source to start");
- return;
- }
+ for (RegisteredProducerBackend& backend : producer_backends_) {
+ if (backend_type != backend.type)
+ continue;
- // Check if the data source was already started for startup tracing.
- uint16_t startup_reservation =
- ds.internal_state->startup_target_buffer_reservation.load(
- std::memory_order_relaxed);
- if (startup_reservation) {
- RegisteredProducerBackend& backend = *FindProducerBackendById(backend_id);
- TracingSessionGlobalID session_id = ds.internal_state->startup_session_id;
auto session_it = std::find_if(
backend.startup_sessions.begin(), backend.startup_sessions.end(),
[session_id](const RegisteredStartupSession& session) {
return session.session_id == session_id;
});
- PERFETTO_DCHECK(session_it != backend.startup_sessions.end());
- if (session_it->is_aborting) {
- PERFETTO_DLOG("Data source %" PRIu64
- " was already aborted for startup tracing, not starting it",
- instance_id);
+ // The startup session may have already been aborted or fully adopted.
+ if (session_it == backend.startup_sessions.end())
+ return;
+ if (session_it->is_aborting)
return;
- }
- PERFETTO_DLOG(
- "Data source %" PRIu64
- " was already started for startup tracing, binding its target buffer",
- instance_id);
+ session_it->is_aborting = true;
- backend.producer->service_->MaybeSharedMemoryArbiter()
- ->BindStartupTargetBuffer(startup_reservation,
- ds.internal_state->buffer_id);
+ // Iterate all data sources and abort them if they weren't adopted yet.
+ for (const auto& rds : data_sources_) {
+ DataSourceStaticState* static_state = rds.static_state;
+ for (uint32_t i = 0; i < kMaxDataSourceInstances; i++) {
+ auto* internal_state = static_state->TryGet(i);
+ if (internal_state &&
+ internal_state->startup_target_buffer_reservation.load(
+ std::memory_order_relaxed) &&
+ internal_state->data_source_instance_id == 0 &&
+ internal_state->startup_session_id == session_id) {
+ PERFETTO_DLOG(
+ "Aborting startup tracing for data source %s (target buffer "
+ "reservation %" PRIu16 ")",
+ rds.descriptor.name().c_str(),
+ internal_state->startup_target_buffer_reservation.load(
+ std::memory_order_relaxed));
- // The reservation ID can be used even after binding it, so there's no need
- // for any barriers here - we just need atomicity.
- ds.internal_state->startup_target_buffer_reservation.store(
- 0, std::memory_order_relaxed);
+ // Abort the instance asynchronously by stopping it. From this point
+ // onwards, the service will not be able to adopt it via
+ // StartDataSource().
+ session_it->num_aborting_data_sources++;
+ StopDataSource_AsyncBeginImpl(
+ FindDataSourceRes(static_state, internal_state, i,
+ rds.params.requires_callbacks_under_lock));
+ }
+ }
+ }
- // TODO(eseckler): Should we reset incremental state at this point, or
- // notify the data source some other way?
+ // If we did everything right, we should have aborted all still-unbound data
+ // source instances.
+ PERFETTO_DCHECK(session_it->num_unbound_data_sources ==
+ session_it->num_aborting_data_sources);
- // The session should not have been fully bound yet (or aborted).
- PERFETTO_DCHECK(session_it->num_unbound_data_sources > 0);
+ if (session_it->num_aborting_data_sources == 0) {
+ if (session_it->on_aborted)
+ task_runner_->PostTask(session_it->on_aborted);
- session_it->num_unbound_data_sources--;
- if (session_it->num_unbound_data_sources == 0) {
- if (session_it->on_adopted)
- task_runner_->PostTask(session_it->on_adopted);
backend.startup_sessions.erase(session_it);
}
return;
}
+ // We might reach here in tests because when we start a trace, we post the
+ // Task(AbortStartupTrace, delay=timeout). When we do
+ // perfetto::ResetForTesting, we sweep dead backends, and we are not able to
+ // kill those delayed tasks because TaskRunner doesn't have support for
+ // deleting scheduled future tasks and TaskRunner doesn't have any API for us
+ // to wait for the completion of all the scheduled tasks (apart from
+ // deleting the TaskRunner) and we want to avoid doing that because we need
+ // a long running TaskRunner in muxer.
+ PERFETTO_DLOG("Invalid startup tracing session backend");
+}
- StartDataSourceImpl(ds);
+void TracingMuxerImpl::InitializeInstance(const TracingInitArgs& args) {
+ if (instance_ != TracingMuxerFake::Get()) {
+ // The tracing muxer was already initialized. We might need to initialize
+ // additional backends that were not configured earlier.
+ auto* muxer = static_cast<TracingMuxerImpl*>(instance_);
+ muxer->task_runner_->PostTask([muxer, args] { muxer->AddBackends(args); });
+ return;
+ }
+ // If we previously had a TracingMuxerImpl instance which was reset,
+ // reinitialize and reuse it instead of trying to create a new one. See
+ // ResetForTesting().
+ if (g_prev_instance) {
+ auto* muxer = g_prev_instance;
+ g_prev_instance = nullptr;
+ instance_ = muxer;
+ muxer->task_runner_->PostTask([muxer, args] {
+ muxer->Initialize(args);
+ muxer->AddBackends(args);
+ });
+ } else {
+ new TracingMuxerImpl(args);
+ }
}
-void TracingMuxerImpl::StartDataSourceImpl(const FindDataSourceRes& ds) {
- PERFETTO_DCHECK_THREAD(thread_checker_);
+// static
+void TracingMuxerImpl::ResetForTesting() {
+ // Ideally we'd tear down the entire TracingMuxerImpl, but the lifetimes of
+ // various objects make that a non-starter. In particular:
+ //
+ // 1) Any thread that has entered a trace event has a TraceWriter, which holds
+ // a reference back to ProducerImpl::service_.
+ //
+ // 2) ProducerImpl::service_ has a reference back to the ProducerImpl.
+ //
+ // 3) ProducerImpl holds reference to TracingMuxerImpl::task_runner_, which in
+ // turn depends on TracingMuxerImpl itself.
+ //
+ // Because of this, it's not safe to deallocate TracingMuxerImpl until all
+ // threads have dropped their TraceWriters. Since we can't really ask the
+ // caller to guarantee this, we'll instead reset enough of the muxer's state
+ // so that it can be reinitialized later and ensure all necessary objects from
+ // the old state remain alive until all references have gone away.
+ auto* muxer = reinterpret_cast<TracingMuxerImpl*>(instance_);
- DataSourceBase::StartArgs start_args{};
- start_args.internal_instance_index = ds.instance_idx;
+ base::WaitableEvent reset_done;
+ auto do_reset = [muxer, &reset_done] {
+ muxer->DestroyStoppedTraceWritersForCurrentThread();
+ // Unregister all data sources so they don't interfere with any future
+ // tracing sessions.
+ for (RegisteredDataSource& rds : muxer->data_sources_) {
+ for (RegisteredProducerBackend& backend : muxer->producer_backends_) {
+ if (!backend.producer->service_ || !backend.producer->connected_)
+ continue;
+ backend.producer->service_->UnregisterDataSource(rds.descriptor.name());
+ }
+ }
+ for (auto& backend : muxer->consumer_backends_) {
+ // Check that no consumer session is currently active on any backend.
+ for (auto& consumer : backend.consumers)
+ PERFETTO_CHECK(!consumer->service_);
+ }
+ for (auto& backend : muxer->producer_backends_) {
+ backend.producer->muxer_ = nullptr;
+ backend.producer->DisposeConnection();
+ muxer->dead_backends_.push_back(std::move(backend));
+ }
+ muxer->consumer_backends_.clear();
+ muxer->producer_backends_.clear();
+ muxer->interceptors_.clear();
- std::unique_lock<std::recursive_mutex> lock(ds.internal_state->lock);
- if (ds.internal_state->interceptor)
- ds.internal_state->interceptor->OnStart({});
- ds.internal_state->trace_lambda_enabled.store(true,
- std::memory_order_relaxed);
- PERFETTO_DCHECK(ds.internal_state->data_source != nullptr);
+ for (auto& ds : muxer->data_sources_) {
+ ds.static_state->ResetForTesting();
+ }
- if (!ds.requires_callbacks_under_lock)
- lock.unlock();
- ds.internal_state->data_source->OnStart(start_args);
-}
+ muxer->data_sources_.clear();
+ muxer->next_data_source_index_ = 0;
-// Called by the service of one of the backends.
-void TracingMuxerImpl::StopDataSource_AsyncBegin(
- TracingBackendId backend_id,
- DataSourceInstanceID instance_id) {
- PERFETTO_DLOG("Stopping data source %" PRIu64, instance_id);
- PERFETTO_DCHECK_THREAD(thread_checker_);
+ // Free all backends without active trace writers or other inbound
+ // references. Note that even if all the backends get swept, the muxer still
+ // needs to stay around since |task_runner_| is assumed to be long-lived.
+ muxer->SweepDeadBackends();
- auto ds = FindDataSource(backend_id, instance_id);
- if (!ds) {
- PERFETTO_ELOG("Could not find data source to stop");
- return;
+ // Make sure we eventually discard any per-thread trace writers from the
+ // previous instance.
+ muxer->muxer_id_for_testing_++;
+
+ g_prev_instance = muxer;
+ instance_ = TracingMuxerFake::Get();
+
+ // Call the user provided cleanups on the muxer thread.
+ for (auto& cb : muxer->reset_callbacks_) {
+ cb();
+ }
+
+ reset_done.Notify();
+ };
+
+ // Some tests run the muxer and the test on the same thread. In these cases,
+ // we can reset synchronously.
+ if (muxer->task_runner_->RunsTasksOnCurrentThread()) {
+ do_reset();
+ } else {
+ muxer->DestroyStoppedTraceWritersForCurrentThread();
+ muxer->task_runner_->PostTask(std::move(do_reset));
+ reset_done.Wait();
+ // Call the user provided cleanups also on this thread.
+ for (auto& cb : muxer->reset_callbacks_) {
+ cb();
+ }
}
+ muxer->reset_callbacks_.clear();
+}
- StopDataSource_AsyncBeginImpl(ds);
+// static
+void TracingMuxerImpl::Shutdown() {
+ auto* muxer = reinterpret_cast<TracingMuxerImpl*>(instance_);
+
+ // Shutting down on the muxer thread would lead to a deadlock.
+ PERFETTO_CHECK(!muxer->task_runner_->RunsTasksOnCurrentThread());
+ // Destroy this thread's trace writers, including those of still-running data
+ // sources: the SMB dies with `delete muxer` below, but this thread's TLS only
+ // at platform->Shutdown() further down. Flushing then is a UAF (b/534222391).
+ muxer->DestroyAllTraceWritersForCurrentThread();
+
+ std::unique_ptr<base::TaskRunner> owned_task_runner(
+ muxer->task_runner_.get());
+ Platform* platform = muxer->platform_;
+ base::WaitableEvent shutdown_done;
+ owned_task_runner->PostTask([muxer, &shutdown_done] {
+ // Check that no consumer session is currently active on any backend.
+ // Producers will be automatically disconnected as a part of deleting the
+ // muxer below.
+ for (auto& backend : muxer->consumer_backends_) {
+ for (auto& consumer : backend.consumers) {
+ PERFETTO_CHECK(!consumer->service_);
+ }
+ }
+ // Destroy all writers before delete muxer frees the SMB; any writer left
+ // alive would UAF when the muxer thread exits (b/534222391).
+ muxer->DestroyAllTraceWritersForCurrentThread();
+ // The task runner must be deleted outside the muxer thread. This is done by
+ // `owned_task_runner` above.
+ muxer->task_runner_.release();
+ delete muxer;
+ instance_ = TracingMuxerFake::Get();
+ shutdown_done.Notify();
+ });
+ shutdown_done.Wait();
+
+ // Join the muxer thread before the platform (and its TLS key) is destroyed.
+ owned_task_runner.reset();
+
+ // On the calling thread, so the platform can free this thread's TLS object.
+ platform->Shutdown();
}
-void TracingMuxerImpl::StopDataSource_AsyncBeginImpl(
- const FindDataSourceRes& ds) {
- TracingBackendId backend_id = ds.internal_state->backend_id;
- uint32_t backend_connection_id = ds.internal_state->backend_connection_id;
- DataSourceInstanceID instance_id = ds.internal_state->data_source_instance_id;
+void TracingMuxerImpl::AppendResetForTestingCallback(std::function<void()> cb) {
+ reset_callbacks_.push_back(std::move(cb));
+}
- StopArgsImpl stop_args{};
- stop_args.internal_instance_index = ds.instance_idx;
- stop_args.async_stop_closure = [this, backend_id, backend_connection_id,
- instance_id, ds] {
- // TracingMuxerImpl is long lived, capturing |this| is okay.
- // The notification closure can be moved out of the StopArgs by the
- // embedder to handle stop asynchronously. The embedder might then
- // call the closure on a different thread than the current one, hence
- // this nested PostTask().
- task_runner_->PostTask(
- [this, backend_id, backend_connection_id, instance_id, ds] {
- StopDataSource_AsyncEnd(backend_id, backend_connection_id,
- instance_id, ds);
- });
- };
+TracingMuxer::~TracingMuxer() = default;
+
+static_assert(std::is_same<internal::BufferId, BufferID>::value,
+ "public's BufferId and tracing/core's BufferID diverged");
+
+} // namespace internal
+} // namespace perfetto
+// gen_amalgamated begin source: src/tracing/internal/track_event_internal.cc
+// gen_amalgamated begin header: include/perfetto/ext/base/no_destructor.h
+/*
+ * 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.
+ */
+
+#ifndef INCLUDE_PERFETTO_EXT_BASE_NO_DESTRUCTOR_H_
+#define INCLUDE_PERFETTO_EXT_BASE_NO_DESTRUCTOR_H_
+
+#include <new>
+#include <utility>
+
+namespace perfetto {
+namespace base {
- {
- std::unique_lock<std::recursive_mutex> lock(ds.internal_state->lock);
+// Wrapper that can hold an object of type T, without invoking the contained
+// object's destructor when being destroyed. Useful for creating statics while
+// avoiding static destructors.
+//
+// Stores the object inline, and therefore doesn't incur memory allocation and
+// pointer indirection overheads.
+//
+// Example of use:
+//
+// const std::string& GetStr() {
+// static base::NoDestructor<std::string> s("hello");
+// return s.ref();
+// }
+//
+template <typename T>
+class NoDestructor {
+ public:
+ // Forward arguments to T's constructor. Note that this doesn't cover
+ // construction from initializer lists.
+ template <typename... Args>
+ explicit NoDestructor(Args&&... args) {
+ new (storage_) T(std::forward<Args>(args)...);
+ }
- // Don't call OnStop again if the datasource is already stopping.
- if (ds.internal_state->async_stop_in_progress)
- return;
- ds.internal_state->async_stop_in_progress = true;
+ NoDestructor(const NoDestructor&) = delete;
+ NoDestructor& operator=(const NoDestructor&) = delete;
+ NoDestructor(NoDestructor&&) = delete;
+ NoDestructor& operator=(NoDestructor&&) = delete;
- if (ds.internal_state->interceptor)
- ds.internal_state->interceptor->OnStop({});
+ ~NoDestructor() = default;
- if (!ds.requires_callbacks_under_lock)
- lock.unlock();
- ds.internal_state->data_source->OnStop(stop_args);
+ /* To avoid type-punned pointer strict aliasing warnings on GCC6 and below
+ * these need to be split over two lines. If they are collapsed onto one line.
+ * return reinterpret_cast<const T*>(storage_);
+ * The error fires.
+ */
+ const T& ref() const {
+ auto* const cast = reinterpret_cast<const T*>(storage_);
+ return *cast;
+ }
+ T& ref() {
+ auto* const cast = reinterpret_cast<T*>(storage_);
+ return *cast;
}
- // If the embedder hasn't called StopArgs.HandleStopAsynchronously() run the
- // async closure here. In theory we could avoid the PostTask and call
- // straight into CompleteDataSourceAsyncStop(). We keep that to reduce
- // divergencies between the deferred-stop vs non-deferred-stop code paths.
- if (stop_args.async_stop_closure)
- std::move(stop_args.async_stop_closure)();
-}
+ private:
+ alignas(T) char storage_[sizeof(T)];
+};
-void TracingMuxerImpl::StopDataSource_AsyncEnd(TracingBackendId backend_id,
- uint32_t backend_connection_id,
- DataSourceInstanceID instance_id,
- const FindDataSourceRes& ds) {
- PERFETTO_DLOG("Ending async stop of data source %" PRIu64, instance_id);
- PERFETTO_DCHECK_THREAD(thread_checker_);
+} // namespace base
+} // namespace perfetto
- // Check that the data source instance is still active and was not modified
- // while it was being stopped.
- if (!ds.static_state->TryGet(ds.instance_idx) ||
- ds.internal_state->backend_id != backend_id ||
- ds.internal_state->backend_connection_id != backend_connection_id ||
- ds.internal_state->data_source_instance_id != instance_id) {
- PERFETTO_ELOG(
- "Async stop of data source %" PRIu64
- " failed. This might be due to calling the async_stop_closure twice.",
- instance_id);
- return;
- }
+#endif // INCLUDE_PERFETTO_EXT_BASE_NO_DESTRUCTOR_H_
+/*
+ * 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.
+ */
- const uint32_t mask = ~(1U << ds.instance_idx);
- ds.static_state->valid_instances.fetch_and(mask, std::memory_order_acq_rel);
+// gen_amalgamated expanded: #include "perfetto/tracing/internal/track_event_internal.h"
- bool will_notify_on_stop;
- // Take the mutex to prevent that the data source is in the middle of
- // a Trace() execution where it called GetDataSourceLocked() while we
- // destroy it.
- uint16_t startup_buffer_reservation;
- TracingSessionGlobalID startup_session_id;
- {
- std::lock_guard<std::recursive_mutex> guard(ds.internal_state->lock);
- ds.internal_state->trace_lambda_enabled.store(false,
- std::memory_order_relaxed);
- ds.internal_state->data_source.reset();
- ds.internal_state->interceptor.reset();
- ds.internal_state->config.reset();
- ds.internal_state->async_stop_in_progress = false;
- will_notify_on_stop = ds.internal_state->will_notify_on_stop;
- startup_buffer_reservation =
- ds.internal_state->startup_target_buffer_reservation.load(
- std::memory_order_relaxed);
- startup_session_id = ds.internal_state->startup_session_id;
- }
+// gen_amalgamated expanded: #include "perfetto/base/proc_utils.h"
+// gen_amalgamated expanded: #include "perfetto/base/time.h"
+// gen_amalgamated expanded: #include "perfetto/ext/base/no_destructor.h"
+// gen_amalgamated expanded: #include "perfetto/tracing/core/data_source_config.h"
+// gen_amalgamated expanded: #include "perfetto/tracing/data_source.h"
+// gen_amalgamated expanded: #include "perfetto/tracing/internal/track_event_interned_fields.h"
+// gen_amalgamated expanded: #include "perfetto/tracing/track_event.h"
+// gen_amalgamated expanded: #include "perfetto/tracing/track_event_category_registry.h"
+// gen_amalgamated expanded: #include "perfetto/tracing/track_event_interned_data_index.h"
+// gen_amalgamated expanded: #include "protos/perfetto/common/data_source_descriptor.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/common/track_event_descriptor.pbzero.h"
+// gen_amalgamated expanded: #include "protos/perfetto/trace/clock_snapshot.pbzero.h"
+// gen_amalgamated expanded: #include "protos/perfetto/trace/interned_data/interned_data.pbzero.h"
+// gen_amalgamated expanded: #include "protos/perfetto/trace/trace_packet_defaults.pbzero.h"
+// gen_amalgamated expanded: #include "protos/perfetto/trace/track_event/debug_annotation.pbzero.h"
+// gen_amalgamated expanded: #include "protos/perfetto/trace/track_event/track_descriptor.pbzero.h"
+#if PERFETTO_BUILDFLAG(PERFETTO_OS_APPLE)
+#include <os/signpost.h>
+#endif
- // The other fields of internal_state are deliberately *not* cleared.
- // See races-related comments of DataSource::Trace().
+using perfetto::protos::pbzero::ClockSnapshot;
- TracingMuxer::generation_++;
+namespace perfetto {
- // |producer_backends_| is append-only, Backend instances are always valid.
- PERFETTO_CHECK(backend_id < producer_backends_.size());
- RegisteredProducerBackend& backend = *FindProducerBackendById(backend_id);
- ProducerImpl* producer = backend.producer.get();
- if (!producer)
- return;
+TrackEventSessionObserver::~TrackEventSessionObserver() = default;
+void TrackEventSessionObserver::OnSetup(const DataSourceBase::SetupArgs&) {}
+void TrackEventSessionObserver::OnStart(const DataSourceBase::StartArgs&) {}
+void TrackEventSessionObserver::OnStop(const DataSourceBase::StopArgs&) {}
+void TrackEventSessionObserver::WillClearIncrementalState(
+ const DataSourceBase::ClearIncrementalStateArgs&) {}
- // If the data source instance still has a startup buffer reservation, it was
- // only active for startup tracing and never started by the service. Discard
- // the startup buffer reservation.
- if (startup_buffer_reservation) {
- PERFETTO_DCHECK(startup_session_id);
+TrackEventTlsStateUserData::~TrackEventTlsStateUserData() = default;
- if (producer->service_ && producer->service_->MaybeSharedMemoryArbiter()) {
- producer->service_->MaybeSharedMemoryArbiter()
- ->AbortStartupTracingForReservation(startup_buffer_reservation);
- }
+namespace internal {
- auto session_it = std::find_if(
- backend.startup_sessions.begin(), backend.startup_sessions.end(),
- [startup_session_id](const RegisteredStartupSession& session) {
- return session.session_id == startup_session_id;
- });
+BaseTrackEventInternedDataIndex::~BaseTrackEventInternedDataIndex() = default;
- // Session should not be removed until abortion of all data source instances
- // is complete.
- PERFETTO_DCHECK(session_it != backend.startup_sessions.end());
+namespace {
- session_it->num_aborting_data_sources--;
- if (session_it->num_aborting_data_sources == 0) {
- if (session_it->on_aborted)
- task_runner_->PostTask(session_it->on_aborted);
+static constexpr const char kSlowTag[] = "slow";
+static constexpr const char kDebugTag[] = "debug";
+static constexpr const char kFilteredEventName[] = "FILTERED";
- backend.startup_sessions.erase(session_it);
- }
+constexpr auto kClockIdIncremental =
+ TrackEventIncrementalState::kClockIdIncremental;
+
+constexpr auto kClockIdAbsolute = TrackEventIncrementalState::kClockIdAbsolute;
+
+class TrackEventSessionObserverRegistry {
+ public:
+ static TrackEventSessionObserverRegistry* GetInstance() {
+ static TrackEventSessionObserverRegistry* instance =
+ new TrackEventSessionObserverRegistry(); // leaked
+ return instance;
}
- if (producer->connected_ &&
- backend.producer->connection_id_.load(std::memory_order_relaxed) ==
- backend_connection_id) {
- // Flush any commits that might have been batched by SharedMemoryArbiter.
- producer->service_->MaybeSharedMemoryArbiter()
- ->FlushPendingCommitDataRequests();
- if (instance_id && will_notify_on_stop)
- producer->service_->NotifyDataSourceStopped(instance_id);
+ void AddObserverForRegistry(const TrackEventCategoryRegistry& registry,
+ TrackEventSessionObserver* observer) {
+ std::unique_lock<std::recursive_mutex> lock(mutex_);
+ observers_.emplace_back(®istry, observer);
}
- producer->SweepDeadServices();
- base::MaybeReleaseAllocatorMemToOS();
-}
-void TracingMuxerImpl::ClearDataSourceIncrementalState(
- TracingBackendId backend_id,
- DataSourceInstanceID instance_id) {
- PERFETTO_DCHECK_THREAD(thread_checker_);
- PERFETTO_DLOG("Clearing incremental state for data source %" PRIu64,
- instance_id);
- auto ds = FindDataSource(backend_id, instance_id);
- if (!ds) {
- PERFETTO_ELOG("Could not find data source to clear incremental state for");
- return;
+ void RemoveObserverForRegistry(const TrackEventCategoryRegistry& registry,
+ TrackEventSessionObserver* observer) {
+ std::unique_lock<std::recursive_mutex> lock(mutex_);
+ observers_.erase(std::remove(observers_.begin(), observers_.end(),
+ RegisteredObserver(®istry, observer)),
+ observers_.end());
}
- DataSourceBase::ClearIncrementalStateArgs clear_incremental_state_args;
- clear_incremental_state_args.internal_instance_index = ds.instance_idx;
- {
- std::unique_lock<std::recursive_mutex> lock;
- if (ds.requires_callbacks_under_lock)
- lock = std::unique_lock<std::recursive_mutex>(ds.internal_state->lock);
- ds.internal_state->data_source->WillClearIncrementalState(
- clear_incremental_state_args);
+ void ForEachObserverForRegistries(
+ const std::vector<const TrackEventCategoryRegistry*>& registries,
+ std::function<void(TrackEventSessionObserver*)> callback) {
+ std::unique_lock<std::recursive_mutex> lock(mutex_);
+ for (auto& registered_observer : observers_) {
+ for (const auto* registry : registries) {
+ if (registry == registered_observer.registry) {
+ callback(registered_observer.observer);
+ }
+ }
+ }
}
- // Make DataSource::TraceContext::GetIncrementalState() eventually notice that
- // the incremental state should be cleared.
- ds.static_state->GetUnsafe(ds.instance_idx)
- ->incremental_state_generation.fetch_add(1, std::memory_order_relaxed);
-}
+ private:
+ struct RegisteredObserver {
+ RegisteredObserver(const TrackEventCategoryRegistry* r,
+ TrackEventSessionObserver* o)
+ : registry(r), observer(o) {}
+ bool operator==(const RegisteredObserver& other) {
+ return registry == other.registry && observer == other.observer;
+ }
+ const TrackEventCategoryRegistry* registry;
+ TrackEventSessionObserver* observer;
+ };
-bool TracingMuxerImpl::FlushDataSource_AsyncBegin(
- TracingBackendId backend_id,
- DataSourceInstanceID instance_id,
- FlushRequestID flush_id,
- FlushFlags flush_flags) {
- PERFETTO_DLOG("Flushing data source %" PRIu64, instance_id);
- auto ds = FindDataSource(backend_id, instance_id);
- if (!ds) {
- PERFETTO_ELOG("Could not find data source to flush");
- return true;
- }
+ std::recursive_mutex mutex_;
+ std::vector<RegisteredObserver> observers_;
+};
- uint32_t backend_connection_id = ds.internal_state->backend_connection_id;
+enum class MatchType { kExact, kPattern, kWildcard };
- FlushArgsImpl flush_args;
- flush_args.flush_flags = flush_flags;
- flush_args.internal_instance_index = ds.instance_idx;
- flush_args.async_flush_closure = [this, backend_id, backend_connection_id,
- instance_id, ds, flush_id] {
- // TracingMuxerImpl is long lived, capturing |this| is okay.
- // The notification closure can be moved out of the StopArgs by the
- // embedder to handle stop asynchronously. The embedder might then
- // call the closure on a different thread than the current one, hence
- // this nested PostTask().
- task_runner_->PostTask(
- [this, backend_id, backend_connection_id, instance_id, ds, flush_id] {
- FlushDataSource_AsyncEnd(backend_id, backend_connection_id,
- instance_id, ds, flush_id);
- });
- };
- {
- std::unique_lock<std::recursive_mutex> lock;
- if (ds.requires_callbacks_under_lock)
- lock = std::unique_lock<std::recursive_mutex>(ds.internal_state->lock);
- ds.internal_state->data_source->OnFlush(flush_args);
+bool NameMatchesPattern(const std::string& pattern,
+ const std::string& name,
+ MatchType match_type) {
+ // To avoid pulling in all of std::regex, for now we only support a single "*"
+ // wildcard at the end of the pattern.
+ size_t i = pattern.find('*');
+ if (i != std::string::npos) {
+ PERFETTO_DCHECK(i == pattern.size() - 1);
+ if (i == 0) {
+ return match_type == MatchType::kWildcard;
+ }
+ if (match_type != MatchType::kPattern)
+ return false;
+ return name.substr(0, i) == pattern.substr(0, i);
}
+ return name == pattern;
+}
- // |async_flush_closure| is moved out of |flush_args| if the producer
- // requested to handle the flush asynchronously.
- bool handled = static_cast<bool>(flush_args.async_flush_closure);
- return handled;
+bool NameMatchesPatternList(const std::vector<std::string>& patterns,
+ const std::string& name,
+ MatchType match_type) {
+ for (const auto& pattern : patterns) {
+ if (NameMatchesPattern(pattern, name, match_type))
+ return true;
+ }
+ return false;
}
-void TracingMuxerImpl::FlushDataSource_AsyncEnd(
- TracingBackendId backend_id,
- uint32_t backend_connection_id,
- DataSourceInstanceID instance_id,
- const FindDataSourceRes& ds,
- FlushRequestID flush_id) {
- PERFETTO_DLOG("Ending async flush of data source %" PRIu64, instance_id);
- PERFETTO_DCHECK_THREAD(thread_checker_);
+} // namespace
- // Check that the data source instance is still active and was not modified
- // while it was being flushed.
- if (!ds.static_state->TryGet(ds.instance_idx) ||
- ds.internal_state->backend_id != backend_id ||
- ds.internal_state->backend_connection_id != backend_connection_id ||
- ds.internal_state->data_source_instance_id != instance_id) {
- PERFETTO_ELOG("Async flush of data source %" PRIu64
- " failed. This might be due to the data source being stopped "
- "in the meantime",
- instance_id);
- return;
- }
+TrackEventInternal& TrackEventInternal::GetInstance() {
+ static base::NoDestructor<TrackEventInternal> state;
+ return state.ref();
+}
- // |producer_backends_| is append-only, Backend instances are always valid.
- PERFETTO_CHECK(backend_id < producer_backends_.size());
- RegisteredProducerBackend& backend = *FindProducerBackendById(backend_id);
+// static
+const Track TrackEventInternal::kDefaultTrack{};
- ProducerImpl* producer = backend.producer.get();
- if (!producer)
- return;
+// static
+std::atomic<int> TrackEventInternal::session_count_{};
- // If the tracing service disconnects and reconnects while a data source is
- // handling a flush request, there's no point is sending the flush reply to
- // the newly reconnected producer.
- if (producer->connected_ &&
- backend.producer->connection_id_.load(std::memory_order_relaxed) ==
- backend_connection_id) {
- producer->NotifyFlushForDataSourceDone(instance_id, flush_id);
- }
+std::vector<const TrackEventCategoryRegistry*>
+TrackEventInternal::GetRegistries() {
+ std::unique_lock<std::mutex> lock(mu_);
+ return registries_;
}
-void TracingMuxerImpl::SyncProducersForTesting() {
- std::mutex mutex;
- std::condition_variable cv;
+std::vector<const TrackEventCategoryRegistry*> TrackEventInternal::AddRegistry(
+ const TrackEventCategoryRegistry* registry) {
+ std::unique_lock<std::mutex> lock(mu_);
+ registries_.push_back(registry);
+ return registries_;
+}
- // IPC-based producers don't report connection errors explicitly for each
- // command, but instead with an asynchronous callback
- // (ProducerImpl::OnDisconnected). This means that the sync command below
- // may have completed but failed to reach the service because of a
- // disconnection, but we can't tell until the disconnection message comes
- // through. To guard against this, we run two whole rounds of sync round-trips
- // before returning; the first one will detect any disconnected producers and
- // the second one will ensure any reconnections have completed and all data
- // sources are registered in the service again.
- for (size_t i = 0; i < 2; i++) {
- size_t countdown = std::numeric_limits<size_t>::max();
- task_runner_->PostTask([this, &mutex, &cv, &countdown] {
- {
- std::unique_lock<std::mutex> countdown_lock(mutex);
- countdown = producer_backends_.size();
- }
- for (auto& backend : producer_backends_) {
- auto* producer = backend.producer.get();
- producer->service_->Sync([&mutex, &cv, &countdown] {
- std::unique_lock<std::mutex> countdown_lock(mutex);
- countdown--;
- cv.notify_one();
- });
- }
- });
+void TrackEventInternal::ResetRegistriesForTesting() {
+ std::unique_lock<std::mutex> lock(mu_);
+ registries_.clear();
+}
- {
- std::unique_lock<std::mutex> countdown_lock(mutex);
- cv.wait(countdown_lock, [&countdown] { return !countdown; });
+// static
+bool TrackEventInternal::Initialize(
+ const std::vector<const TrackEventCategoryRegistry*> registries,
+ bool (*register_data_source)(const DataSourceDescriptor&)) {
+ DataSourceDescriptor dsd;
+ dsd.set_name("track_event");
+
+ protozero::HeapBuffered<protos::pbzero::TrackEventDescriptor> ted;
+ for (const auto* registry : registries) {
+ for (size_t i = 0; i < registry->category_count(); i++) {
+ auto category = registry->GetCategory(i);
+ // Don't register group categories.
+ if (category->IsGroup())
+ continue;
+ auto cat = ted->add_available_categories();
+ cat->set_name(category->name);
+ if (category->description)
+ cat->set_description(category->description);
+ for (const auto& tag : category->tags) {
+ if (tag) {
+ cat->add_tags(tag);
+ }
+ }
}
}
+ dsd.set_track_event_descriptor_raw(ted.SerializeAsString());
- // Check that all producers are indeed connected.
- bool done = false;
- bool all_producers_connected = true;
- task_runner_->PostTask([this, &mutex, &cv, &done, &all_producers_connected] {
- for (auto& backend : producer_backends_)
- all_producers_connected &= backend.producer->connected_;
- std::unique_lock<std::mutex> lock(mutex);
- done = true;
- cv.notify_one();
- });
+ return register_data_source(dsd);
+}
- {
- std::unique_lock<std::mutex> lock(mutex);
- cv.wait(lock, [&done] { return done; });
- }
- PERFETTO_DCHECK(all_producers_connected);
+// static
+bool TrackEventInternal::AddSessionObserver(
+ const TrackEventCategoryRegistry& registry,
+ TrackEventSessionObserver* observer) {
+ TrackEventSessionObserverRegistry::GetInstance()->AddObserverForRegistry(
+ registry, observer);
+ return true;
}
-void TracingMuxerImpl::DestroyStoppedTraceWritersForCurrentThread() {
- // Iterate across all possible data source types.
- auto cur_generation = generation_.load(std::memory_order_acquire);
- auto* root_tls = GetOrCreateTracingTLS();
+// static
+void TrackEventInternal::RemoveSessionObserver(
+ const TrackEventCategoryRegistry& registry,
+ TrackEventSessionObserver* observer) {
+ TrackEventSessionObserverRegistry::GetInstance()->RemoveObserverForRegistry(
+ registry, observer);
+}
- auto destroy_stopped_instances = [](DataSourceThreadLocalState& tls) {
- // |tls| has a vector of per-data-source-instance thread-local state.
- DataSourceStaticState* static_state = tls.static_state;
- if (!static_state)
- return; // Slot not used.
+#if !PERFETTO_BUILDFLAG(PERFETTO_OS_APPLE) && \
+ !PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
+static constexpr protos::pbzero::BuiltinClock kDefaultTraceClock =
+ protos::pbzero::BUILTIN_CLOCK_BOOTTIME;
+#else
+static constexpr protos::pbzero::BuiltinClock kDefaultTraceClock =
+ protos::pbzero::BUILTIN_CLOCK_MONOTONIC;
+#endif
- // Iterate across all possible instances for this data source.
- for (uint32_t inst = 0; inst < kMaxDataSourceInstances; inst++) {
- DataSourceInstanceThreadLocalState& ds_tls = tls.per_instance[inst];
- if (!ds_tls.trace_writer)
- continue;
+// static
+protos::pbzero::BuiltinClock TrackEventInternal::clock_ = kDefaultTraceClock;
- DataSourceState* ds_state = static_state->TryGet(inst);
- if (ds_state &&
- ds_state->muxer_id_for_testing == ds_tls.muxer_id_for_testing &&
- ds_state->backend_id == ds_tls.backend_id &&
- ds_state->backend_connection_id == ds_tls.backend_connection_id &&
- ds_state->startup_target_buffer_reservation.load(
- std::memory_order_relaxed) ==
- ds_tls.startup_target_buffer_reservation &&
- ds_state->buffer_id == ds_tls.buffer_id &&
- ds_state->data_source_instance_id == ds_tls.data_source_instance_id) {
- continue;
- }
+// static
+bool TrackEventInternal::disallow_merging_with_system_tracks_ = false;
+
+// static
+BufferExhaustedPolicy TrackEventInternal::buffer_exhausted_policy_ =
+ BufferExhaustedPolicy::kDrop;
- // The DataSource instance has been destroyed or recycled.
- ds_tls.Reset(); // Will also destroy the |ds_tls.trace_writer|.
+// static
+void TrackEventInternal::EnableRegistry(
+ const TrackEventCategoryRegistry* registry,
+ const protos::gen::TrackEventConfig& config,
+ uint32_t internal_instance_index) {
+ for (size_t i = 0; i < registry->category_count(); i++) {
+ if (IsCategoryEnabled(*registry, config, *registry->GetCategory(i))) {
+ PERFETTO_DLOG("EnableRegistry %" PRIu32 " %zu", internal_instance_index,
+ i);
+ registry->EnableCategoryForInstance(i, internal_instance_index);
}
- };
+ }
+}
- for (size_t ds_idx = 0; ds_idx < kMaxDataSources; ds_idx++) {
- // |tls| has a vector of per-data-source-instance thread-local state.
- DataSourceThreadLocalState& tls = root_tls->data_sources_tls[ds_idx];
- destroy_stopped_instances(tls);
+void TrackEventInternal::EnableTracing(
+ const protos::gen::TrackEventConfig& config,
+ const DataSourceBase::SetupArgs& args) {
+ std::vector<const TrackEventCategoryRegistry*> registries;
+ {
+ std::unique_lock<std::mutex> lock(mu_);
+ registries = registries_;
+ for (const auto& registry : registries) {
+ for (size_t i = 0; i < registry->category_count(); i++) {
+ if (IsCategoryEnabled(*registry, config, *registry->GetCategory(i)))
+ registry->EnableCategoryForInstance(i, args.internal_instance_index);
+ }
+ }
}
- destroy_stopped_instances(root_tls->track_event_tls);
- root_tls->generation = cur_generation;
+ TrackEventSessionObserverRegistry::GetInstance()
+ ->ForEachObserverForRegistries(
+ registries, [&](TrackEventSessionObserver* o) { o->OnSetup(args); });
}
-// Called both when a new data source is registered or when a new backend
-// connects. In both cases we want to be sure we reflected the data source
-// registrations on the backends.
-void TracingMuxerImpl::UpdateDataSourcesOnAllBackends() {
- PERFETTO_DCHECK_THREAD(thread_checker_);
- for (RegisteredDataSource& rds : data_sources_) {
- UpdateDataSourceOnAllBackends(rds, /*is_changed=*/false);
+void TrackEventInternal::DisableTracing(uint32_t internal_instance_index) {
+ std::unique_lock<std::mutex> lock(mu_);
+ for (const auto& registry : registries_) {
+ for (size_t i = 0; i < registry->category_count(); i++)
+ registry->DisableCategoryForInstance(i, internal_instance_index);
}
}
-void TracingMuxerImpl::UpdateDataSourceOnAllBackends(RegisteredDataSource& rds,
- bool is_changed) {
- PERFETTO_DCHECK_THREAD(thread_checker_);
- for (RegisteredProducerBackend& backend : producer_backends_) {
- // We cannot call RegisterDataSource on the backend before it connects.
- if (!backend.producer->connected_)
- continue;
+// static
+void TrackEventInternal::OnStart(const DataSourceBase::StartArgs& args) {
+ session_count_.fetch_add(1);
+ TrackEventSessionObserverRegistry::GetInstance()
+ ->ForEachObserverForRegistries(
+ GetInstance().GetRegistries(),
+ [&](TrackEventSessionObserver* o) { o->OnStart(args); });
+}
- PERFETTO_DCHECK(rds.static_state->index < kMaxDataSources);
- bool is_registered = backend.producer->registered_data_sources_.test(
- rds.static_state->index);
- if (is_registered && !is_changed)
- continue;
+// static
+void TrackEventInternal::OnStop(const DataSourceBase::StopArgs& args) {
+ TrackEventSessionObserverRegistry::GetInstance()
+ ->ForEachObserverForRegistries(
+ GetInstance().GetRegistries(),
+ [&](TrackEventSessionObserver* o) { o->OnStop(args); });
+}
- if (!rds.descriptor.no_flush()) {
- rds.descriptor.set_no_flush(rds.no_flush);
- }
- rds.descriptor.set_will_notify_on_start(true);
- if (!rds.descriptor.has_will_notify_on_stop()) {
- rds.descriptor.set_will_notify_on_stop(true);
- }
+// static
+void TrackEventInternal::WillClearIncrementalState(
+ const DataSourceBase::ClearIncrementalStateArgs& args) {
+ TrackEventSessionObserverRegistry::GetInstance()
+ ->ForEachObserverForRegistries(GetInstance().GetRegistries(),
+ [&](TrackEventSessionObserver* o) {
+ o->WillClearIncrementalState(args);
+ });
+}
- rds.descriptor.set_handles_incremental_state_clear(true);
- rds.descriptor.set_id(rds.static_state->id);
- if (is_registered) {
- backend.producer->service_->UpdateDataSource(rds.descriptor);
- } else {
- backend.producer->service_->RegisterDataSource(rds.descriptor);
- }
- backend.producer->registered_data_sources_.set(rds.static_state->index);
+// static
+bool TrackEventInternal::IsCategoryEnabled(
+ const TrackEventCategoryRegistry& registry,
+ const protos::gen::TrackEventConfig& config,
+ const Category& category) {
+ // If this is a group category, check if any of its constituent categories are
+ // enabled. If so, then this one is enabled too.
+ if (category.IsGroup()) {
+ bool result = false;
+ category.ForEachGroupMember([&](const char* member_name, size_t name_size) {
+ for (size_t i = 0; i < registry.category_count(); i++) {
+ const auto ref_category = registry.GetCategory(i);
+ // Groups can't refer to other groups.
+ if (ref_category->IsGroup())
+ continue;
+ // Require an exact match.
+ if (ref_category->name_size() != name_size ||
+ strncmp(ref_category->name, member_name, name_size)) {
+ continue;
+ }
+ if (IsCategoryEnabled(registry, config, *ref_category)) {
+ result = true;
+ // Break ForEachGroupMember() loop.
+ return false;
+ }
+ break;
+ }
+ // No match? Must be a dynamic category.
+ DynamicCategory dyn_category(std::string(member_name, name_size));
+ Category ref_category{Category::FromDynamicCategory(dyn_category)};
+ if (IsCategoryEnabled(registry, config, ref_category)) {
+ result = true;
+ // Break ForEachGroupMember() loop.
+ return false;
+ }
+ // No match found => keep iterating.
+ return true;
+ });
+ return result;
}
-}
-void TracingMuxerImpl::SetupTracingSession(
- TracingSessionGlobalID session_id,
- const std::shared_ptr<TraceConfig>& trace_config,
- base::ScopedFile trace_fd) {
- PERFETTO_DCHECK_THREAD(thread_checker_);
- PERFETTO_CHECK(!trace_fd || trace_config->write_into_file());
+ auto has_matching_tag = [&](std::function<bool(const char*)> matcher) {
+ for (const auto& tag : category.tags) {
+ if (!tag)
+ break;
+ if (matcher(tag))
+ return true;
+ }
+ return false;
+ };
- auto* consumer = FindConsumer(session_id);
- if (!consumer)
- return;
+ // First try exact matches, then pattern matches. Last, try the global
+ // wildcard.
+ const std::array<MatchType, 3> match_types = {
+ {MatchType::kExact, MatchType::kPattern, MatchType::kWildcard}};
+ for (auto match_type : match_types) {
+ // 1. Enabled categories.
+ if (NameMatchesPatternList(config.enabled_categories(), category.name,
+ match_type)) {
+ return true;
+ }
- consumer->trace_config_ = trace_config;
- if (trace_fd)
- consumer->trace_fd_ = std::move(trace_fd);
+ // 2. Disabled categories.
+ if (NameMatchesPatternList(config.disabled_categories(), category.name,
+ match_type)) {
+ return false;
+ }
- if (!consumer->connected_)
- return;
+ // 3. Disabled tags.
+ if (has_matching_tag([&](const char* tag) {
+ if (config.disabled_tags_size()) {
+ return NameMatchesPatternList(config.disabled_tags(), tag,
+ match_type);
+ } else if (config.enabled_tags_size() == 0) {
+ // The "slow" and "debug" tags are disabled by default.
+ return NameMatchesPattern(kSlowTag, tag, match_type) ||
+ NameMatchesPattern(kDebugTag, tag, match_type);
+ }
+ return false;
+ })) {
+ return false;
+ }
- // Only used in the deferred start mode.
- if (trace_config->deferred_start()) {
- consumer->service_->EnableTracing(*trace_config,
- std::move(consumer->trace_fd_));
+ // 4. Enabled tags.
+ if (has_matching_tag([&](const char* tag) {
+ return NameMatchesPatternList(config.enabled_tags(), tag, match_type);
+ })) {
+ return true;
+ }
}
+
+ // If nothing matched, enable the category by default.
+ return true;
}
-void TracingMuxerImpl::StartTracingSession(TracingSessionGlobalID session_id) {
- PERFETTO_DCHECK_THREAD(thread_checker_);
+// static
+uint64_t TrackEventInternal::GetTimeNs() {
+ if (GetClockId() == protos::pbzero::BUILTIN_CLOCK_BOOTTIME)
+ return static_cast<uint64_t>(perfetto::base::GetBootTimeNs().count());
+ else if (GetClockId() == protos::pbzero::BUILTIN_CLOCK_MONOTONIC)
+ return static_cast<uint64_t>(perfetto::base::GetWallTimeNs().count());
+ PERFETTO_DCHECK(GetClockId() == protos::pbzero::BUILTIN_CLOCK_MONOTONIC_RAW);
+ return static_cast<uint64_t>(perfetto::base::GetWallTimeRawNs().count());
+}
- auto* consumer = FindConsumer(session_id);
+// static
+TraceTimestamp TrackEventInternal::GetTraceTime() {
+ return {kClockIdIncremental, GetTimeNs()};
+}
- if (!consumer)
- return;
+// static
+int TrackEventInternal::GetSessionCount() {
+ return session_count_.load();
+}
- if (!consumer->trace_config_) {
- PERFETTO_ELOG("Must call Setup(config) first");
- return;
+// static
+void TrackEventInternal::ResetIncrementalState(
+ TraceWriterBase* trace_writer,
+ TrackEventIncrementalState* incr_state,
+ const TrackEventTlsState& tls_state,
+ const TraceTimestamp& timestamp) {
+ auto sequence_timestamp = timestamp;
+ if (timestamp.clock_id != kClockIdIncremental) {
+ sequence_timestamp = TrackEventInternal::GetTraceTime();
}
- if (!consumer->connected_) {
- consumer->start_pending_ = true;
- return;
- }
+ incr_state->last_timestamp_ns = sequence_timestamp.value;
+ auto default_track = ThreadTrack::Current();
+ auto ts_unit_multiplier = tls_state.timestamp_unit_multiplier;
+ auto thread_time_counter_track =
+ CounterTrack("thread_time", default_track)
+ .set_is_incremental(true)
+ .set_unit_multiplier(static_cast<int64_t>(ts_unit_multiplier))
+ .set_type(protos::gen::CounterDescriptor::COUNTER_THREAD_TIME_NS);
+ {
+ // Mark any incremental state before this point invalid. Also set up
+ // defaults so that we don't need to repeat constant data for each packet.
+ auto packet = NewTracePacket(
+ trace_writer, incr_state, tls_state, timestamp,
+ protos::pbzero::TracePacket::SEQ_INCREMENTAL_STATE_CLEARED);
+ auto defaults = packet->set_trace_packet_defaults();
+ defaults->set_timestamp_clock_id(tls_state.default_clock);
+ // Establish the default track for this event sequence.
+ auto track_defaults = defaults->set_track_event_defaults();
+ track_defaults->set_track_uuid(default_track.uuid);
+ if (tls_state.enable_thread_time_sampling) {
+ track_defaults->add_extra_counter_track_uuids(
+ thread_time_counter_track.uuid);
+ }
- consumer->start_pending_ = false;
- if (consumer->trace_config_->deferred_start()) {
- consumer->service_->StartTracing();
- } else {
- consumer->service_->EnableTracing(*consumer->trace_config_,
- std::move(consumer->trace_fd_));
- }
+#if PERFETTO_BUILDFLAG(PERFETTO_OS_APPLE)
+ // Emit a MacOS point-of-interest signpost to synchronize Mac profiler time
+ // with boot time.
+ // TODO(leszeks): Consider allowing synchronization against other clocks
+ // than boot time.
+ static os_log_t log_handle = os_log_create(
+ "dev.perfetto.clock_sync", OS_LOG_CATEGORY_POINTS_OF_INTEREST);
+ os_signpost_event_emit(
+ log_handle, OS_SIGNPOST_ID_EXCLUSIVE, "boottime", "%" PRId64,
+ static_cast<uint64_t>(perfetto::base::GetBootTimeNs().count()));
+#endif
- // TODO implement support for the deferred-start + fast-triggering case.
-}
+ if (tls_state.default_clock != static_cast<uint32_t>(GetClockId())) {
+ ClockSnapshot* clocks = packet->set_clock_snapshot();
+ // Trace clock.
+ ClockSnapshot::Clock* trace_clock = clocks->add_clocks();
+ trace_clock->set_clock_id(static_cast<uint32_t>(GetClockId()));
+ trace_clock->set_timestamp(sequence_timestamp.value);
-void TracingMuxerImpl::CloneTracingSession(
- TracingSessionGlobalID session_id,
- TracingSession::CloneTraceArgs args,
- TracingSession::CloneTraceCallback callback) {
- PERFETTO_DCHECK_THREAD(thread_checker_);
- auto* consumer = FindConsumer(session_id);
- if (!consumer) {
- TracingSession::CloneTraceCallbackArgs callback_arg{};
- callback_arg.success = false;
- callback_arg.error = "Tracing session not found";
- callback(callback_arg);
- return;
- }
- // Multiple concurrent cloning isn't supported.
- PERFETTO_DCHECK(!consumer->clone_trace_callback_);
- consumer->clone_trace_callback_ = std::move(callback);
- ConsumerEndpoint::CloneSessionArgs consumer_args;
- consumer_args.unique_session_name = args.unique_session_name;
- if (!consumer->connected_) {
- consumer->session_to_clone_ = std::move(consumer_args);
- return;
+ if (PERFETTO_LIKELY(tls_state.default_clock == kClockIdIncremental)) {
+ // Delta-encoded incremental clock in nanoseconds by default but
+ // configurable by |tls_state.timestamp_unit_multiplier|.
+ ClockSnapshot::Clock* clock_incremental = clocks->add_clocks();
+ clock_incremental->set_clock_id(kClockIdIncremental);
+ clock_incremental->set_timestamp(sequence_timestamp.value /
+ ts_unit_multiplier);
+ clock_incremental->set_is_incremental(true);
+ clock_incremental->set_unit_multiplier_ns(ts_unit_multiplier);
+ }
+ if (ts_unit_multiplier > 1) {
+ // absolute clock with custom timestamp_unit_multiplier.
+ ClockSnapshot::Clock* absolute_clock = clocks->add_clocks();
+ absolute_clock->set_clock_id(kClockIdAbsolute);
+ absolute_clock->set_timestamp(sequence_timestamp.value /
+ ts_unit_multiplier);
+ absolute_clock->set_is_incremental(false);
+ absolute_clock->set_unit_multiplier_ns(ts_unit_multiplier);
+ }
+ }
}
- consumer->session_to_clone_ = std::nullopt;
- consumer->service_->CloneSession(std::move(consumer_args));
-}
-
-void TracingMuxerImpl::ChangeTracingSessionConfig(
- TracingSessionGlobalID session_id,
- const TraceConfig& trace_config) {
- PERFETTO_DCHECK_THREAD(thread_checker_);
- auto* consumer = FindConsumer(session_id);
+ // Every thread should write a descriptor for its default track, because most
+ // trace points won't explicitly reference it. We also write the process
+ // descriptor from every thread that writes trace events to ensure it gets
+ // emitted at least once.
+ incr_state->seen_tracks.insert(default_track.uuid);
+ WriteTrackDescriptor(default_track, trace_writer, incr_state, tls_state,
+ sequence_timestamp);
- if (!consumer)
- return;
+ incr_state->seen_tracks.insert(ProcessTrack::Current().uuid);
+ WriteTrackDescriptor(ProcessTrack::Current(), trace_writer, incr_state,
+ tls_state, sequence_timestamp);
- if (!consumer->trace_config_) {
- // Changing the config is only supported for started sessions.
- PERFETTO_ELOG("Must call Setup(config) and Start() first");
- return;
+ if (tls_state.enable_thread_time_sampling) {
+ WriteTrackDescriptor(thread_time_counter_track, trace_writer, incr_state,
+ tls_state, sequence_timestamp);
}
-
- consumer->trace_config_ = std::make_shared<TraceConfig>(trace_config);
- if (consumer->connected_)
- consumer->service_->ChangeTraceConfig(trace_config);
}
-void TracingMuxerImpl::FlushTracingSession(TracingSessionGlobalID session_id,
- uint32_t timeout_ms,
- std::function<void(bool)> callback) {
- PERFETTO_DCHECK_THREAD(thread_checker_);
- auto* consumer = FindConsumer(session_id);
- if (!consumer || consumer->start_pending_ || consumer->stop_pending_ ||
- !consumer->trace_config_) {
- PERFETTO_ELOG("Flush() can be called only after Start() and before Stop()");
- std::move(callback)(false);
- return;
+// static
+protozero::MessageHandle<protos::pbzero::TracePacket>
+TrackEventInternal::NewTracePacket(TraceWriterBase* trace_writer,
+ TrackEventIncrementalState* incr_state,
+ const TrackEventTlsState& tls_state,
+ TraceTimestamp timestamp,
+ uint32_t seq_flags) {
+ if (PERFETTO_UNLIKELY(tls_state.default_clock != kClockIdIncremental &&
+ timestamp.clock_id == kClockIdIncremental)) {
+ timestamp.clock_id = tls_state.default_clock;
}
-
- // For now we don't want to expose the flush reason to the consumer-side SDK
- // users to avoid misuses until there is a strong need.
- consumer->service_->Flush(timeout_ms, std::move(callback),
- FlushFlags(FlushFlags::Initiator::kConsumerSdk,
- FlushFlags::Reason::kExplicit));
+ auto packet = trace_writer->NewTracePacket();
+ auto ts_unit_multiplier = tls_state.timestamp_unit_multiplier;
+ if (PERFETTO_LIKELY(timestamp.clock_id == kClockIdIncremental)) {
+ if (PERFETTO_LIKELY(incr_state->last_timestamp_ns <= timestamp.value)) {
+ // No need to set the clock id here, since kClockIdIncremental is the
+ // clock id assumed by default.
+ auto time_diff_ns = timestamp.value - incr_state->last_timestamp_ns;
+ auto time_diff_units = time_diff_ns / ts_unit_multiplier;
+ packet->set_timestamp(time_diff_units);
+ incr_state->last_timestamp_ns += time_diff_units * ts_unit_multiplier;
+ } else {
+ packet->set_timestamp(timestamp.value / ts_unit_multiplier);
+ packet->set_timestamp_clock_id(ts_unit_multiplier == 1
+ ? static_cast<uint32_t>(GetClockId())
+ : kClockIdAbsolute);
+ }
+ } else if (PERFETTO_LIKELY(timestamp.clock_id == tls_state.default_clock)) {
+ packet->set_timestamp(timestamp.value / ts_unit_multiplier);
+ } else {
+ packet->set_timestamp(timestamp.value);
+ packet->set_timestamp_clock_id(timestamp.clock_id);
+ }
+ packet->set_sequence_flags(seq_flags);
+ return packet;
}
-void TracingMuxerImpl::StopTracingSession(TracingSessionGlobalID session_id) {
- PERFETTO_DCHECK_THREAD(thread_checker_);
- auto* consumer = FindConsumer(session_id);
- if (!consumer)
- return;
-
- if (consumer->start_pending_) {
- // If the session hasn't started yet, wait until it does before stopping.
- consumer->stop_pending_ = true;
- return;
+// static
+void TrackEventInternal::WriteEventName(StaticString event_name,
+ perfetto::EventContext& event_ctx,
+ const TrackEventTlsState&) {
+ if (PERFETTO_LIKELY(event_name.value != nullptr)) {
+ size_t name_iid = InternedEventName::Get(&event_ctx, event_name.value);
+ event_ctx.event()->set_name_iid(name_iid);
}
+}
- consumer->stop_pending_ = false;
- if (consumer->stopped_) {
- // If the session was already stopped (e.g., it failed to start), don't try
- // stopping again.
- consumer->NotifyStopComplete();
- } else if (!consumer->trace_config_) {
- PERFETTO_ELOG("Must call Setup(config) and Start() first");
- return;
+// static
+void TrackEventInternal::WriteEventName(perfetto::DynamicString event_name,
+ perfetto::EventContext& event_ctx,
+ const TrackEventTlsState& tls_state) {
+ if (PERFETTO_UNLIKELY(tls_state.filter_dynamic_event_names)) {
+ event_ctx.event()->set_name(kFilteredEventName,
+ sizeof(kFilteredEventName) - 1);
} else {
- consumer->service_->DisableTracing();
+ event_ctx.event()->set_name(event_name.value, event_name.length);
}
-
- consumer->trace_config_.reset();
}
-void TracingMuxerImpl::DestroyTracingSession(
- TracingSessionGlobalID session_id) {
- PERFETTO_DCHECK_THREAD(thread_checker_);
- for (RegisteredConsumerBackend& backend : consumer_backends_) {
- // We need to find the consumer (if any) and call Disconnect as we destroy
- // the tracing session. We can't call Disconnect() inside this for loop
- // because in the in-process case this will end up to a synchronous call to
- // OnConsumerDisconnect which will invalidate all the iterators to
- // |backend.consumers|.
- ConsumerImpl* consumer = nullptr;
- for (auto& con : backend.consumers) {
- if (con->session_id_ == session_id) {
- consumer = con.get();
- break;
- }
- }
- if (consumer) {
- // We broke out of the loop above on the assumption that each backend will
- // only have a single consumer per session. This DCHECK ensures that
- // this is the case.
- PERFETTO_DCHECK(
- std::count_if(backend.consumers.begin(), backend.consumers.end(),
- [session_id](const std::unique_ptr<ConsumerImpl>& con) {
- return con->session_id_ == session_id;
- }) == 1u);
- consumer->Disconnect();
+// static
+EventContext TrackEventInternal::WriteEvent(
+ TraceWriterBase* trace_writer,
+ TrackEventIncrementalState* incr_state,
+ TrackEventTlsState& tls_state,
+ const Category* category,
+ perfetto::protos::pbzero::TrackEvent::Type type,
+ const TraceTimestamp& timestamp,
+ bool on_current_thread_track) {
+ PERFETTO_DCHECK(!incr_state->was_cleared);
+ auto packet = NewTracePacket(trace_writer, incr_state, tls_state, timestamp);
+ EventContext ctx(std::move(packet), incr_state, &tls_state);
+
+ auto track_event = ctx.event();
+ if (type != protos::pbzero::TrackEvent::TYPE_UNSPECIFIED)
+ track_event->set_type(type);
+
+ if (tls_state.enable_thread_time_sampling && on_current_thread_track) {
+ if (tls_state.thread_time_subsampling_ns == 0 ||
+ incr_state->last_thread_time_timestamp_ns == 0 ||
+ timestamp.value >= incr_state->last_thread_time_timestamp_ns +
+ tls_state.thread_time_subsampling_ns) {
+ auto thread_time_ns = base::GetThreadCPUTimeNs().count();
+ auto thread_time_delta_ns =
+ thread_time_ns - incr_state->last_thread_time_ns;
+ incr_state->last_thread_time_ns = thread_time_ns;
+ incr_state->last_thread_time_timestamp_ns = timestamp.value;
+ track_event->add_extra_counter_values(
+ thread_time_delta_ns /
+ static_cast<int64_t>(tls_state.timestamp_unit_multiplier));
+ } else {
+ // When subsampling, the skip emitting values.
+ track_event->add_extra_counter_values(0);
}
}
-}
-void TracingMuxerImpl::ReadTracingSessionData(
- TracingSessionGlobalID session_id,
- std::function<void(TracingSession::ReadTraceCallbackArgs)> callback) {
- PERFETTO_DCHECK_THREAD(thread_checker_);
- auto* consumer = FindConsumer(session_id);
- if (!consumer) {
- // TODO(skyostil): Signal an error to the user.
- TracingSession::ReadTraceCallbackArgs callback_arg{};
- callback(callback_arg);
- return;
+ // We assume that |category| points to the string with static lifetime.
+ // This means we can use their addresses as interning keys.
+ // TODO(skyostil): Intern categories at compile time.
+ if (category && type != protos::pbzero::TrackEvent::TYPE_SLICE_END &&
+ type != protos::pbzero::TrackEvent::TYPE_COUNTER) {
+ category->ForEachGroupMember(
+ [&](const char* member_name, size_t name_size) {
+ size_t category_iid =
+ InternedEventCategory::Get(&ctx, member_name, name_size);
+ track_event->add_category_iids(category_iid);
+ return true;
+ });
}
- PERFETTO_DCHECK(!consumer->read_trace_callback_);
- consumer->read_trace_callback_ = std::move(callback);
- consumer->service_->ReadBuffers();
+ return ctx;
}
-void TracingMuxerImpl::GetTraceStats(
- TracingSessionGlobalID session_id,
- TracingSession::GetTraceStatsCallback callback) {
- PERFETTO_DCHECK_THREAD(thread_checker_);
- auto* consumer = FindConsumer(session_id);
- if (!consumer) {
- TracingSession::GetTraceStatsCallbackArgs callback_arg{};
- callback_arg.success = false;
- callback(std::move(callback_arg));
- return;
- }
- PERFETTO_DCHECK(!consumer->get_trace_stats_callback_);
- consumer->get_trace_stats_callback_ = std::move(callback);
- if (!consumer->connected_) {
- consumer->get_trace_stats_pending_ = true;
- return;
- }
- consumer->get_trace_stats_pending_ = false;
- consumer->service_->GetTraceStats();
+// static
+protos::pbzero::DebugAnnotation* TrackEventInternal::AddDebugAnnotation(
+ perfetto::EventContext* event_ctx,
+ const char* name) {
+ auto annotation = event_ctx->event()->add_debug_annotations();
+ annotation->set_name_iid(InternedDebugAnnotationName::Get(event_ctx, name));
+ return annotation;
}
-void TracingMuxerImpl::QueryServiceState(
- TracingSessionGlobalID session_id,
- TracingSession::QueryServiceStateCallback callback) {
- PERFETTO_DCHECK_THREAD(thread_checker_);
- auto* consumer = FindConsumer(session_id);
- if (!consumer) {
- TracingSession::QueryServiceStateCallbackArgs callback_arg{};
- callback_arg.success = false;
- callback(std::move(callback_arg));
- return;
- }
- PERFETTO_DCHECK(!consumer->query_service_state_callback_);
- if (!consumer->connected_) {
- consumer->query_service_state_callback_ = std::move(callback);
- return;
- }
- auto callback_wrapper = [callback](bool success,
- protos::gen::TracingServiceState state) {
- TracingSession::QueryServiceStateCallbackArgs callback_arg{};
- callback_arg.success = success;
- callback_arg.service_state_data = state.SerializeAsArray();
- callback(std::move(callback_arg));
- };
- consumer->service_->QueryServiceState({}, std::move(callback_wrapper));
+// static
+protos::pbzero::DebugAnnotation* TrackEventInternal::AddDebugAnnotation(
+ perfetto::EventContext* event_ctx,
+ perfetto::DynamicString name) {
+ auto annotation = event_ctx->event()->add_debug_annotations();
+ annotation->set_name(name.value);
+ return annotation;
}
-void TracingMuxerImpl::SetBatchCommitsDurationForTesting(
- uint32_t batch_commits_duration_ms,
- BackendType backend_type) {
- for (RegisteredProducerBackend& backend : producer_backends_) {
- if (backend.producer && backend.producer->connected_ &&
- backend.type == backend_type) {
- backend.producer->service_->MaybeSharedMemoryArbiter()
- ->SetBatchCommitsDuration(batch_commits_duration_ms);
- }
- }
+void TrackEventDataSource::OnStart(const DataSourceBase::StartArgs& args) {
+ TrackEventInternal::OnStart(args);
}
-bool TracingMuxerImpl::EnableDirectSMBPatchingForTesting(
- BackendType backend_type) {
- for (RegisteredProducerBackend& backend : producer_backends_) {
- if (backend.producer && backend.producer->connected_ &&
- backend.type == backend_type &&
- !backend.producer->service_->MaybeSharedMemoryArbiter()
- ->EnableDirectSMBPatching()) {
- return false;
- }
- }
- return true;
-}
+} // namespace internal
-TracingMuxerImpl::ConsumerImpl* TracingMuxerImpl::FindConsumer(
- TracingSessionGlobalID session_id) {
- PERFETTO_DCHECK_THREAD(thread_checker_);
- return FindConsumerAndBackend(session_id).first;
-}
+PERFETTO_DEFINE_DATA_SOURCE_STATIC_MEMBERS_WITH_ATTRS(
+ PERFETTO_EXPORT_COMPONENT,
+ perfetto::internal::TrackEventDataSource,
+ perfetto::internal::TrackEventDataSourceTraits);
-std::pair<TracingMuxerImpl::ConsumerImpl*,
- TracingMuxerImpl::RegisteredConsumerBackend*>
-TracingMuxerImpl::FindConsumerAndBackend(TracingSessionGlobalID session_id) {
- PERFETTO_DCHECK_THREAD(thread_checker_);
- for (RegisteredConsumerBackend& backend : consumer_backends_) {
- for (auto& consumer : backend.consumers) {
- if (consumer->session_id_ == session_id) {
- return {consumer.get(), &backend};
- }
- }
- }
- return {nullptr, nullptr};
-}
+} // namespace perfetto
+// gen_amalgamated begin source: src/tracing/internal/track_event_interned_fields.cc
+/*
+ * Copyright (C) 2021 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.
+ */
-void TracingMuxerImpl::InitializeConsumer(TracingSessionGlobalID session_id) {
- PERFETTO_DCHECK_THREAD(thread_checker_);
+// gen_amalgamated expanded: #include "perfetto/tracing/internal/track_event_interned_fields.h"
- auto res = FindConsumerAndBackend(session_id);
- if (!res.first || !res.second)
- return;
- TracingMuxerImpl::ConsumerImpl* consumer = res.first;
- RegisteredConsumerBackend& backend = *res.second;
+namespace perfetto {
+namespace internal {
- TracingBackend::ConnectConsumerArgs conn_args;
- conn_args.consumer = consumer;
- conn_args.task_runner = task_runner_.get();
- consumer->Initialize(backend.backend->ConnectConsumer(conn_args));
-}
+InternedEventCategory::~InternedEventCategory() = default;
-void TracingMuxerImpl::OnConsumerDisconnected(ConsumerImpl* consumer) {
- PERFETTO_DCHECK_THREAD(thread_checker_);
- for (RegisteredConsumerBackend& backend : consumer_backends_) {
- auto pred = [consumer](const std::unique_ptr<ConsumerImpl>& con) {
- return con.get() == consumer;
- };
- backend.consumers.erase(std::remove_if(backend.consumers.begin(),
- backend.consumers.end(), pred),
- backend.consumers.end());
- }
+// static
+void InternedEventCategory::Add(protos::pbzero::InternedData* interned_data,
+ size_t iid,
+ const char* value,
+ size_t length) {
+ auto category = interned_data->add_event_categories();
+ category->set_iid(iid);
+ category->set_name(value, length);
}
-void TracingMuxerImpl::SetMaxProducerReconnectionsForTesting(uint32_t count) {
- max_producer_reconnections_.store(count);
+InternedEventName::~InternedEventName() = default;
+
+// static
+void InternedEventName::Add(protos::pbzero::InternedData* interned_data,
+ size_t iid,
+ const char* value) {
+ auto name = interned_data->add_event_names();
+ name->set_iid(iid);
+ name->set_name(value);
}
-void TracingMuxerImpl::OnProducerDisconnected(ProducerImpl* producer) {
- PERFETTO_DCHECK_THREAD(thread_checker_);
- for (RegisteredProducerBackend& backend : producer_backends_) {
- if (backend.producer.get() != producer)
- continue;
+InternedDebugAnnotationName::~InternedDebugAnnotationName() = default;
- // The tracing service is disconnected. It does not make sense to keep
- // tracing (we wouldn't be able to commit). On reconnection, the tracing
- // service will restart the data sources.
- for (const auto& rds : data_sources_) {
- DataSourceStaticState* static_state = rds.static_state;
- for (uint32_t i = 0; i < kMaxDataSourceInstances; i++) {
- auto* internal_state = static_state->TryGet(i);
- if (internal_state && internal_state->backend_id == backend.id &&
- internal_state->backend_connection_id ==
- backend.producer->connection_id_.load(
- std::memory_order_relaxed)) {
- StopDataSource_AsyncBeginImpl(
- FindDataSourceRes(static_state, internal_state, i,
- rds.params.requires_callbacks_under_lock));
- }
- }
- }
+// static
+void InternedDebugAnnotationName::Add(
+ protos::pbzero::InternedData* interned_data,
+ size_t iid,
+ const char* value) {
+ auto name = interned_data->add_debug_annotation_names();
+ name->set_iid(iid);
+ name->set_name(value);
+}
- // Try reconnecting the disconnected producer. If the connection succeeds,
- // all the data sources will be automatically re-registered.
- if (producer->connection_id_.load(std::memory_order_relaxed) >
- max_producer_reconnections_.load()) {
- // Avoid reconnecting a failing producer too many times. Instead we just
- // leak the producer instead of trying to avoid further complicating
- // cross-thread trace writer creation.
- PERFETTO_ELOG("Producer disconnected too many times; not reconnecting");
- continue;
- }
+InternedDebugAnnotationValueTypeName::~InternedDebugAnnotationValueTypeName() =
+ default;
- backend.producer->Initialize(
- backend.backend->ConnectProducer(backend.producer_conn_args));
- // Don't use producer-provided SMBs for the next connection unless startup
- // tracing requires it again.
- backend.producer_conn_args.use_producer_provided_smb = false;
- }
+// static
+void InternedDebugAnnotationValueTypeName::Add(
+ protos::pbzero::InternedData* interned_data,
+ size_t iid,
+ const char* value) {
+ auto name = interned_data->add_debug_annotation_value_type_names();
+ name->set_iid(iid);
+ name->set_name(value);
}
-void TracingMuxerImpl::SweepDeadBackends() {
- PERFETTO_DCHECK_THREAD(thread_checker_);
- for (auto it = dead_backends_.begin(); it != dead_backends_.end();) {
- auto next_it = it;
- next_it++;
- if (it->producer->SweepDeadServices())
- dead_backends_.erase(it);
- it = next_it;
- }
+} // namespace internal
+} // namespace perfetto
+// gen_amalgamated begin source: src/tracing/platform.cc
+/*
+ * 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.
+ */
+
+// gen_amalgamated expanded: #include "perfetto/tracing/platform.h"
+// gen_amalgamated expanded: #include "perfetto/tracing/internal/tracing_tls.h"
+// gen_amalgamated expanded: #include "perfetto/tracing/trace_writer_base.h"
+
+namespace perfetto {
+
+PlatformThreadLocalObject::~PlatformThreadLocalObject() = default;
+Platform::~Platform() = default;
+
+void Platform::Shutdown() {}
+
+base::PlatformThreadId Platform::GetCurrentThreadId() {
+ return base::GetThreadId();
}
-TracingMuxerImpl::FindDataSourceRes TracingMuxerImpl::FindDataSource(
- TracingBackendId backend_id,
- DataSourceInstanceID instance_id) {
- PERFETTO_DCHECK_THREAD(thread_checker_);
- // 0 is the sentinel id for unadopted startup data sources; never match it.
- if (instance_id == 0)
- return FindDataSourceRes();
- RegisteredProducerBackend& backend = *FindProducerBackendById(backend_id);
- for (const auto& rds : data_sources_) {
- DataSourceStaticState* static_state = rds.static_state;
- for (uint32_t i = 0; i < kMaxDataSourceInstances; i++) {
- auto* internal_state = static_state->TryGet(i);
- if (internal_state && internal_state->backend_id == backend_id &&
- internal_state->backend_connection_id ==
- backend.producer->connection_id_.load(
- std::memory_order_relaxed) &&
- internal_state->data_source_instance_id == instance_id) {
- return FindDataSourceRes(static_state, internal_state, i,
- rds.params.requires_callbacks_under_lock);
- }
- }
- }
- return FindDataSourceRes();
+// static
+std::unique_ptr<PlatformThreadLocalObject>
+PlatformThreadLocalObject::CreateInstance() {
+ return std::unique_ptr<PlatformThreadLocalObject>(new internal::TracingTLS());
}
-// Can be called from any thread.
-std::unique_ptr<TraceWriterBase> TracingMuxerImpl::CreateTraceWriter(
- DataSourceStaticState* static_state,
- uint32_t data_source_instance_index,
- DataSourceState* data_source,
- BufferExhaustedPolicy buffer_exhausted_policy) {
- if (PERFETTO_UNLIKELY(data_source->interceptor_id)) {
- // If the session is being intercepted, return a heap-backed trace writer
- // instead. This is safe because all the data given to the interceptor is
- // either thread-local (|instance_index|), statically allocated
- // (|static_state|) or constant after initialization (|interceptor|). Access
- // to the interceptor instance itself through |data_source| is protected by
- // a statically allocated lock (similarly to the data source instance).
- auto& interceptor = interceptors_[data_source->interceptor_id - 1];
- return std::unique_ptr<TraceWriterBase>(new InterceptorTraceWriter(
- interceptor.tls_factory(static_state, data_source_instance_index),
- interceptor.packet_callback, static_state, data_source_instance_index));
- }
- ProducerImpl* producer =
- FindProducerBackendById(data_source->backend_id)->producer.get();
- // Atomically load the current service endpoint. We keep the pointer as a
- // shared pointer on the stack to guard against it from being concurrently
- // modified on the thread by ProducerImpl::Initialize() swapping in a
- // reconnected service on the muxer task runner thread.
- //
- // The endpoint may also be concurrently modified by SweepDeadServices()
- // clearing out old disconnected services. We guard against that by
- // SharedMemoryArbiter keeping track of any outstanding trace writers. After
- // shutdown has started, the trace writer created below will be a null one
- // which will drop any written data. See SharedMemoryArbiter::TryShutdown().
- //
- // We use an atomic pointer instead of holding a lock because
- // CreateTraceWriter posts tasks under the hood.
- std::shared_ptr<ProducerEndpoint> service =
- std::atomic_load(&producer->service_);
+// static
+base::PlatformProcessId Platform::process_id_ = 0;
- // The service may have been disconnected and reconnected concurrently after
- // the data source was enabled, in which case we may not have an arbiter, or
- // would be creating a TraceWriter for the wrong (a newer) connection / SMB.
- // Instead, early-out now. A relaxed load is fine here because the atomic_load
- // above ensures that the |service| isn't newer.
- if (producer->connection_id_.load(std::memory_order_relaxed) !=
- data_source->backend_connection_id) {
- return std::unique_ptr<TraceWriter>(new NullTraceWriter());
- }
+} // namespace perfetto
+// gen_amalgamated begin source: src/tracing/platform_posix.cc
+/*
+ * 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.
+ */
- // We just need a relaxed atomic read here: We can use the reservation ID even
- // after the buffer was bound, we just need to be sure to read it atomically.
- uint16_t startup_buffer_reservation =
- data_source->startup_target_buffer_reservation.load(
- std::memory_order_relaxed);
- if (startup_buffer_reservation) {
- return service->MaybeSharedMemoryArbiter()->CreateStartupTraceWriter(
- startup_buffer_reservation);
- }
- return service->CreateTraceWriter(data_source->buffer_id,
- buffer_exhausted_policy);
-}
+// gen_amalgamated expanded: #include "perfetto/base/build_config.h"
-// This is called via the public API Tracing::NewTrace().
-// Can be called from any thread.
-std::unique_ptr<TracingSession> TracingMuxerImpl::CreateTracingSession(
- BackendType requested_backend_type,
- TracingConsumerBackend* (*system_backend_factory)()) {
- TracingSessionGlobalID session_id = ++next_tracing_session_id_;
+#if PERFETTO_BUILDFLAG(PERFETTO_OS_LINUX) || \
+ PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID) || \
+ PERFETTO_BUILDFLAG(PERFETTO_OS_FUCHSIA) || \
+ PERFETTO_BUILDFLAG(PERFETTO_OS_FREEBSD) || \
+ PERFETTO_BUILDFLAG(PERFETTO_OS_APPLE)
- // |backend_type| can only specify one backend, not an OR-ed mask.
- PERFETTO_CHECK((requested_backend_type & (requested_backend_type - 1)) == 0);
+// gen_amalgamated expanded: #include "perfetto/ext/base/file_utils.h"
+// gen_amalgamated expanded: #include "perfetto/ext/base/thread_task_runner.h"
+// gen_amalgamated expanded: #include "perfetto/tracing/internal/tracing_tls.h"
+// gen_amalgamated expanded: #include "perfetto/tracing/platform.h"
+// gen_amalgamated expanded: #include "perfetto/tracing/trace_writer_base.h"
- // Capturing |this| is fine because the TracingMuxer is a leaky singleton.
- task_runner_->PostTask([this, requested_backend_type, session_id,
- system_backend_factory] {
- if (requested_backend_type == kSystemBackend && system_backend_factory &&
- !FindConsumerBackendByType(kSystemBackend)) {
- AddConsumerBackend(system_backend_factory(), kSystemBackend);
- }
- for (RegisteredConsumerBackend& backend : consumer_backends_) {
- if (requested_backend_type && backend.type &&
- backend.type != requested_backend_type) {
- continue;
- }
+#include <pthread.h>
+#include <stdlib.h>
- // Create the consumer now, even if we have to ask the embedder below, so
- // that any other tasks executing after this one can find the consumer and
- // change its pending attributes.
- backend.consumers.emplace_back(
- new ConsumerImpl(this, backend.type, session_id));
+namespace perfetto {
- // The last registered backend in |consumer_backends_| is the unsupported
- // backend without a valid type.
- if (!backend.type) {
- PERFETTO_ELOG(
- "No tracing backend ready for type=%u, consumer will disconnect",
- requested_backend_type);
- InitializeConsumer(session_id);
- return;
- }
+namespace {
- // Check if the embedder wants to be asked for permission before
- // connecting the consumer.
- if (!policy_) {
- InitializeConsumer(session_id);
- return;
- }
+class PlatformPosix : public Platform {
+ public:
+ PlatformPosix();
+ ~PlatformPosix() override;
- BackendType type = backend.type;
- TracingPolicy::ShouldAllowConsumerSessionArgs args;
- args.backend_type = backend.type;
- args.result_callback = [this, type, session_id](bool allow) {
- task_runner_->PostTask([this, type, session_id, allow] {
- if (allow) {
- InitializeConsumer(session_id);
- return;
- }
+ ThreadLocalObject* GetOrCreateThreadLocalObject() override;
- PERFETTO_ELOG(
- "Consumer session for backend type type=%u forbidden, "
- "consumer will disconnect",
- type);
+ std::unique_ptr<base::TaskRunner> CreateTaskRunner(
+ const CreateTaskRunnerArgs&) override;
+ std::string GetCurrentProcessName() override;
+ void Shutdown() override;
- auto* consumer = FindConsumer(session_id);
- if (!consumer)
- return;
+ private:
+ pthread_key_t tls_key_{};
+};
- consumer->OnDisconnect();
- });
- };
- policy_->ShouldAllowConsumerSession(args);
- return;
- }
- PERFETTO_DFATAL("Not reached");
- });
+PlatformPosix* g_instance = nullptr;
- return std::unique_ptr<TracingSession>(
- new TracingSessionImpl(this, session_id, requested_backend_type));
+using ThreadLocalObject = Platform::ThreadLocalObject;
+
+PlatformPosix::PlatformPosix() {
+ PERFETTO_CHECK(!g_instance);
+ g_instance = this;
+ auto tls_dtor = [](void* obj) {
+ // The Posix TLS implementation resets the key before calling this dtor.
+ // Here we re-reset it to the object we are about to delete. This is to
+ // handle re-entrant usages of tracing in the PostTask done during the dtor
+ // (see comments in TracingTLS::~TracingTLS()). Chromium's platform
+ // implementation (which does NOT use this platform impl) has a similar
+ // workaround (https://crrev.com/c/2748300).
+ pthread_setspecific(g_instance->tls_key_, obj);
+ delete static_cast<ThreadLocalObject*>(obj);
+ pthread_setspecific(g_instance->tls_key_, nullptr);
+ };
+ PERFETTO_CHECK(pthread_key_create(&tls_key_, tls_dtor) == 0);
+}
+
+PlatformPosix::~PlatformPosix() {
+ // pthread_key_delete doesn't call destructors, so do it manually for the
+ // calling thread.
+ void* tls_ptr = pthread_getspecific(tls_key_);
+ delete static_cast<ThreadLocalObject*>(tls_ptr);
+
+ pthread_key_delete(tls_key_);
+ g_instance = nullptr;
}
-// static
-// This is called via the public API Tracing::SetupStartupTracing().
-// Can be called from any thread.
-std::unique_ptr<StartupTracingSession>
-TracingMuxerImpl::CreateStartupTracingSession(
- const TraceConfig& config,
- Tracing::SetupStartupTracingOpts opts) {
- BackendType backend_type = opts.backend;
- // |backend_type| can only specify one backend, not an OR-ed mask.
- PERFETTO_CHECK((backend_type & (backend_type - 1)) == 0);
- // The in-process backend doesn't support startup tracing.
- PERFETTO_CHECK(backend_type != BackendType::kInProcessBackend);
-
- TracingSessionGlobalID session_id = ++next_tracing_session_id_;
+void PlatformPosix::Shutdown() {
+ PERFETTO_CHECK(g_instance == this);
+ delete this;
+ PERFETTO_CHECK(!g_instance);
+ // We're not clearing out the instance in GetDefaultPlatform() since it's not
+ // possible to re-initialize Perfetto after calling this function anyway.
+}
- // Capturing |this| is fine because the TracingMuxer is a leaky singleton.
- task_runner_->PostTask([this, config, opts, backend_type, session_id] {
- for (RegisteredProducerBackend& backend : producer_backends_) {
- if (backend_type && backend.type && backend.type != backend_type) {
- continue;
- }
+ThreadLocalObject* PlatformPosix::GetOrCreateThreadLocalObject() {
+ // In chromium this should be implemented using base::ThreadLocalStorage.
+ void* tls_ptr = pthread_getspecific(tls_key_);
- TracingBackendId backend_id = backend.id;
+ // This is needed to handle re-entrant calls during TLS dtor.
+ // See comments in platform.cc and aosp/1712371 .
+ ThreadLocalObject* tls = static_cast<ThreadLocalObject*>(tls_ptr);
+ if (!tls) {
+ tls = ThreadLocalObject::CreateInstance().release();
+ pthread_setspecific(tls_key_, tls);
+ }
+ return tls;
+}
- // The last registered backend in |producer_backends_| is the unsupported
- // backend without a valid type.
- if (!backend.type) {
- PERFETTO_ELOG(
- "No tracing backend initialized for type=%u, startup tracing "
- "failed",
- backend_type);
- if (opts.on_setup)
- opts.on_setup(Tracing::OnStartupTracingSetupCallbackArgs{
- 0 /* num_data_sources_started */});
- return;
- }
+std::unique_ptr<base::TaskRunner> PlatformPosix::CreateTaskRunner(
+ const CreateTaskRunnerArgs& args) {
+ return std::unique_ptr<base::TaskRunner>(new base::ThreadTaskRunner(
+ base::ThreadTaskRunner::CreateAndStart(args.name_for_debugging)));
+}
- if (!backend.producer->service_ ||
- !backend.producer->service_->shared_memory()) {
- // If we unsuccessfully attempted to use a producer-provided SMB in the
- // past, don't try again.
- if (backend.producer->producer_provided_smb_failed_) {
- PERFETTO_ELOG(
- "Backend %zu doesn't seem to support producer-provided "
- "SMBs, startup tracing failed",
- backend_id);
- if (opts.on_setup)
- opts.on_setup(Tracing::OnStartupTracingSetupCallbackArgs{
- 0 /* num_data_sources_started */});
- return;
- }
+std::string PlatformPosix::GetCurrentProcessName() {
+#if PERFETTO_BUILDFLAG(PERFETTO_OS_LINUX) || \
+ PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID)
+ std::string cmdline;
+ base::ReadFile("/proc/self/cmdline", &cmdline);
+ return cmdline.substr(0, cmdline.find('\0'));
+#elif PERFETTO_BUILDFLAG(PERFETTO_OS_APPLE) || \
+ PERFETTO_BUILDFLAG(PERFETTO_OS_FREEBSD)
+ return std::string(getprogname());
+#else
+ return "unknown_producer";
+#endif
+}
- PERFETTO_DLOG("Reconnecting backend %zu for startup tracing",
- backend_id);
- backend.producer_conn_args.use_producer_provided_smb = true;
- backend.producer->service_->Disconnect(); // Causes a reconnect.
- PERFETTO_DCHECK(backend.producer->service_ &&
- backend.producer->service_->MaybeSharedMemoryArbiter());
- }
+} // namespace
- RegisteredStartupSession session;
- session.session_id = session_id;
- session.on_aborted = opts.on_aborted;
- session.on_adopted = opts.on_adopted;
+// static
+Platform* Platform::GetDefaultPlatform() {
+ static PlatformPosix* instance = new PlatformPosix();
+ return instance;
+}
- for (const TraceConfig::DataSource& ds_cfg : config.data_sources()) {
- // Find all matching data sources and start one instance of each.
- for (const auto& rds : data_sources_) {
- if (rds.descriptor.name() != ds_cfg.config().name())
- continue;
+} // namespace perfetto
+#endif // OS_LINUX || OS_ANDROID || OS_APPLE || OS_FUCHSIA
+// gen_amalgamated begin source: src/tracing/platform_windows.cc
+/*
+ * Copyright (C) 2021 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.
+ */
- PERFETTO_DLOG(
- "Setting up data source %s for startup tracing with target "
- "buffer reservation %" PRIi32,
- rds.descriptor.name().c_str(),
- backend.producer->last_startup_target_buffer_reservation_ + 1u);
- auto ds = SetupDataSourceImpl(
- rds, backend_id,
- backend.producer->connection_id_.load(std::memory_order_relaxed),
- /*instance_id=*/0, ds_cfg.config(),
- /*startup_session_id=*/session_id);
- if (ds) {
- StartDataSourceImpl(ds);
- session.num_unbound_data_sources++;
- }
- }
- }
+// gen_amalgamated expanded: #include "perfetto/base/build_config.h"
- int num_ds = session.num_unbound_data_sources;
- auto on_setup = opts.on_setup;
- if (on_setup) {
- backend.producer->OnStartupTracingSetup();
- task_runner_->PostTask([on_setup, num_ds] {
- on_setup(Tracing::OnStartupTracingSetupCallbackArgs{num_ds});
- });
- }
+#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
- if (num_ds > 0) {
- backend.startup_sessions.push_back(std::move(session));
+#include <windows.h>
- if (opts.timeout_ms > 0) {
- task_runner_->PostDelayedTask(
- [this, session_id, backend_type] {
- AbortStartupTracingSession(session_id, backend_type);
- },
- opts.timeout_ms);
- }
- }
- return;
- }
- PERFETTO_DFATAL("Invalid startup tracing session backend");
- });
+// gen_amalgamated expanded: #include "perfetto/ext/base/thread_task_runner.h"
+// gen_amalgamated expanded: #include "perfetto/tracing/internal/tracing_tls.h"
+// gen_amalgamated expanded: #include "perfetto/tracing/platform.h"
- return std::unique_ptr<StartupTracingSession>(
- new StartupTracingSessionImpl(this, session_id, backend_type));
-}
+// Thread Termination Callbacks.
+// Windows doesn't support a per-thread destructor with its
+// TLS primitives. So, we build it manually by inserting a
+// function to be called on each thread's exit.
+// This magic is from chromium's base/threading/thread_local_storage_win.cc
+// which in turn is from http://www.codeproject.com/threads/tls.asp.
-// Must not be called from the SDK's internal thread.
-std::unique_ptr<StartupTracingSession>
-TracingMuxerImpl::CreateStartupTracingSessionBlocking(
- const TraceConfig& config,
- Tracing::SetupStartupTracingOpts opts) {
- auto previous_on_setup = std::move(opts.on_setup);
- PERFETTO_CHECK(!task_runner_->RunsTasksOnCurrentThread());
- base::WaitableEvent event;
- // It is safe to capture by reference because once on_setup is called only
- // once before this method returns.
- opts.on_setup = [&](Tracing::OnStartupTracingSetupCallbackArgs args) {
- if (previous_on_setup) {
- previous_on_setup(std::move(args));
- }
- event.Notify();
- };
- auto session = CreateStartupTracingSession(config, std::move(opts));
- event.Wait();
- return session;
-}
+#ifdef _WIN64
+#pragma comment(linker, "/INCLUDE:_tls_used")
+#pragma comment(linker, "/INCLUDE:perfetto_thread_callback_base")
+#else
+#pragma comment(linker, "/INCLUDE:__tls_used")
+#pragma comment(linker, "/INCLUDE:_perfetto_thread_callback_base")
+#endif
-void TracingMuxerImpl::AbortStartupTracingSession(
- TracingSessionGlobalID session_id,
- BackendType backend_type) {
- PERFETTO_DCHECK_THREAD(thread_checker_);
+namespace perfetto {
- for (RegisteredProducerBackend& backend : producer_backends_) {
- if (backend_type != backend.type)
- continue;
+namespace {
- auto session_it = std::find_if(
- backend.startup_sessions.begin(), backend.startup_sessions.end(),
- [session_id](const RegisteredStartupSession& session) {
- return session.session_id == session_id;
- });
+class PlatformWindows : public Platform {
+ public:
+ static PlatformWindows* instance;
+ PlatformWindows();
+ ~PlatformWindows() override;
- // The startup session may have already been aborted or fully adopted.
- if (session_it == backend.startup_sessions.end())
- return;
- if (session_it->is_aborting)
- return;
+ ThreadLocalObject* GetOrCreateThreadLocalObject() override;
+ std::unique_ptr<base::TaskRunner> CreateTaskRunner(
+ const CreateTaskRunnerArgs&) override;
+ std::string GetCurrentProcessName() override;
+ void OnThreadExit();
- session_it->is_aborting = true;
+ private:
+ DWORD tls_key_{};
+};
- // Iterate all data sources and abort them if they weren't adopted yet.
- for (const auto& rds : data_sources_) {
- DataSourceStaticState* static_state = rds.static_state;
- for (uint32_t i = 0; i < kMaxDataSourceInstances; i++) {
- auto* internal_state = static_state->TryGet(i);
- if (internal_state &&
- internal_state->startup_target_buffer_reservation.load(
- std::memory_order_relaxed) &&
- internal_state->data_source_instance_id == 0 &&
- internal_state->startup_session_id == session_id) {
- PERFETTO_DLOG(
- "Aborting startup tracing for data source %s (target buffer "
- "reservation %" PRIu16 ")",
- rds.descriptor.name().c_str(),
- internal_state->startup_target_buffer_reservation.load(
- std::memory_order_relaxed));
+using ThreadLocalObject = Platform::ThreadLocalObject;
- // Abort the instance asynchronously by stopping it. From this point
- // onwards, the service will not be able to adopt it via
- // StartDataSource().
- session_it->num_aborting_data_sources++;
- StopDataSource_AsyncBeginImpl(
- FindDataSourceRes(static_state, internal_state, i,
- rds.params.requires_callbacks_under_lock));
- }
- }
- }
+// static
+PlatformWindows* PlatformWindows::instance = nullptr;
- // If we did everything right, we should have aborted all still-unbound data
- // source instances.
- PERFETTO_DCHECK(session_it->num_unbound_data_sources ==
- session_it->num_aborting_data_sources);
+PlatformWindows::PlatformWindows() {
+ instance = this;
+ tls_key_ = ::TlsAlloc();
+ PERFETTO_CHECK(tls_key_ != TLS_OUT_OF_INDEXES);
+}
- if (session_it->num_aborting_data_sources == 0) {
- if (session_it->on_aborted)
- task_runner_->PostTask(session_it->on_aborted);
+PlatformWindows::~PlatformWindows() {
+ // TlsFree doesn't call destructors, so do it manually for the calling
+ // thread.
+ OnThreadExit();
+ ::TlsFree(tls_key_);
+ instance = nullptr;
+}
- backend.startup_sessions.erase(session_it);
- }
- return;
+void PlatformWindows::OnThreadExit() {
+ auto tls = static_cast<ThreadLocalObject*>(::TlsGetValue(tls_key_));
+ if (tls) {
+ // At this point we rely on the TLS object to be still set to the TracingTLS
+ // we are deleting. See comments in TracingTLS::~TracingTLS().
+ delete tls;
}
- // We might reach here in tests because when we start a trace, we post the
- // Task(AbortStartupTrace, delay=timeout). When we do
- // perfetto::ResetForTesting, we sweep dead backends, and we are not able to
- // kill those delayed tasks because TaskRunner doesn't have support for
- // deleting scheduled future tasks and TaskRunner doesn't have any API for us
- // to wait for the completion of all the scheduled tasks (apart from
- // deleting the TaskRunner) and we want to avoid doing that because we need
- // a long running TaskRunner in muxer.
- PERFETTO_DLOG("Invalid startup tracing session backend");
}
-void TracingMuxerImpl::InitializeInstance(const TracingInitArgs& args) {
- if (instance_ != TracingMuxerFake::Get()) {
- // The tracing muxer was already initialized. We might need to initialize
- // additional backends that were not configured earlier.
- auto* muxer = static_cast<TracingMuxerImpl*>(instance_);
- muxer->task_runner_->PostTask([muxer, args] { muxer->AddBackends(args); });
- return;
- }
- // If we previously had a TracingMuxerImpl instance which was reset,
- // reinitialize and reuse it instead of trying to create a new one. See
- // ResetForTesting().
- if (g_prev_instance) {
- auto* muxer = g_prev_instance;
- g_prev_instance = nullptr;
- instance_ = muxer;
- muxer->task_runner_->PostTask([muxer, args] {
- muxer->Initialize(args);
- muxer->AddBackends(args);
- });
- } else {
- new TracingMuxerImpl(args);
+ThreadLocalObject* PlatformWindows::GetOrCreateThreadLocalObject() {
+ void* tls_ptr = ::TlsGetValue(tls_key_);
+
+ auto* tls = static_cast<ThreadLocalObject*>(tls_ptr);
+ if (!tls) {
+ tls = ThreadLocalObject::CreateInstance().release();
+ ::TlsSetValue(tls_key_, tls);
}
+ return tls;
}
-// static
-void TracingMuxerImpl::ResetForTesting() {
- // Ideally we'd tear down the entire TracingMuxerImpl, but the lifetimes of
- // various objects make that a non-starter. In particular:
- //
- // 1) Any thread that has entered a trace event has a TraceWriter, which holds
- // a reference back to ProducerImpl::service_.
- //
- // 2) ProducerImpl::service_ has a reference back to the ProducerImpl.
- //
- // 3) ProducerImpl holds reference to TracingMuxerImpl::task_runner_, which in
- // turn depends on TracingMuxerImpl itself.
- //
- // Because of this, it's not safe to deallocate TracingMuxerImpl until all
- // threads have dropped their TraceWriters. Since we can't really ask the
- // caller to guarantee this, we'll instead reset enough of the muxer's state
- // so that it can be reinitialized later and ensure all necessary objects from
- // the old state remain alive until all references have gone away.
- auto* muxer = reinterpret_cast<TracingMuxerImpl*>(instance_);
-
- base::WaitableEvent reset_done;
- auto do_reset = [muxer, &reset_done] {
- muxer->DestroyStoppedTraceWritersForCurrentThread();
- // Unregister all data sources so they don't interfere with any future
- // tracing sessions.
- for (RegisteredDataSource& rds : muxer->data_sources_) {
- for (RegisteredProducerBackend& backend : muxer->producer_backends_) {
- if (!backend.producer->service_ || !backend.producer->connected_)
- continue;
- backend.producer->service_->UnregisterDataSource(rds.descriptor.name());
- }
- }
- for (auto& backend : muxer->consumer_backends_) {
- // Check that no consumer session is currently active on any backend.
- for (auto& consumer : backend.consumers)
- PERFETTO_CHECK(!consumer->service_);
- }
- for (auto& backend : muxer->producer_backends_) {
- backend.producer->muxer_ = nullptr;
- backend.producer->DisposeConnection();
- muxer->dead_backends_.push_back(std::move(backend));
- }
- muxer->consumer_backends_.clear();
- muxer->producer_backends_.clear();
- muxer->interceptors_.clear();
+std::unique_ptr<base::TaskRunner> PlatformWindows::CreateTaskRunner(
+ const CreateTaskRunnerArgs& args) {
+ return std::unique_ptr<base::TaskRunner>(new base::ThreadTaskRunner(
+ base::ThreadTaskRunner::CreateAndStart(args.name_for_debugging)));
+}
- for (auto& ds : muxer->data_sources_) {
- ds.static_state->ResetForTesting();
- }
+std::string PlatformWindows::GetCurrentProcessName() {
+ char buf[MAX_PATH];
+ auto len = ::GetModuleFileNameA(nullptr /*current*/, buf, sizeof(buf));
+ std::string name(buf, static_cast<size_t>(len));
+ size_t sep = name.find_last_of('\\');
+ if (sep != std::string::npos)
+ name = name.substr(sep + 1);
+ return name;
+}
- muxer->data_sources_.clear();
- muxer->next_data_source_index_ = 0;
+} // namespace
- // Free all backends without active trace writers or other inbound
- // references. Note that even if all the backends get swept, the muxer still
- // needs to stay around since |task_runner_| is assumed to be long-lived.
- muxer->SweepDeadBackends();
+// static
+Platform* Platform::GetDefaultPlatform() {
+ static PlatformWindows* thread_safe_init_instance = new PlatformWindows();
+ return thread_safe_init_instance;
+}
- // Make sure we eventually discard any per-thread trace writers from the
- // previous instance.
- muxer->muxer_id_for_testing_++;
+} // namespace perfetto
- g_prev_instance = muxer;
- instance_ = TracingMuxerFake::Get();
+// -----------------------
+// Thread-local destructor
+// -----------------------
- // Call the user provided cleanups on the muxer thread.
- for (auto& cb : muxer->reset_callbacks_) {
- cb();
- }
+// .CRT$XLA to .CRT$XLZ is an array of PIMAGE_TLS_CALLBACK pointers that are
+// called automatically by the OS loader code (not the CRT) when the module is
+// loaded and on thread creation. They are NOT called if the module has been
+// loaded by a LoadLibrary() call. It must have implicitly been loaded at
+// process startup.
+// See VC\crt\src\tlssup.c for reference.
- reset_done.Notify();
- };
+// extern "C" suppresses C++ name mangling so we know the symbol name for the
+// linker /INCLUDE:symbol pragma above.
+extern "C" {
+// The linker must not discard perfetto_thread_callback_base. (We force a
+// reference to this variable with a linker /INCLUDE:symbol pragma to ensure
+// that.) If this variable is discarded, the OnThreadExit function will never be
+// called.
- // Some tests run the muxer and the test on the same thread. In these cases,
- // we can reset synchronously.
- if (muxer->task_runner_->RunsTasksOnCurrentThread()) {
- do_reset();
- } else {
- muxer->DestroyStoppedTraceWritersForCurrentThread();
- muxer->task_runner_->PostTask(std::move(do_reset));
- reset_done.Wait();
- // Call the user provided cleanups also on this thread.
- for (auto& cb : muxer->reset_callbacks_) {
- cb();
- }
+void NTAPI PerfettoOnThreadExit(PVOID, DWORD, PVOID);
+void NTAPI PerfettoOnThreadExit(PVOID, DWORD reason, PVOID) {
+ if (reason == DLL_THREAD_DETACH || reason == DLL_PROCESS_DETACH) {
+ if (perfetto::PlatformWindows::instance)
+ perfetto::PlatformWindows::instance->OnThreadExit();
}
- muxer->reset_callbacks_.clear();
}
-// static
-void TracingMuxerImpl::Shutdown() {
- auto* muxer = reinterpret_cast<TracingMuxerImpl*>(instance_);
+#ifdef _WIN64
- // Shutting down on the muxer thread would lead to a deadlock.
- PERFETTO_CHECK(!muxer->task_runner_->RunsTasksOnCurrentThread());
- muxer->DestroyStoppedTraceWritersForCurrentThread();
+// .CRT section is merged with .rdata on x64 so it must be constant data.
+#pragma const_seg(".CRT$XLP")
- std::unique_ptr<base::TaskRunner> owned_task_runner(
- muxer->task_runner_.get());
- Platform* platform = muxer->platform_;
- base::WaitableEvent shutdown_done;
- owned_task_runner->PostTask([muxer, &shutdown_done] {
- // Check that no consumer session is currently active on any backend.
- // Producers will be automatically disconnected as a part of deleting the
- // muxer below.
- for (auto& backend : muxer->consumer_backends_) {
- for (auto& consumer : backend.consumers) {
- PERFETTO_CHECK(!consumer->service_);
- }
- }
- // Make sure no trace writers are lingering around on the muxer thread. Note
- // that we can't do this for any arbitrary thread in the process; it is the
- // caller's responsibility to clean them up before shutting down Perfetto.
- muxer->DestroyStoppedTraceWritersForCurrentThread();
- // The task runner must be deleted outside the muxer thread. This is done by
- // `owned_task_runner` above.
- muxer->task_runner_.release();
- delete muxer;
- instance_ = TracingMuxerFake::Get();
- shutdown_done.Notify();
- });
- shutdown_done.Wait();
+// When defining a const variable, it must have external linkage to be sure the
+// linker doesn't discard it.
+extern const PIMAGE_TLS_CALLBACK perfetto_thread_callback_base;
+const PIMAGE_TLS_CALLBACK perfetto_thread_callback_base = PerfettoOnThreadExit;
- // Join the muxer thread before the platform (and its TLS key) is destroyed.
- owned_task_runner.reset();
+// Reset the default section.
+#pragma const_seg()
- // On the calling thread, so the platform can free this thread's TLS object.
- platform->Shutdown();
-}
+#else // _WIN64
-void TracingMuxerImpl::AppendResetForTestingCallback(std::function<void()> cb) {
- reset_callbacks_.push_back(std::move(cb));
-}
+#pragma data_seg(".CRT$XLP")
+PIMAGE_TLS_CALLBACK perfetto_thread_callback_base = PerfettoOnThreadExit;
+// Reset the default section.
+#pragma data_seg()
-TracingMuxer::~TracingMuxer() = default;
+#endif // _WIN64
-static_assert(std::is_same<internal::BufferId, BufferID>::value,
- "public's BufferId and tracing/core's BufferID diverged");
+} // extern "C"
-} // namespace internal
-} // namespace perfetto
-// gen_amalgamated begin source: src/tracing/internal/track_event_internal.cc
-// gen_amalgamated begin header: include/perfetto/ext/base/no_destructor.h
+#endif // OS_WIN
+// gen_amalgamated begin source: src/tracing/traced_value.cc
/*
- * Copyright (C) 2019 The Android Open Source Project
+ * Copyright (C) 2021 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.
@@ -48974,68 +53861,175 @@ static_assert(std::is_same<internal::BufferId, BufferID>::value,
* limitations under the License.
*/
-#ifndef INCLUDE_PERFETTO_EXT_BASE_NO_DESTRUCTOR_H_
-#define INCLUDE_PERFETTO_EXT_BASE_NO_DESTRUCTOR_H_
+// gen_amalgamated expanded: #include "perfetto/tracing/traced_value.h"
-#include <new>
-#include <utility>
+// gen_amalgamated expanded: #include "perfetto/base/logging.h"
+// gen_amalgamated expanded: #include "perfetto/tracing/debug_annotation.h"
+// gen_amalgamated expanded: #include "perfetto/tracing/internal/track_event_interned_fields.h"
+// gen_amalgamated expanded: #include "protos/perfetto/trace/track_event/debug_annotation.pbzero.h"
namespace perfetto {
-namespace base {
-// Wrapper that can hold an object of type T, without invoking the contained
-// object's destructor when being destroyed. Useful for creating statics while
-// avoiding static destructors.
-//
-// Stores the object inline, and therefore doesn't incur memory allocation and
-// pointer indirection overheads.
-//
-// Example of use:
-//
-// const std::string& GetStr() {
-// static base::NoDestructor<std::string> s("hello");
-// return s.ref();
-// }
-//
-template <typename T>
-class NoDestructor {
- public:
- // Forward arguments to T's constructor. Note that this doesn't cover
- // construction from initializer lists.
- template <typename... Args>
- explicit NoDestructor(Args&&... args) {
- new (storage_) T(std::forward<Args>(args)...);
- }
+namespace internal {
- NoDestructor(const NoDestructor&) = delete;
- NoDestructor& operator=(const NoDestructor&) = delete;
- NoDestructor(NoDestructor&&) = delete;
- NoDestructor& operator=(NoDestructor&&) = delete;
+TracedValue CreateTracedValueFromProto(
+ protos::pbzero::DebugAnnotation* annotation,
+ EventContext* event_context) {
+ return TracedValue::CreateFromProto(annotation, event_context);
+}
- ~NoDestructor() = default;
+} // namespace internal
- /* To avoid type-punned pointer strict aliasing warnings on GCC6 and below
- * these need to be split over two lines. If they are collapsed onto one line.
- * return reinterpret_cast<const T*>(storage_);
- * The error fires.
- */
- const T& ref() const {
- auto* const cast = reinterpret_cast<const T*>(storage_);
- return *cast;
- }
- T& ref() {
- auto* const cast = reinterpret_cast<T*>(storage_);
- return *cast;
+// static
+TracedValue TracedValue::CreateFromProto(
+ protos::pbzero::DebugAnnotation* annotation,
+ EventContext* event_context) {
+ return TracedValue(annotation, event_context, nullptr);
+}
+
+TracedValue::TracedValue(TracedValue&&) = default;
+TracedValue::~TracedValue() = default;
+
+void TracedValue::WriteInt64(int64_t value) && {
+ PERFETTO_DCHECK(checked_scope_.is_active());
+ annotation_->set_int_value(value);
+}
+
+void TracedValue::WriteUInt64(uint64_t value) && {
+ PERFETTO_DCHECK(checked_scope_.is_active());
+ annotation_->set_uint_value(value);
+}
+
+void TracedValue::WriteDouble(double value) && {
+ PERFETTO_DCHECK(checked_scope_.is_active());
+ annotation_->set_double_value(value);
+}
+
+void TracedValue::WriteBoolean(bool value) && {
+ PERFETTO_DCHECK(checked_scope_.is_active());
+ annotation_->set_bool_value(value);
+}
+
+void TracedValue::WriteString(const char* value) && {
+ PERFETTO_DCHECK(checked_scope_.is_active());
+ annotation_->set_string_value(value);
+}
+
+void TracedValue::WriteString(const char* value, size_t len) && {
+ PERFETTO_DCHECK(checked_scope_.is_active());
+ annotation_->set_string_value(value, len);
+}
+
+void TracedValue::WriteString(const std::string& value) && {
+ PERFETTO_DCHECK(checked_scope_.is_active());
+ annotation_->set_string_value(value);
+}
+
+void TracedValue::WriteString(std::string_view value) && {
+ PERFETTO_DCHECK(checked_scope_.is_active());
+ annotation_->set_string_value(value.data(), value.size());
+}
+
+void TracedValue::WritePointer(const void* value) && {
+ PERFETTO_DCHECK(checked_scope_.is_active());
+ annotation_->set_pointer_value(reinterpret_cast<uint64_t>(value));
+}
+
+TracedDictionary TracedValue::WriteDictionary() && {
+ // Note: this passes |checked_scope_.is_active_| bit to the parent to be
+ // picked up later by the new TracedDictionary.
+ PERFETTO_DCHECK(checked_scope_.is_active());
+ checked_scope_.Reset();
+
+ PERFETTO_DCHECK(!annotation_->is_finalized());
+ return TracedDictionary(annotation_,
+ protos::pbzero::DebugAnnotation::kDictEntries,
+ event_context_, checked_scope_.parent_scope());
+}
+
+TracedArray TracedValue::WriteArray() && {
+ // Note: this passes |checked_scope_.is_active_| bit to the parent to be
+ // picked up later by the new TracedDictionary.
+ PERFETTO_DCHECK(checked_scope_.is_active());
+ checked_scope_.Reset();
+
+ PERFETTO_DCHECK(!annotation_->is_finalized());
+ return TracedArray(annotation_, event_context_,
+ checked_scope_.parent_scope());
+}
+
+protozero::Message* TracedValue::WriteProtoInternal(const char* name) {
+ if (event_context_) {
+ annotation_->set_proto_type_name_iid(
+ internal::InternedDebugAnnotationValueTypeName::Get(event_context_,
+ name));
+ } else {
+ annotation_->set_proto_type_name(name);
}
+ return annotation_->template BeginNestedMessage<protozero::Message>(
+ protos::pbzero::DebugAnnotation::kProtoValueFieldNumber);
+}
- private:
- alignas(T) char storage_[sizeof(T)];
-};
+TracedArray::TracedArray(TracedValue annotation)
+ : TracedArray(std::move(annotation).WriteArray()) {}
-} // namespace base
-} // namespace perfetto
+TracedValue TracedArray::AppendItem() {
+ PERFETTO_DCHECK(checked_scope_.is_active());
+ return TracedValue(annotation_->add_array_values(), event_context_,
+ &checked_scope_);
+}
-#endif // INCLUDE_PERFETTO_EXT_BASE_NO_DESTRUCTOR_H_
+TracedDictionary TracedArray::AppendDictionary() {
+ PERFETTO_DCHECK(checked_scope_.is_active());
+ return AppendItem().WriteDictionary();
+}
+
+TracedArray TracedArray::AppendArray() {
+ PERFETTO_DCHECK(checked_scope_.is_active());
+ return AppendItem().WriteArray();
+}
+
+TracedDictionary::TracedDictionary(TracedValue annotation)
+ : TracedDictionary(std::move(annotation).WriteDictionary()) {}
+
+TracedValue TracedDictionary::AddItem(StaticString key) {
+ PERFETTO_DCHECK(checked_scope_.is_active());
+ protos::pbzero::DebugAnnotation* item =
+ message_->BeginNestedMessage<protos::pbzero::DebugAnnotation>(field_id_);
+ item->set_name(key.value);
+ return TracedValue(item, event_context_, &checked_scope_);
+}
+
+TracedValue TracedDictionary::AddItem(DynamicString key) {
+ PERFETTO_DCHECK(checked_scope_.is_active());
+ protos::pbzero::DebugAnnotation* item =
+ message_->BeginNestedMessage<protos::pbzero::DebugAnnotation>(field_id_);
+ item->set_name(key.value);
+ return TracedValue(item, event_context_, &checked_scope_);
+}
+
+TracedDictionary TracedDictionary::AddDictionary(StaticString key) {
+ PERFETTO_DCHECK(checked_scope_.is_active());
+ return AddItem(key).WriteDictionary();
+}
+
+TracedDictionary TracedDictionary::AddDictionary(DynamicString key) {
+ PERFETTO_DCHECK(checked_scope_.is_active());
+ return AddItem(key).WriteDictionary();
+}
+
+TracedArray TracedDictionary::AddArray(StaticString key) {
+ PERFETTO_DCHECK(checked_scope_.is_active());
+ return AddItem(key).WriteArray();
+}
+
+TracedArray TracedDictionary::AddArray(DynamicString key) {
+ PERFETTO_DCHECK(checked_scope_.is_active());
+ return AddItem(key).WriteArray();
+}
+
+} // namespace perfetto
+// gen_amalgamated begin source: src/tracing/tracing.cc
/*
* Copyright (C) 2019 The Android Open Source Project
*
@@ -49052,655 +54046,581 @@ class NoDestructor {
* limitations under the License.
*/
-// gen_amalgamated expanded: #include "perfetto/tracing/internal/track_event_internal.h"
+// gen_amalgamated expanded: #include "perfetto/tracing/tracing.h"
+
+#include <atomic>
+#include <condition_variable>
+#include <mutex>
-// gen_amalgamated expanded: #include "perfetto/base/proc_utils.h"
// gen_amalgamated expanded: #include "perfetto/base/time.h"
// gen_amalgamated expanded: #include "perfetto/ext/base/no_destructor.h"
-// gen_amalgamated expanded: #include "perfetto/tracing/core/data_source_config.h"
-// gen_amalgamated expanded: #include "perfetto/tracing/data_source.h"
-// gen_amalgamated expanded: #include "perfetto/tracing/internal/track_event_interned_fields.h"
-// gen_amalgamated expanded: #include "perfetto/tracing/track_event.h"
-// gen_amalgamated expanded: #include "perfetto/tracing/track_event_category_registry.h"
-// gen_amalgamated expanded: #include "perfetto/tracing/track_event_interned_data_index.h"
-// gen_amalgamated expanded: #include "protos/perfetto/common/data_source_descriptor.gen.h"
-// gen_amalgamated expanded: #include "protos/perfetto/common/track_event_descriptor.pbzero.h"
-// gen_amalgamated expanded: #include "protos/perfetto/trace/clock_snapshot.pbzero.h"
-// gen_amalgamated expanded: #include "protos/perfetto/trace/interned_data/interned_data.pbzero.h"
-// gen_amalgamated expanded: #include "protos/perfetto/trace/trace_packet_defaults.pbzero.h"
-// gen_amalgamated expanded: #include "protos/perfetto/trace/track_event/debug_annotation.pbzero.h"
-// gen_amalgamated expanded: #include "protos/perfetto/trace/track_event/track_descriptor.pbzero.h"
-#if PERFETTO_BUILDFLAG(PERFETTO_OS_APPLE)
-#include <os/signpost.h>
-#endif
-
-using perfetto::protos::pbzero::ClockSnapshot;
+// gen_amalgamated expanded: #include "perfetto/ext/base/waitable_event.h"
+// gen_amalgamated expanded: #include "perfetto/tracing/internal/track_event_data_source.h"
+// gen_amalgamated expanded: #include "perfetto/tracing/internal/track_event_internal.h"
+// gen_amalgamated expanded: #include "src/tracing/internal/tracing_muxer_impl.h"
namespace perfetto {
+namespace {
+bool g_was_initialized = false;
-TrackEventSessionObserver::~TrackEventSessionObserver() = default;
-void TrackEventSessionObserver::OnSetup(const DataSourceBase::SetupArgs&) {}
-void TrackEventSessionObserver::OnStart(const DataSourceBase::StartArgs&) {}
-void TrackEventSessionObserver::OnStop(const DataSourceBase::StopArgs&) {}
-void TrackEventSessionObserver::WillClearIncrementalState(
- const DataSourceBase::ClearIncrementalStateArgs&) {}
+// Wrapped in a function to avoid global constructor
+std::mutex& InitializedMutex() {
+ static base::NoDestructor<std::mutex> initialized_mutex;
+ return initialized_mutex.ref();
+}
+} // namespace
-TrackEventTlsStateUserData::~TrackEventTlsStateUserData() = default;
+// static
+void Tracing::InitializeInternal(const TracingInitArgs& args) {
+ base::InitializeTime();
+ std::unique_lock<std::mutex> lock(InitializedMutex());
+ // If it's the first time Initialize is called, set some global params.
+ if (!g_was_initialized) {
+ // Make sure the headers and implementation files agree on the build config.
+ PERFETTO_CHECK(args.dcheck_is_on_ == PERFETTO_DCHECK_IS_ON());
+ if (args.log_message_callback) {
+ base::SetLogMessageCallback(args.log_message_callback);
+ }
-namespace internal {
+ if (args.use_monotonic_clock) {
+ PERFETTO_CHECK(!args.use_monotonic_raw_clock);
+ internal::TrackEventInternal::SetClockId(
+ protos::pbzero::BUILTIN_CLOCK_MONOTONIC);
+ } else if (args.use_monotonic_raw_clock) {
+ internal::TrackEventInternal::SetClockId(
+ protos::pbzero::BUILTIN_CLOCK_MONOTONIC_RAW);
+ }
-BaseTrackEventInternedDataIndex::~BaseTrackEventInternedDataIndex() = default;
+ if (args.disallow_merging_with_system_tracks) {
+ internal::TrackEventInternal::SetDisallowMergingWithSystemTracks(true);
+ }
-namespace {
+ internal::TrackEventInternal::SetBufferExhaustedPolicy(
+ args.track_event_buffer_exhausted_policy);
+ }
-static constexpr const char kSlowTag[] = "slow";
-static constexpr const char kDebugTag[] = "debug";
-static constexpr const char kFilteredEventName[] = "FILTERED";
+ internal::TracingMuxerImpl::InitializeInstance(args);
+ internal::TrackRegistry::InitializeInstance(args.process_uuid);
+ g_was_initialized = true;
+}
-constexpr auto kClockIdIncremental =
- TrackEventIncrementalState::kClockIdIncremental;
+// static
+bool Tracing::IsInitialized() {
+ std::unique_lock<std::mutex> lock(InitializedMutex());
+ return g_was_initialized;
+}
-constexpr auto kClockIdAbsolute = TrackEventIncrementalState::kClockIdAbsolute;
+// static
+void Tracing::Shutdown() {
+ std::unique_lock<std::mutex> lock(InitializedMutex());
+ if (!g_was_initialized)
+ return;
+ internal::TracingMuxerImpl::Shutdown();
+ g_was_initialized = false;
+}
-class TrackEventSessionObserverRegistry {
- public:
- static TrackEventSessionObserverRegistry* GetInstance() {
- static TrackEventSessionObserverRegistry* instance =
- new TrackEventSessionObserverRegistry(); // leaked
- return instance;
- }
+// static
+void Tracing::ResetForTesting() {
+ std::unique_lock<std::mutex> lock(InitializedMutex());
+ if (!g_was_initialized)
+ return;
+ base::SetLogMessageCallback(nullptr);
+ internal::TracingMuxerImpl::ResetForTesting();
+ internal::TrackRegistry::ResetForTesting();
+ internal::TrackEventDataSource::ResetForTesting();
+ g_was_initialized = false;
+}
- void AddObserverForRegistry(const TrackEventCategoryRegistry& registry,
- TrackEventSessionObserver* observer) {
- std::unique_lock<std::recursive_mutex> lock(mutex_);
- observers_.emplace_back(®istry, observer);
- }
+// static
+std::unique_ptr<TracingSession> Tracing::NewTraceInternal(
+ BackendType backend,
+ TracingConsumerBackend* (*system_backend_factory)()) {
+ return static_cast<internal::TracingMuxerImpl*>(internal::TracingMuxer::Get())
+ ->CreateTracingSession(backend, system_backend_factory);
+}
- void RemoveObserverForRegistry(const TrackEventCategoryRegistry& registry,
- TrackEventSessionObserver* observer) {
- std::unique_lock<std::recursive_mutex> lock(mutex_);
- observers_.erase(std::remove(observers_.begin(), observers_.end(),
- RegisteredObserver(®istry, observer)),
- observers_.end());
- }
+// static
+std::unique_ptr<StartupTracingSession> Tracing::SetupStartupTracing(
+ const TraceConfig& config,
+ Tracing::SetupStartupTracingOpts opts) {
+ return static_cast<internal::TracingMuxerImpl*>(internal::TracingMuxer::Get())
+ ->CreateStartupTracingSession(config, std::move(opts));
+}
- void ForEachObserverForRegistries(
- const std::vector<const TrackEventCategoryRegistry*>& registries,
- std::function<void(TrackEventSessionObserver*)> callback) {
- std::unique_lock<std::recursive_mutex> lock(mutex_);
- for (auto& registered_observer : observers_) {
- for (const auto* registry : registries) {
- if (registry == registered_observer.registry) {
- callback(registered_observer.observer);
- }
- }
- }
- }
+// static
+std::unique_ptr<StartupTracingSession> Tracing::SetupStartupTracingBlocking(
+ const TraceConfig& config,
+ Tracing::SetupStartupTracingOpts opts) {
+ return static_cast<internal::TracingMuxerImpl*>(internal::TracingMuxer::Get())
+ ->CreateStartupTracingSessionBlocking(config, std::move(opts));
+}
- private:
- struct RegisteredObserver {
- RegisteredObserver(const TrackEventCategoryRegistry* r,
- TrackEventSessionObserver* o)
- : registry(r), observer(o) {}
- bool operator==(const RegisteredObserver& other) {
- return registry == other.registry && observer == other.observer;
- }
- const TrackEventCategoryRegistry* registry;
- TrackEventSessionObserver* observer;
- };
+// static
+void Tracing::ActivateTriggers(const std::vector<std::string>& triggers,
+ uint32_t ttl_ms) {
+ internal::TracingMuxer::Get()->ActivateTriggers(triggers, ttl_ms);
+}
- std::recursive_mutex mutex_;
- std::vector<RegisteredObserver> observers_;
-};
+TracingSession::~TracingSession() = default;
-enum class MatchType { kExact, kPattern, kWildcard };
+void TracingSession::CloneTrace(CloneTraceArgs, CloneTraceCallback) {}
-bool NameMatchesPattern(const std::string& pattern,
- const std::string& name,
- MatchType match_type) {
- // To avoid pulling in all of std::regex, for now we only support a single "*"
- // wildcard at the end of the pattern.
- size_t i = pattern.find('*');
- if (i != std::string::npos) {
- PERFETTO_DCHECK(i == pattern.size() - 1);
- if (i == 0) {
- return match_type == MatchType::kWildcard;
- }
- if (match_type != MatchType::kPattern)
- return false;
- return name.substr(0, i) == pattern.substr(0, i);
+// Can be called from any thread.
+bool TracingSession::FlushBlocking(uint32_t timeout_ms) {
+ std::atomic<bool> flush_result;
+ base::WaitableEvent flush_ack;
+
+ // The non blocking Flush() can be called on any thread. It does the PostTask
+ // internally.
+ Flush(
+ [&flush_ack, &flush_result](bool res) {
+ flush_result = res;
+ flush_ack.Notify();
+ },
+ timeout_ms);
+ flush_ack.Wait();
+ return flush_result;
+}
+
+std::vector<char> TracingSession::ReadTraceBlocking() {
+ std::vector<char> raw_trace;
+ std::mutex mutex;
+ std::condition_variable cv;
+
+ bool all_read = false;
+
+ ReadTrace([&mutex, &raw_trace, &all_read, &cv](ReadTraceCallbackArgs cb) {
+ raw_trace.insert(raw_trace.end(), cb.data, cb.data + cb.size);
+ std::unique_lock<std::mutex> lock(mutex);
+ all_read = !cb.has_more;
+ if (all_read)
+ cv.notify_one();
+ });
+
+ {
+ std::unique_lock<std::mutex> lock(mutex);
+ cv.wait(lock, [&all_read] { return all_read; });
}
- return name == pattern;
+ return raw_trace;
}
-bool NameMatchesPatternList(const std::vector<std::string>& patterns,
- const std::string& name,
- MatchType match_type) {
- for (const auto& pattern : patterns) {
- if (NameMatchesPattern(pattern, name, match_type))
- return true;
+TracingSession::GetTraceStatsCallbackArgs
+TracingSession::GetTraceStatsBlocking() {
+ std::mutex mutex;
+ std::condition_variable cv;
+ GetTraceStatsCallbackArgs result;
+ bool stats_read = false;
+
+ GetTraceStats(
+ [&mutex, &result, &stats_read, &cv](GetTraceStatsCallbackArgs args) {
+ result = std::move(args);
+ std::unique_lock<std::mutex> lock(mutex);
+ stats_read = true;
+ cv.notify_one();
+ });
+
+ {
+ std::unique_lock<std::mutex> lock(mutex);
+ cv.wait(lock, [&stats_read] { return stats_read; });
}
- return false;
+ return result;
}
-} // namespace
+TracingSession::QueryServiceStateCallbackArgs
+TracingSession::QueryServiceStateBlocking() {
+ std::mutex mutex;
+ std::condition_variable cv;
+ QueryServiceStateCallbackArgs result;
+ bool status_read = false;
-TrackEventInternal& TrackEventInternal::GetInstance() {
- static base::NoDestructor<TrackEventInternal> state;
- return state.ref();
+ QueryServiceState(
+ [&mutex, &result, &status_read, &cv](QueryServiceStateCallbackArgs args) {
+ result = std::move(args);
+ std::unique_lock<std::mutex> lock(mutex);
+ status_read = true;
+ cv.notify_one();
+ });
+
+ {
+ std::unique_lock<std::mutex> lock(mutex);
+ cv.wait(lock, [&status_read] { return status_read; });
+ }
+ return result;
}
-// static
-const Track TrackEventInternal::kDefaultTrack{};
+StartupTracingSession::~StartupTracingSession() = default;
+
+} // namespace perfetto
+// gen_amalgamated begin source: src/tracing/tracing_policy.cc
+/*
+ * Copyright (C) 2021 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.
+ */
-// static
-std::atomic<int> TrackEventInternal::session_count_{};
+// gen_amalgamated expanded: #include "perfetto/tracing/tracing_policy.h"
-std::vector<const TrackEventCategoryRegistry*>
-TrackEventInternal::GetRegistries() {
- std::unique_lock<std::mutex> lock(mu_);
- return registries_;
-}
+namespace perfetto {
-std::vector<const TrackEventCategoryRegistry*> TrackEventInternal::AddRegistry(
- const TrackEventCategoryRegistry* registry) {
- std::unique_lock<std::mutex> lock(mu_);
- registries_.push_back(registry);
- return registries_;
-}
+TracingPolicy::~TracingPolicy() = default;
-void TrackEventInternal::ResetRegistriesForTesting() {
- std::unique_lock<std::mutex> lock(mu_);
- registries_.clear();
-}
+} // namespace perfetto
+// gen_amalgamated begin source: src/tracing/track.cc
+/*
+ * 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.
+ */
-// static
-bool TrackEventInternal::Initialize(
- const std::vector<const TrackEventCategoryRegistry*> registries,
- bool (*register_data_source)(const DataSourceDescriptor&)) {
- DataSourceDescriptor dsd;
- dsd.set_name("track_event");
+// gen_amalgamated expanded: #include "perfetto/tracing/track.h"
- protozero::HeapBuffered<protos::pbzero::TrackEventDescriptor> ted;
- for (const auto* registry : registries) {
- for (size_t i = 0; i < registry->category_count(); i++) {
- auto category = registry->GetCategory(i);
- // Don't register group categories.
- if (category->IsGroup())
- continue;
- auto cat = ted->add_available_categories();
- cat->set_name(category->name);
- if (category->description)
- cat->set_description(category->description);
- for (const auto& tag : category->tags) {
- if (tag) {
- cat->add_tags(tag);
- }
- }
- }
- }
- dsd.set_track_event_descriptor_raw(ted.SerializeAsString());
+// gen_amalgamated expanded: #include "perfetto/ext/base/file_utils.h"
+// gen_amalgamated expanded: #include "perfetto/ext/base/fnv_hash.h"
+// gen_amalgamated expanded: #include "perfetto/ext/base/scoped_file.h"
+// gen_amalgamated expanded: #include "perfetto/ext/base/string_splitter.h"
+// gen_amalgamated expanded: #include "perfetto/ext/base/string_utils.h"
+// gen_amalgamated expanded: #include "perfetto/ext/base/thread_utils.h"
+// gen_amalgamated expanded: #include "perfetto/ext/base/uuid.h"
+// gen_amalgamated expanded: #include "perfetto/tracing/internal/track_event_data_source.h"
+// gen_amalgamated expanded: #include "perfetto/tracing/internal/track_event_internal.h"
+// gen_amalgamated expanded: #include "protos/perfetto/trace/track_event/counter_descriptor.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/trace/track_event/process_descriptor.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/trace/track_event/process_descriptor.pbzero.h"
+// gen_amalgamated expanded: #include "protos/perfetto/trace/track_event/thread_descriptor.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/trace/track_event/thread_descriptor.pbzero.h"
- return register_data_source(dsd);
-}
+namespace perfetto {
// static
-bool TrackEventInternal::AddSessionObserver(
- const TrackEventCategoryRegistry& registry,
- TrackEventSessionObserver* observer) {
- TrackEventSessionObserverRegistry::GetInstance()->AddObserverForRegistry(
- registry, observer);
- return true;
-}
+uint64_t Track::process_uuid = 0;
-// static
-void TrackEventInternal::RemoveSessionObserver(
- const TrackEventCategoryRegistry& registry,
- TrackEventSessionObserver* observer) {
- TrackEventSessionObserverRegistry::GetInstance()->RemoveObserverForRegistry(
- registry, observer);
+protos::gen::TrackDescriptor Track::Serialize() const {
+ protos::gen::TrackDescriptor desc;
+ desc.set_uuid(uuid);
+ if (parent_uuid)
+ desc.set_parent_uuid(parent_uuid);
+ return desc;
}
-#if !PERFETTO_BUILDFLAG(PERFETTO_OS_APPLE) && \
- !PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
-static constexpr protos::pbzero::BuiltinClock kDefaultTraceClock =
- protos::pbzero::BUILTIN_CLOCK_BOOTTIME;
-#else
-static constexpr protos::pbzero::BuiltinClock kDefaultTraceClock =
- protos::pbzero::BUILTIN_CLOCK_MONOTONIC;
-#endif
-
-// static
-protos::pbzero::BuiltinClock TrackEventInternal::clock_ = kDefaultTraceClock;
-
-// static
-bool TrackEventInternal::disallow_merging_with_system_tracks_ = false;
+void Track::Serialize(protos::pbzero::TrackDescriptor* desc) const {
+ auto bytes = Serialize().SerializeAsString();
+ desc->AppendRawProtoBytes(bytes.data(), bytes.size());
+}
// static
-BufferExhaustedPolicy TrackEventInternal::buffer_exhausted_policy_ =
- BufferExhaustedPolicy::kDrop;
+Track Track::ThreadScoped(const void* ptr, Track parent) {
+ if (parent.uuid == 0)
+ return Track::FromPointer(ptr, ThreadTrack::Current());
+ return Track::FromPointer(ptr, parent);
+}
-// static
-void TrackEventInternal::EnableRegistry(
- const TrackEventCategoryRegistry* registry,
- const protos::gen::TrackEventConfig& config,
- uint32_t internal_instance_index) {
- for (size_t i = 0; i < registry->category_count(); i++) {
- if (IsCategoryEnabled(*registry, config, *registry->GetCategory(i))) {
- PERFETTO_DLOG("EnableRegistry %" PRIu32 " %zu", internal_instance_index,
- i);
- registry->EnableCategoryForInstance(i, internal_instance_index);
+protos::gen::TrackDescriptor ProcessTrack::Serialize() const {
+ auto desc = Track::Serialize();
+ auto pd = desc.mutable_process();
+ pd->set_pid(static_cast<int32_t>(pid));
+#if PERFETTO_BUILDFLAG(PERFETTO_OS_LINUX) || \
+ PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID)
+ std::string cmdline;
+ if (base::ReadFile("/proc/self/cmdline", &cmdline)) {
+ // Since cmdline is a zero-terminated list of arguments, this ends up
+ // writing just the first element, i.e., the process name, into the process
+ // name field.
+ pd->set_process_name(cmdline.c_str());
+ base::StringSplitter splitter(std::move(cmdline), '\0');
+ while (splitter.Next()) {
+ pd->add_cmdline(
+ std::string(splitter.cur_token(), splitter.cur_token_size()));
}
}
+ // TODO(skyostil): Record command line on Windows, FreeBSD and Mac.
+#endif
+ return desc;
}
-void TrackEventInternal::EnableTracing(
- const protos::gen::TrackEventConfig& config,
- const DataSourceBase::SetupArgs& args) {
- std::vector<const TrackEventCategoryRegistry*> registries;
- {
- std::unique_lock<std::mutex> lock(mu_);
- registries = registries_;
- for (const auto& registry : registries) {
- for (size_t i = 0; i < registry->category_count(); i++) {
- if (IsCategoryEnabled(*registry, config, *registry->GetCategory(i)))
- registry->EnableCategoryForInstance(i, args.internal_instance_index);
- }
- }
- }
- TrackEventSessionObserverRegistry::GetInstance()
- ->ForEachObserverForRegistries(
- registries, [&](TrackEventSessionObserver* o) { o->OnSetup(args); });
+void ProcessTrack::Serialize(protos::pbzero::TrackDescriptor* desc) const {
+ auto bytes = Serialize().SerializeAsString();
+ desc->AppendRawProtoBytes(bytes.data(), bytes.size());
}
-void TrackEventInternal::DisableTracing(uint32_t internal_instance_index) {
- std::unique_lock<std::mutex> lock(mu_);
- for (const auto& registry : registries_) {
- for (size_t i = 0; i < registry->category_count(); i++)
- registry->DisableCategoryForInstance(i, internal_instance_index);
+protos::gen::TrackDescriptor ThreadTrack::Serialize() const {
+ auto desc = Track::Serialize();
+ auto td = desc.mutable_thread();
+ td->set_pid(static_cast<int32_t>(pid));
+ td->set_tid(static_cast<int32_t>(tid));
+ if (disallow_merging_with_system_tracks) {
+ desc.set_disallow_merging_with_system_tracks(true);
}
+ std::string thread_name;
+ if (base::GetThreadName(thread_name))
+ td->set_thread_name(thread_name);
+ return desc;
}
// static
-void TrackEventInternal::OnStart(const DataSourceBase::StartArgs& args) {
- session_count_.fetch_add(1);
- TrackEventSessionObserverRegistry::GetInstance()
- ->ForEachObserverForRegistries(
- GetInstance().GetRegistries(),
- [&](TrackEventSessionObserver* o) { o->OnStart(args); });
+ThreadTrack ThreadTrack::Current() {
+ return ThreadTrack(
+ internal::TracingMuxer::Get()->GetCurrentThreadId(),
+ internal::TrackEventInternal::GetDisallowMergingWithSystemTracks());
}
// static
-void TrackEventInternal::OnStop(const DataSourceBase::StopArgs& args) {
- TrackEventSessionObserverRegistry::GetInstance()
- ->ForEachObserverForRegistries(
- GetInstance().GetRegistries(),
- [&](TrackEventSessionObserver* o) { o->OnStop(args); });
+ThreadTrack ThreadTrack::ForThread(base::PlatformThreadId tid_) {
+ return ThreadTrack(
+ tid_, internal::TrackEventInternal::GetDisallowMergingWithSystemTracks());
}
-// static
-void TrackEventInternal::WillClearIncrementalState(
- const DataSourceBase::ClearIncrementalStateArgs& args) {
- TrackEventSessionObserverRegistry::GetInstance()
- ->ForEachObserverForRegistries(GetInstance().GetRegistries(),
- [&](TrackEventSessionObserver* o) {
- o->WillClearIncrementalState(args);
- });
+void ThreadTrack::Serialize(protos::pbzero::TrackDescriptor* desc) const {
+ auto bytes = Serialize().SerializeAsString();
+ desc->AppendRawProtoBytes(bytes.data(), bytes.size());
}
-// static
-bool TrackEventInternal::IsCategoryEnabled(
- const TrackEventCategoryRegistry& registry,
- const protos::gen::TrackEventConfig& config,
- const Category& category) {
- // If this is a group category, check if any of its constituent categories are
- // enabled. If so, then this one is enabled too.
- if (category.IsGroup()) {
- bool result = false;
- category.ForEachGroupMember([&](const char* member_name, size_t name_size) {
- for (size_t i = 0; i < registry.category_count(); i++) {
- const auto ref_category = registry.GetCategory(i);
- // Groups can't refer to other groups.
- if (ref_category->IsGroup())
- continue;
- // Require an exact match.
- if (ref_category->name_size() != name_size ||
- strncmp(ref_category->name, member_name, name_size)) {
- continue;
- }
- if (IsCategoryEnabled(registry, config, *ref_category)) {
- result = true;
- // Break ForEachGroupMember() loop.
- return false;
- }
- break;
- }
- // No match? Must be a dynamic category.
- DynamicCategory dyn_category(std::string(member_name, name_size));
- Category ref_category{Category::FromDynamicCategory(dyn_category)};
- if (IsCategoryEnabled(registry, config, ref_category)) {
- result = true;
- // Break ForEachGroupMember() loop.
- return false;
- }
- // No match found => keep iterating.
- return true;
- });
- return result;
+protos::gen::TrackDescriptor NamedTrack::Serialize() const {
+ auto desc = NamedTrackBase::Serialize();
+ if (sibling_merge_behavior_ != perfetto::protos::gen::TrackDescriptor::
+ SIBLING_MERGE_BEHAVIOR_UNSPECIFIED) {
+ desc.set_sibling_merge_behavior(sibling_merge_behavior_);
}
-
- auto has_matching_tag = [&](std::function<bool(const char*)> matcher) {
- for (const auto& tag : category.tags) {
- if (!tag)
- break;
- if (matcher(tag))
- return true;
- }
- return false;
- };
-
- // First try exact matches, then pattern matches. Last, try the global
- // wildcard.
- const std::array<MatchType, 3> match_types = {
- {MatchType::kExact, MatchType::kPattern, MatchType::kWildcard}};
- for (auto match_type : match_types) {
- // 1. Enabled categories.
- if (NameMatchesPatternList(config.enabled_categories(), category.name,
- match_type)) {
- return true;
- }
-
- // 2. Disabled categories.
- if (NameMatchesPatternList(config.disabled_categories(), category.name,
- match_type)) {
- return false;
- }
-
- // 3. Disabled tags.
- if (has_matching_tag([&](const char* tag) {
- if (config.disabled_tags_size()) {
- return NameMatchesPatternList(config.disabled_tags(), tag,
- match_type);
- } else if (config.enabled_tags_size() == 0) {
- // The "slow" and "debug" tags are disabled by default.
- return NameMatchesPattern(kSlowTag, tag, match_type) ||
- NameMatchesPattern(kDebugTag, tag, match_type);
- }
- return false;
- })) {
- return false;
- }
-
- // 4. Enabled tags.
- if (has_matching_tag([&](const char* tag) {
- return NameMatchesPatternList(config.enabled_tags(), tag, match_type);
- })) {
- return true;
- }
+ if (sibling_merge_key_) {
+ desc.set_sibling_merge_key(sibling_merge_key_);
+ } else if (sibling_merge_key_int_.has_value()) {
+ desc.set_sibling_merge_key_int(*sibling_merge_key_int_);
}
-
- // If nothing matched, enable the category by default.
- return true;
-}
-
-// static
-uint64_t TrackEventInternal::GetTimeNs() {
- if (GetClockId() == protos::pbzero::BUILTIN_CLOCK_BOOTTIME)
- return static_cast<uint64_t>(perfetto::base::GetBootTimeNs().count());
- else if (GetClockId() == protos::pbzero::BUILTIN_CLOCK_MONOTONIC)
- return static_cast<uint64_t>(perfetto::base::GetWallTimeNs().count());
- PERFETTO_DCHECK(GetClockId() == protos::pbzero::BUILTIN_CLOCK_MONOTONIC_RAW);
- return static_cast<uint64_t>(perfetto::base::GetWallTimeRawNs().count());
-}
-
-// static
-TraceTimestamp TrackEventInternal::GetTraceTime() {
- return {kClockIdIncremental, GetTimeNs()};
+ return desc;
}
-// static
-int TrackEventInternal::GetSessionCount() {
- return session_count_.load();
+protos::gen::TrackDescriptor StateTrack::Serialize() const {
+ auto desc = NamedTrackBase::Serialize();
+ // Initialize the state submessage to mark this track as a StateTrack.
+ desc.mutable_state();
+ return desc;
}
-// static
-void TrackEventInternal::ResetIncrementalState(
- TraceWriterBase* trace_writer,
- TrackEventIncrementalState* incr_state,
- const TrackEventTlsState& tls_state,
- const TraceTimestamp& timestamp) {
- auto sequence_timestamp = timestamp;
- if (timestamp.clock_id != kClockIdIncremental) {
- sequence_timestamp = TrackEventInternal::GetTraceTime();
+protos::gen::TrackDescriptor CounterTrack::Serialize() const {
+ auto desc = Track::Serialize();
+ auto* counter = desc.mutable_counter();
+ if (static_name_) {
+ desc.set_static_name(static_name_.value);
+ } else {
+ desc.set_name(dynamic_name_.value);
}
- incr_state->last_timestamp_ns = sequence_timestamp.value;
- auto default_track = ThreadTrack::Current();
- auto ts_unit_multiplier = tls_state.timestamp_unit_multiplier;
- auto thread_time_counter_track =
- CounterTrack("thread_time", default_track)
- .set_is_incremental(true)
- .set_unit_multiplier(static_cast<int64_t>(ts_unit_multiplier))
- .set_type(protos::gen::CounterDescriptor::COUNTER_THREAD_TIME_NS);
+ if (category_)
+ counter->add_categories(category_);
+ if (unit_ != perfetto::protos::pbzero::CounterDescriptor::UNIT_UNSPECIFIED)
+ counter->set_unit(static_cast<protos::gen::CounterDescriptor_Unit>(unit_));
{
- // Mark any incremental state before this point invalid. Also set up
- // defaults so that we don't need to repeat constant data for each packet.
- auto packet = NewTracePacket(
- trace_writer, incr_state, tls_state, timestamp,
- protos::pbzero::TracePacket::SEQ_INCREMENTAL_STATE_CLEARED);
- auto defaults = packet->set_trace_packet_defaults();
- defaults->set_timestamp_clock_id(tls_state.default_clock);
- // Establish the default track for this event sequence.
- auto track_defaults = defaults->set_track_event_defaults();
- track_defaults->set_track_uuid(default_track.uuid);
- if (tls_state.enable_thread_time_sampling) {
- track_defaults->add_extra_counter_track_uuids(
- thread_time_counter_track.uuid);
- }
-
-#if PERFETTO_BUILDFLAG(PERFETTO_OS_APPLE)
- // Emit a MacOS point-of-interest signpost to synchronize Mac profiler time
- // with boot time.
- // TODO(leszeks): Consider allowing synchronization against other clocks
- // than boot time.
- static os_log_t log_handle = os_log_create(
- "dev.perfetto.clock_sync", OS_LOG_CATEGORY_POINTS_OF_INTEREST);
- os_signpost_event_emit(
- log_handle, OS_SIGNPOST_ID_EXCLUSIVE, "boottime", "%" PRId64,
- static_cast<uint64_t>(perfetto::base::GetBootTimeNs().count()));
-#endif
-
- if (tls_state.default_clock != static_cast<uint32_t>(GetClockId())) {
- ClockSnapshot* clocks = packet->set_clock_snapshot();
- // Trace clock.
- ClockSnapshot::Clock* trace_clock = clocks->add_clocks();
- trace_clock->set_clock_id(static_cast<uint32_t>(GetClockId()));
- trace_clock->set_timestamp(sequence_timestamp.value);
-
- if (PERFETTO_LIKELY(tls_state.default_clock == kClockIdIncremental)) {
- // Delta-encoded incremental clock in nanoseconds by default but
- // configurable by |tls_state.timestamp_unit_multiplier|.
- ClockSnapshot::Clock* clock_incremental = clocks->add_clocks();
- clock_incremental->set_clock_id(kClockIdIncremental);
- clock_incremental->set_timestamp(sequence_timestamp.value /
- ts_unit_multiplier);
- clock_incremental->set_is_incremental(true);
- clock_incremental->set_unit_multiplier_ns(ts_unit_multiplier);
- }
- if (ts_unit_multiplier > 1) {
- // absolute clock with custom timestamp_unit_multiplier.
- ClockSnapshot::Clock* absolute_clock = clocks->add_clocks();
- absolute_clock->set_clock_id(kClockIdAbsolute);
- absolute_clock->set_timestamp(sequence_timestamp.value /
- ts_unit_multiplier);
- absolute_clock->set_is_incremental(false);
- absolute_clock->set_unit_multiplier_ns(ts_unit_multiplier);
- }
+ // if |type| is set, we don't want to emit |unit_name|. Trace processor
+ // infers the track name from the type in that case.
+ if (type_ !=
+ perfetto::protos::gen::CounterDescriptor::COUNTER_UNSPECIFIED) {
+ counter->set_type(type_);
+ } else if (unit_name_) {
+ counter->set_unit_name(unit_name_);
}
}
+ if (unit_multiplier_ != 1)
+ counter->set_unit_multiplier(unit_multiplier_);
+ if (is_incremental_)
+ counter->set_is_incremental(is_incremental_);
+ return desc;
+}
- // Every thread should write a descriptor for its default track, because most
- // trace points won't explicitly reference it. We also write the process
- // descriptor from every thread that writes trace events to ensure it gets
- // emitted at least once.
- incr_state->seen_tracks.insert(default_track.uuid);
- WriteTrackDescriptor(default_track, trace_writer, incr_state, tls_state,
- sequence_timestamp);
-
- incr_state->seen_tracks.insert(ProcessTrack::Current().uuid);
- WriteTrackDescriptor(ProcessTrack::Current(), trace_writer, incr_state,
- tls_state, sequence_timestamp);
-
- if (tls_state.enable_thread_time_sampling) {
- WriteTrackDescriptor(thread_time_counter_track, trace_writer, incr_state,
- tls_state, sequence_timestamp);
- }
+void CounterTrack::Serialize(protos::pbzero::TrackDescriptor* desc) const {
+ auto bytes = Serialize().SerializeAsString();
+ desc->AppendRawProtoBytes(bytes.data(), bytes.size());
}
-// static
-protozero::MessageHandle<protos::pbzero::TracePacket>
-TrackEventInternal::NewTracePacket(TraceWriterBase* trace_writer,
- TrackEventIncrementalState* incr_state,
- const TrackEventTlsState& tls_state,
- TraceTimestamp timestamp,
- uint32_t seq_flags) {
- if (PERFETTO_UNLIKELY(tls_state.default_clock != kClockIdIncremental &&
- timestamp.clock_id == kClockIdIncremental)) {
- timestamp.clock_id = tls_state.default_clock;
- }
- auto packet = trace_writer->NewTracePacket();
- auto ts_unit_multiplier = tls_state.timestamp_unit_multiplier;
- if (PERFETTO_LIKELY(timestamp.clock_id == kClockIdIncremental)) {
- if (PERFETTO_LIKELY(incr_state->last_timestamp_ns <= timestamp.value)) {
- // No need to set the clock id here, since kClockIdIncremental is the
- // clock id assumed by default.
- auto time_diff_ns = timestamp.value - incr_state->last_timestamp_ns;
- auto time_diff_units = time_diff_ns / ts_unit_multiplier;
- packet->set_timestamp(time_diff_units);
- incr_state->last_timestamp_ns += time_diff_units * ts_unit_multiplier;
- } else {
- packet->set_timestamp(timestamp.value / ts_unit_multiplier);
- packet->set_timestamp_clock_id(ts_unit_multiplier == 1
- ? static_cast<uint32_t>(GetClockId())
- : kClockIdAbsolute);
- }
- } else if (PERFETTO_LIKELY(timestamp.clock_id == tls_state.default_clock)) {
- packet->set_timestamp(timestamp.value / ts_unit_multiplier);
- } else {
- packet->set_timestamp(timestamp.value);
- packet->set_timestamp_clock_id(timestamp.clock_id);
+namespace internal {
+namespace {
+
+uint64_t GetProcessStartTime() {
+#if !PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
+ std::string stat;
+ if (!base::ReadFile("/proc/self/stat", &stat))
+ return 0u;
+ // The stat file is a single line split into space-separated fields as "pid
+ // (comm) state ppid ...". However because the command name can contain any
+ // characters (including parentheses and spaces), we need to skip past it
+ // before parsing the rest of the fields. To do that, we look for the last
+ // instance of ") " (parentheses followed by space) and parse forward from
+ // that point.
+ size_t comm_end = stat.rfind(") ");
+ if (comm_end == std::string::npos)
+ return 0u;
+ stat = stat.substr(comm_end + strlen(") "));
+ base::StringSplitter splitter(stat, ' ');
+ for (size_t skip = 0; skip < 20; skip++) {
+ if (!splitter.Next())
+ return 0u;
}
- packet->set_sequence_flags(seq_flags);
- return packet;
+ return base::CStringToUInt64(splitter.cur_token()).value_or(0u);
+#else
+ return 0;
+#endif // !PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
}
+} // namespace
+
// static
-void TrackEventInternal::WriteEventName(StaticString event_name,
- perfetto::EventContext& event_ctx,
- const TrackEventTlsState&) {
- if (PERFETTO_LIKELY(event_name.value != nullptr)) {
- size_t name_iid = InternedEventName::Get(&event_ctx, event_name.value);
- event_ctx.event()->set_name_iid(name_iid);
- }
-}
+TrackRegistry* TrackRegistry::instance_;
+
+TrackRegistry::TrackRegistry() = default;
+TrackRegistry::~TrackRegistry() = default;
// static
-void TrackEventInternal::WriteEventName(perfetto::DynamicString event_name,
- perfetto::EventContext& event_ctx,
- const TrackEventTlsState& tls_state) {
- if (PERFETTO_UNLIKELY(tls_state.filter_dynamic_event_names)) {
- event_ctx.event()->set_name(kFilteredEventName,
- sizeof(kFilteredEventName) - 1);
+void TrackRegistry::InitializeInstance(std::optional<uint64_t> process_uuid) {
+ if (instance_)
+ return;
+ instance_ = new TrackRegistry();
+ if (process_uuid) {
+ Track::process_uuid = *process_uuid;
} else {
- event_ctx.event()->set_name(event_name.value, event_name.length);
+ Track::process_uuid = ComputeProcessUuid();
}
}
// static
-EventContext TrackEventInternal::WriteEvent(
- TraceWriterBase* trace_writer,
- TrackEventIncrementalState* incr_state,
- TrackEventTlsState& tls_state,
- const Category* category,
- perfetto::protos::pbzero::TrackEvent::Type type,
- const TraceTimestamp& timestamp,
- bool on_current_thread_track) {
- PERFETTO_DCHECK(!incr_state->was_cleared);
- auto packet = NewTracePacket(trace_writer, incr_state, tls_state, timestamp);
- EventContext ctx(std::move(packet), incr_state, &tls_state);
+uint64_t TrackRegistry::ComputeProcessUuid() {
+ // Use the process start time + pid as the unique identifier for this process.
+ // This ensures that if there are two independent copies of the Perfetto SDK
+ // in the same process (e.g., one in the app and another in a system
+ // framework), events emitted by each will be consistently interleaved on
+ // common thread and process tracks.
+ uint64_t random;
+ if (uint64_t start_time = GetProcessStartTime()) {
+ random = start_time;
+ } else {
+ // Fall back to a randomly generated identifier.
+ static uint64_t random_once = static_cast<uint64_t>(base::Uuidv4().lsb());
+ random = random_once;
+ }
+ return base::FnvHasher::Combine(random, Platform::GetCurrentProcessId());
+}
- auto track_event = ctx.event();
- if (type != protos::pbzero::TrackEvent::TYPE_UNSPECIFIED)
- track_event->set_type(type);
+void TrackRegistry::ResetForTesting() {
+ instance_->tracks_.clear();
+}
- if (tls_state.enable_thread_time_sampling && on_current_thread_track) {
- if (tls_state.thread_time_subsampling_ns == 0 ||
- incr_state->last_thread_time_timestamp_ns == 0 ||
- timestamp.value >= incr_state->last_thread_time_timestamp_ns +
- tls_state.thread_time_subsampling_ns) {
- auto thread_time_ns = base::GetThreadCPUTimeNs().count();
- auto thread_time_delta_ns =
- thread_time_ns - incr_state->last_thread_time_ns;
- incr_state->last_thread_time_ns = thread_time_ns;
- incr_state->last_thread_time_timestamp_ns = timestamp.value;
- track_event->add_extra_counter_values(
- thread_time_delta_ns /
- static_cast<int64_t>(tls_state.timestamp_unit_multiplier));
- } else {
- // When subsampling, the skip emitting values.
- track_event->add_extra_counter_values(0);
- }
- }
+void TrackRegistry::UpdateTrack(Track track,
+ const std::string& serialized_desc) {
+ std::lock_guard<std::mutex> lock(mutex_);
+ tracks_[track.uuid] = {serialized_desc, track.parent_uuid};
+}
- // We assume that |category| points to the string with static lifetime.
- // This means we can use their addresses as interning keys.
- // TODO(skyostil): Intern categories at compile time.
- if (category && type != protos::pbzero::TrackEvent::TYPE_SLICE_END &&
- type != protos::pbzero::TrackEvent::TYPE_COUNTER) {
- category->ForEachGroupMember(
- [&](const char* member_name, size_t name_size) {
- size_t category_iid =
- InternedEventCategory::Get(&ctx, member_name, name_size);
- track_event->add_category_iids(category_iid);
- return true;
- });
- }
- return ctx;
+void TrackRegistry::EraseTrack(Track track) {
+ std::lock_guard<std::mutex> lock(mutex_);
+ tracks_.erase(track.uuid);
}
// static
-protos::pbzero::DebugAnnotation* TrackEventInternal::AddDebugAnnotation(
- perfetto::EventContext* event_ctx,
- const char* name) {
- auto annotation = event_ctx->event()->add_debug_annotations();
- annotation->set_name_iid(InternedDebugAnnotationName::Get(event_ctx, name));
- return annotation;
+void TrackRegistry::WriteTrackDescriptor(
+ const SerializedTrackDescriptor& desc,
+ protozero::MessageHandle<protos::pbzero::TracePacket> packet) {
+ packet->AppendString(
+ perfetto::protos::pbzero::TracePacket::kTrackDescriptorFieldNumber, desc);
}
+} // namespace internal
+} // namespace perfetto
+// gen_amalgamated begin source: src/tracing/track_event_category_registry.cc
+/*
+ * 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.
+ */
+
+// gen_amalgamated expanded: #include "perfetto/tracing/track_event_category_registry.h"
+
+namespace perfetto {
+namespace {
+
+static constexpr const char kLegacySlowPrefix[] = "disabled-by-default-";
+static constexpr const char kSlowTag[] = "slow";
+
+} // namespace
+
// static
-protos::pbzero::DebugAnnotation* TrackEventInternal::AddDebugAnnotation(
- perfetto::EventContext* event_ctx,
- perfetto::DynamicString name) {
- auto annotation = event_ctx->event()->add_debug_annotations();
- annotation->set_name(name.value);
- return annotation;
+Category Category::FromDynamicCategory(const char* name) {
+ if (GetNthNameSize(1, name, name)) {
+ Category group(Group(name));
+ PERFETTO_DCHECK(group.name);
+ return group;
+ }
+ Category category(name);
+ PERFETTO_DCHECK(category.name);
+ // Disabled-by-default categories get a "slow" tag.
+ if (!strncmp(name, kLegacySlowPrefix, strlen(kLegacySlowPrefix))) {
+ return category.SetTags(kSlowTag);
+ }
+ return category;
}
-void TrackEventDataSource::OnStart(const DataSourceBase::StartArgs& args) {
- TrackEventInternal::OnStart(args);
+Category Category::FromDynamicCategory(
+ const DynamicCategory& dynamic_category) {
+ return FromDynamicCategory(dynamic_category.name.c_str());
}
-} // namespace internal
+namespace internal {
-PERFETTO_DEFINE_DATA_SOURCE_STATIC_MEMBERS_WITH_ATTRS(
- PERFETTO_EXPORT_COMPONENT,
- perfetto::internal::TrackEventDataSource,
- perfetto::internal::TrackEventDataSourceTraits);
+perfetto::DynamicCategory NullCategory(const perfetto::DynamicCategory&) {
+ return perfetto::DynamicCategory{};
+}
+
+void TrackEventCategoryRegistry::EnableCategoryForInstance(
+ size_t category_index,
+ uint32_t instance_index) const {
+ PERFETTO_DCHECK(instance_index < kMaxDataSourceInstances);
+ PERFETTO_DCHECK(category_index < category_count_);
+ // Matches the acquire_load in DataSource::Trace().
+ state_storage_[category_index].fetch_or(
+ static_cast<uint8_t>(1u << instance_index), std::memory_order_release);
+}
+
+void TrackEventCategoryRegistry::DisableCategoryForInstance(
+ size_t category_index,
+ uint32_t instance_index) const {
+ PERFETTO_DCHECK(instance_index < kMaxDataSourceInstances);
+ PERFETTO_DCHECK(category_index < category_count_);
+ // Matches the acquire_load in DataSource::Trace().
+ state_storage_[category_index].fetch_and(
+ static_cast<uint8_t>(~(1u << instance_index)), std::memory_order_release);
+}
+} // namespace internal
} // namespace perfetto
-// gen_amalgamated begin source: src/tracing/internal/track_event_interned_fields.cc
+// gen_amalgamated begin source: src/tracing/track_event_legacy.cc
/*
- * Copyright (C) 2021 The Android Open Source Project
+ * 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.
@@ -49715,62 +54635,357 @@ PERFETTO_DEFINE_DATA_SOURCE_STATIC_MEMBERS_WITH_ATTRS(
* limitations under the License.
*/
-// gen_amalgamated expanded: #include "perfetto/tracing/internal/track_event_interned_fields.h"
+// gen_amalgamated expanded: #include "perfetto/tracing/track_event_legacy.h"
+
+// gen_amalgamated expanded: #include "perfetto/ext/base/fnv_hash.h"
+// gen_amalgamated expanded: #include "perfetto/tracing/track.h"
namespace perfetto {
+namespace legacy {
+
+template <>
+ThreadTrack ConvertThreadId(const PerfettoLegacyCurrentThreadId&) {
+ // Because of the short-circuit in PERFETTO_INTERNAL_LEGACY_EVENT, we should
+ // never get here.
+ PERFETTO_DCHECK(false);
+ return ThreadTrack::Current();
+}
+
+} // namespace legacy
+
namespace internal {
-InternedEventCategory::~InternedEventCategory() = default;
+void LegacyTraceId::Write(protos::pbzero::TrackEvent::LegacyEvent* event,
+ uint32_t event_flags) const {
+ // Legacy flow events always use bind_id.
+ if (event_flags &
+ (legacy::kTraceEventFlagFlowOut | legacy::kTraceEventFlagFlowIn)) {
+ // Flow bind_ids don't have scopes, so we need to mangle in-process ones to
+ // avoid collisions.
+ if (id_flags_ & legacy::kTraceEventFlagHasLocalId) {
+ event->set_bind_id(raw_id_ ^ ProcessTrack::Current().uuid);
+ } else {
+ event->set_bind_id(raw_id_);
+ }
+ return;
+ }
-// static
-void InternedEventCategory::Add(protos::pbzero::InternedData* interned_data,
- size_t iid,
- const char* value,
- size_t length) {
- auto category = interned_data->add_event_categories();
- category->set_iid(iid);
- category->set_name(value, length);
+ uint32_t scope_flags = id_flags_ & (legacy::kTraceEventFlagHasId |
+ legacy::kTraceEventFlagHasLocalId |
+ legacy::kTraceEventFlagHasGlobalId);
+ uint64_t id = raw_id_;
+ if (scope_ && scope_flags != legacy::kTraceEventFlagHasGlobalId) {
+ id = base::FnvHasher::Combine(id, scope_);
+ }
+
+ switch (scope_flags) {
+ case legacy::kTraceEventFlagHasId:
+ event->set_unscoped_id(id);
+ break;
+ case legacy::kTraceEventFlagHasLocalId:
+ event->set_local_id(id);
+ break;
+ case legacy::kTraceEventFlagHasGlobalId:
+ event->set_global_id(id);
+ break;
+ }
+ if (scope_)
+ event->set_id_scope(scope_);
}
-InternedEventName::~InternedEventName() = default;
+} // namespace internal
+} // namespace perfetto
+// gen_amalgamated begin source: src/tracing/track_event_state_tracker.cc
+/*
+ * 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.
+ */
+
+// gen_amalgamated expanded: #include "perfetto/tracing/track_event_state_tracker.h"
+
+// gen_amalgamated expanded: #include "perfetto/ext/base/fnv_hash.h"
+// gen_amalgamated expanded: #include "perfetto/tracing/internal/track_event_internal.h"
+
+// gen_amalgamated expanded: #include "protos/perfetto/common/interceptor_descriptor.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/trace/clock_snapshot.pbzero.h"
+// gen_amalgamated expanded: #include "protos/perfetto/trace/interned_data/interned_data.pbzero.h"
+// gen_amalgamated expanded: #include "protos/perfetto/trace/trace_packet.pbzero.h"
+// gen_amalgamated expanded: #include "protos/perfetto/trace/trace_packet_defaults.pbzero.h"
+// gen_amalgamated expanded: #include "protos/perfetto/trace/track_event/debug_annotation.pbzero.h"
+// gen_amalgamated expanded: #include "protos/perfetto/trace/track_event/process_descriptor.pbzero.h"
+// gen_amalgamated expanded: #include "protos/perfetto/trace/track_event/thread_descriptor.pbzero.h"
+// gen_amalgamated expanded: #include "protos/perfetto/trace/track_event/track_descriptor.pbzero.h"
+// gen_amalgamated expanded: #include "protos/perfetto/trace/track_event/track_event.pbzero.h"
+
+namespace perfetto {
+
+using internal::TrackEventIncrementalState;
+
+TrackEventStateTracker::~TrackEventStateTracker() = default;
+TrackEventStateTracker::Delegate::~Delegate() = default;
// static
-void InternedEventName::Add(protos::pbzero::InternedData* interned_data,
- size_t iid,
- const char* value) {
- auto name = interned_data->add_event_names();
- name->set_iid(iid);
- name->set_name(value);
+void TrackEventStateTracker::ProcessTracePacket(
+ Delegate& delegate,
+ SequenceState& sequence_state,
+ const protos::pbzero::TracePacket_Decoder& packet) {
+ UpdateIncrementalState(delegate, sequence_state, packet);
+
+ if (!packet.has_track_event())
+ return;
+ perfetto::protos::pbzero::TrackEvent::Decoder track_event(
+ packet.track_event());
+
+ auto clock_id = packet.timestamp_clock_id();
+ if (!packet.has_timestamp_clock_id())
+ clock_id = sequence_state.default_clock_id;
+ uint64_t timestamp = packet.timestamp();
+ // TODO(mohitms): Incorporate unit multiplier as well.
+ if (clock_id == internal::TrackEventIncrementalState::kClockIdIncremental) {
+ timestamp += sequence_state.most_recent_absolute_time_ns;
+ sequence_state.most_recent_absolute_time_ns = timestamp;
+ }
+
+ Track* track = &sequence_state.track;
+ if (track_event.has_track_uuid()) {
+ auto* session_state = delegate.GetSessionState();
+ if (!session_state)
+ return; // Tracing must have ended.
+ track = &session_state->tracks[track_event.track_uuid()];
+ }
+
+ // We only log the first category of each event.
+ protozero::ConstChars category{};
+ uint64_t category_iid = 0;
+ if (auto iid_it = track_event.category_iids()) {
+ category_iid = *iid_it;
+ category.data = sequence_state.event_categories[category_iid].data();
+ category.size = sequence_state.event_categories[category_iid].size();
+ } else if (auto cat_it = track_event.categories()) {
+ category.data = reinterpret_cast<const char*>(cat_it->data());
+ category.size = cat_it->size();
+ }
+
+ protozero::ConstChars name{};
+ uint64_t name_iid = track_event.name_iid();
+ uint64_t name_hash = 0;
+ uint64_t duration = 0;
+ if (name_iid) {
+ name.data = sequence_state.event_names[name_iid].data();
+ name.size = sequence_state.event_names[name_iid].size();
+ } else if (track_event.has_name()) {
+ name.data = track_event.name().data;
+ name.size = track_event.name().size;
+ }
+
+ if (name.data) {
+ base::FnvHasher hash;
+ hash.Update(name.data, name.size);
+ name_hash = hash.digest();
+ }
+
+ size_t depth = track->stack.size();
+ switch (track_event.type()) {
+ case protos::pbzero::TrackEvent::TYPE_SLICE_BEGIN: {
+ StackFrame frame;
+ frame.timestamp = timestamp;
+ frame.name_hash = name_hash;
+ if (track_event.has_track_uuid()) {
+ frame.name = name.ToStdString();
+ frame.category = category.ToStdString();
+ } else {
+ frame.name_iid = name_iid;
+ frame.category_iid = category_iid;
+ }
+ track->stack.push_back(std::move(frame));
+ break;
+ }
+ case protos::pbzero::TrackEvent::TYPE_SLICE_END:
+ if (!track->stack.empty()) {
+ const auto& prev_frame = track->stack.back();
+ if (prev_frame.name_iid) {
+ name.data = sequence_state.event_names[prev_frame.name_iid].data();
+ name.size = sequence_state.event_names[prev_frame.name_iid].size();
+ } else {
+ name.data = prev_frame.name.data();
+ name.size = prev_frame.name.size();
+ }
+ name_hash = prev_frame.name_hash;
+ if (prev_frame.category_iid) {
+ category.data =
+ sequence_state.event_categories[prev_frame.category_iid].data();
+ category.size =
+ sequence_state.event_categories[prev_frame.category_iid].size();
+ } else {
+ category.data = prev_frame.category.data();
+ category.size = prev_frame.category.size();
+ }
+ duration = timestamp - prev_frame.timestamp;
+ depth--;
+ }
+ break;
+ case protos::pbzero::TrackEvent::TYPE_INSTANT:
+ break;
+ case protos::pbzero::TrackEvent::TYPE_COUNTER:
+ case protos::pbzero::TrackEvent::TYPE_UNSPECIFIED:
+ // TODO(skyostil): Support counters.
+ return;
+ }
+
+ ParsedTrackEvent parsed_event{track_event};
+ parsed_event.timestamp_ns = timestamp;
+ parsed_event.duration_ns = duration;
+ parsed_event.stack_depth = depth;
+ parsed_event.category = category;
+ parsed_event.name = name;
+ parsed_event.name_hash = name_hash;
+ delegate.OnTrackEvent(*track, parsed_event);
+
+ if (track_event.type() == protos::pbzero::TrackEvent::TYPE_SLICE_END &&
+ !track->stack.empty()) {
+ track->stack.pop_back();
+ }
}
-InternedDebugAnnotationName::~InternedDebugAnnotationName() = default;
+// static
+void TrackEventStateTracker::UpdateIncrementalState(
+ Delegate& delegate,
+ SequenceState& sequence_state,
+ const protos::pbzero::TracePacket_Decoder& packet) {
+#if PERFETTO_DCHECK_IS_ON()
+ if (!sequence_state.sequence_id) {
+ sequence_state.sequence_id = packet.trusted_packet_sequence_id();
+ } else {
+ PERFETTO_DCHECK(sequence_state.sequence_id ==
+ packet.trusted_packet_sequence_id());
+ }
+#endif
+
+ perfetto::protos::pbzero::ClockSnapshot::Decoder snapshot(
+ packet.clock_snapshot());
+ for (auto it = snapshot.clocks(); it; ++it) {
+ perfetto::protos::pbzero::ClockSnapshot::Clock::Decoder clock(*it);
+ // TODO(mohitms) : Handle the incremental clock other than default one.
+ if (clock.is_incremental() &&
+ clock.clock_id() ==
+ internal::TrackEventIncrementalState::kClockIdIncremental) {
+ sequence_state.most_recent_absolute_time_ns =
+ clock.timestamp() * clock.unit_multiplier_ns();
+ break;
+ }
+ }
+
+ if (packet.sequence_flags() &
+ perfetto::protos::pbzero::TracePacket::SEQ_INCREMENTAL_STATE_CLEARED) {
+ // Convert any existing event names and categories on the stack to
+ // non-interned strings so we can look up their names even after the
+ // incremental state is gone.
+ for (auto& frame : sequence_state.track.stack) {
+ if (frame.name_iid) {
+ frame.name = sequence_state.event_names[frame.name_iid];
+ frame.name_iid = 0u;
+ }
+ if (frame.category_iid) {
+ frame.category = sequence_state.event_categories[frame.category_iid];
+ frame.category_iid = 0u;
+ }
+ }
+ sequence_state.event_names.clear();
+ sequence_state.event_categories.clear();
+ sequence_state.debug_annotation_names.clear();
+ sequence_state.track.uuid = 0u;
+ sequence_state.track.index = 0u;
+ }
+ if (packet.has_interned_data()) {
+ perfetto::protos::pbzero::InternedData::Decoder interned_data(
+ packet.interned_data());
+ for (auto it = interned_data.event_names(); it; it++) {
+ perfetto::protos::pbzero::EventName::Decoder entry(*it);
+ sequence_state.event_names[entry.iid()] = entry.name().ToStdString();
+ }
+ for (auto it = interned_data.event_categories(); it; it++) {
+ perfetto::protos::pbzero::EventCategory::Decoder entry(*it);
+ sequence_state.event_categories[entry.iid()] = entry.name().ToStdString();
+ }
+ for (auto it = interned_data.debug_annotation_names(); it; it++) {
+ perfetto::protos::pbzero::DebugAnnotationName::Decoder entry(*it);
+ sequence_state.debug_annotation_names[entry.iid()] =
+ entry.name().ToStdString();
+ }
+ }
+ if (packet.has_trace_packet_defaults()) {
+ perfetto::protos::pbzero::TracePacketDefaults::Decoder defaults(
+ packet.trace_packet_defaults());
+ if (defaults.has_track_event_defaults()) {
+ perfetto::protos::pbzero::TrackEventDefaults::Decoder
+ track_event_defaults(defaults.track_event_defaults());
+ sequence_state.track.uuid = track_event_defaults.track_uuid();
+ if (defaults.has_timestamp_clock_id())
+ sequence_state.default_clock_id = defaults.timestamp_clock_id();
+ }
+ }
+ if (packet.has_track_descriptor()) {
+ perfetto::protos::pbzero::TrackDescriptor::Decoder track_descriptor(
+ packet.track_descriptor());
+ auto* session_state = delegate.GetSessionState();
+ auto& track = session_state->tracks[track_descriptor.uuid()];
+ if (!track.index)
+ track.index = static_cast<uint32_t>(session_state->tracks.size() + 1);
+ track.uuid = track_descriptor.uuid();
+
+ if (track_descriptor.has_name()) {
+ track.name = track_descriptor.name().ToStdString();
+ } else if (track_descriptor.has_static_name()) {
+ track.name = track_descriptor.static_name().ToStdString();
+ }
+ track.pid = 0;
+ track.tid = 0;
+ if (track_descriptor.has_process()) {
+ perfetto::protos::pbzero::ProcessDescriptor::Decoder process(
+ track_descriptor.process());
+ track.pid = process.pid();
+ if (track.name.empty())
+ track.name = process.process_name().ToStdString();
+ } else if (track_descriptor.has_thread()) {
+ perfetto::protos::pbzero::ThreadDescriptor::Decoder thread(
+ track_descriptor.thread());
+ track.pid = thread.pid();
+ track.tid = thread.tid();
+ if (track.name.empty())
+ track.name = thread.thread_name().ToStdString();
+ }
+ delegate.OnTrackUpdated(track);
-// static
-void InternedDebugAnnotationName::Add(
- protos::pbzero::InternedData* interned_data,
- size_t iid,
- const char* value) {
- auto name = interned_data->add_debug_annotation_names();
- name->set_iid(iid);
- name->set_name(value);
+ // Mirror properties to the default track of the sequence. Note that
+ // this does not catch updates to the default track written through other
+ // sequences.
+ if (track.uuid == sequence_state.track.uuid) {
+ sequence_state.track.index = track.index;
+ sequence_state.track.name = track.name;
+ sequence_state.track.pid = track.pid;
+ sequence_state.track.tid = track.tid;
+ sequence_state.track.user_data = track.user_data;
+ }
+ }
}
-InternedDebugAnnotationValueTypeName::~InternedDebugAnnotationValueTypeName() =
- default;
-
-// static
-void InternedDebugAnnotationValueTypeName::Add(
- protos::pbzero::InternedData* interned_data,
- size_t iid,
- const char* value) {
- auto name = interned_data->add_debug_annotation_value_type_names();
- name->set_iid(iid);
- name->set_name(value);
-}
+TrackEventStateTracker::ParsedTrackEvent::ParsedTrackEvent(
+ const perfetto::protos::pbzero::TrackEvent::Decoder& track_event_)
+ : track_event(track_event_) {}
-} // namespace internal
} // namespace perfetto
-// gen_amalgamated begin source: src/tracing/platform.cc
+// gen_amalgamated begin source: src/tracing/virtual_destructors.cc
/*
* Copyright (C) 2019 The Android Open Source Project
*
@@ -49787,34 +55002,47 @@ void InternedDebugAnnotationValueTypeName::Add(
* limitations under the License.
*/
-// gen_amalgamated expanded: #include "perfetto/tracing/platform.h"
// gen_amalgamated expanded: #include "perfetto/tracing/internal/tracing_tls.h"
-// gen_amalgamated expanded: #include "perfetto/tracing/trace_writer_base.h"
-
-namespace perfetto {
+// gen_amalgamated expanded: #include "perfetto/tracing/tracing.h"
+// gen_amalgamated expanded: #include "perfetto/tracing/tracing_backend.h"
-PlatformThreadLocalObject::~PlatformThreadLocalObject() = default;
-Platform::~Platform() = default;
+// This translation unit contains the definitions for the destructor of pure
+// virtual interfaces for the src/public:public target. The alternative would be
+// introducing a one-liner .cc file for each pure virtual interface, which is
+// overkill. This is for compliance with -Wweak-vtables.
-void Platform::Shutdown() {}
+namespace perfetto {
+namespace internal {
-base::PlatformThreadId Platform::GetCurrentThreadId() {
- return base::GetThreadId();
+TracingTLS::~TracingTLS() {
+ // Avoid entering trace points while the thread is being torn down.
+ // This is the problem: when a thread exits, the at-thread-exit destroys the
+ // TracingTLS. As part of that the various TraceWriter for the active data
+ // sources are destroyd. A TraceWriter dtor will issue a PostTask on the IPC
+ // thread to issue a final flush and unregister its ID with the service.
+ // The PostTask, in chromium, might have a trace event that will try to
+ // re-enter the tracing system.
+ // We fix this by resetting the TLS key to the TracingTLS object that is
+ // being destroyed in the platform impl (platform_posix.cc,
+ // platform_windows.cc, chromium's platform.cc). We carefully rely on the fact
+ // that all the tracing path that will be invoked during thread exit will
+ // early out if |is_in_trace_point| == true and will not depend on the other
+ // TLS state that has been destroyed.
+ is_in_trace_point = true;
}
-// static
-std::unique_ptr<PlatformThreadLocalObject>
-PlatformThreadLocalObject::CreateInstance() {
- return std::unique_ptr<PlatformThreadLocalObject>(new internal::TracingTLS());
-}
+} // namespace internal
-// static
-base::PlatformProcessId Platform::process_id_ = 0;
+TracingProducerBackend::~TracingProducerBackend() = default;
+TracingConsumerBackend::~TracingConsumerBackend() = default;
+TracingBackend::~TracingBackend() = default;
} // namespace perfetto
-// gen_amalgamated begin source: src/tracing/platform_posix.cc
+// gen_amalgamated begin source: src/android_stats/statsd_logging_helper.cc
+// gen_amalgamated begin header: src/android_stats/statsd_logging_helper.h
+// gen_amalgamated begin header: src/android_stats/perfetto_atoms.h
/*
- * Copyright (C) 2019 The Android Open Source Project
+ * 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.
@@ -49829,129 +55057,140 @@ base::PlatformProcessId Platform::process_id_ = 0;
* limitations under the License.
*/
-// gen_amalgamated expanded: #include "perfetto/base/build_config.h"
-
-#if PERFETTO_BUILDFLAG(PERFETTO_OS_LINUX) || \
- PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID) || \
- PERFETTO_BUILDFLAG(PERFETTO_OS_FUCHSIA) || \
- PERFETTO_BUILDFLAG(PERFETTO_OS_FREEBSD) || \
- PERFETTO_BUILDFLAG(PERFETTO_OS_APPLE)
+#ifndef SRC_ANDROID_STATS_PERFETTO_ATOMS_H_
+#define SRC_ANDROID_STATS_PERFETTO_ATOMS_H_
-// gen_amalgamated expanded: #include "perfetto/ext/base/file_utils.h"
-// gen_amalgamated expanded: #include "perfetto/ext/base/thread_task_runner.h"
-// gen_amalgamated expanded: #include "perfetto/tracing/internal/tracing_tls.h"
-// gen_amalgamated expanded: #include "perfetto/tracing/platform.h"
-// gen_amalgamated expanded: #include "perfetto/tracing/trace_writer_base.h"
+namespace perfetto {
-#include <pthread.h>
-#include <stdlib.h>
+// This must match the values of the PerfettoUploadEvent enum in:
+// frameworks/proto_logging/stats/atoms.proto
+enum class PerfettoStatsdAtom {
+ kUndefined = 0,
-namespace perfetto {
+ // Checkpoints inside perfetto_cmd before tracing is finished.
+ kTraceBegin = 1,
+ kBackgroundTraceBegin = 2,
+ kCmdCloneTraceBegin = 55,
+ kCmdCloneTriggerTraceBegin = 56,
+ kOnConnect = 3,
+ kCmdOnSessionClone = 58,
+ kCmdOnTriggerSessionClone = 59,
-namespace {
+ // Guardrails inside perfetto_cmd before tracing is finished.
+ kOnTimeout = 16,
-class PlatformPosix : public Platform {
- public:
- PlatformPosix();
- ~PlatformPosix() override;
+ // Checkpoints inside traced.
+ kTracedEnableTracing = 37,
+ kTracedStartTracing = 38,
+ kTracedDisableTracing = 39,
+ kTracedNotifyTracingDisabled = 40,
- ThreadLocalObject* GetOrCreateThreadLocalObject() override;
+ // Trigger checkpoints inside traced.
+ // These atoms are special because, along with the UUID,
+ // they log the trigger name.
+ kTracedTriggerStartTracing = 41,
+ kTracedTriggerStopTracing = 42,
+ kTracedTriggerCloneSnapshot = 53,
- std::unique_ptr<base::TaskRunner> CreateTaskRunner(
- const CreateTaskRunnerArgs&) override;
- std::string GetCurrentProcessName() override;
- void Shutdown() override;
+ // Guardrails inside traced.
+ kTracedEnableTracingExistingTraceSession = 18,
+ kTracedEnableTracingTooLongTrace = 19,
+ kTracedEnableTracingInvalidTriggerTimeout = 20,
+ kTracedEnableTracingDurationWithTrigger = 21,
+ kTracedEnableTracingStopTracingWriteIntoFile = 22,
+ kTracedEnableTracingDuplicateTriggerName = 23,
+ kTracedEnableTracingInvalidDeferredStart = 24,
+ kTracedEnableTracingInvalidBufferSize = 25,
+ kTracedEnableTracingBufferSizeTooLarge = 26,
+ kTracedEnableTracingTooManyBuffers = 27,
+ kTracedEnableTracingDuplicateSessionName = 28,
+ kTracedEnableTracingSessionNameTooRecent = 29,
+ kTracedEnableTracingTooManySessionsForUid = 30,
+ kTracedEnableTracingTooManyConcurrentSessions = 31,
+ kTracedEnableTracingInvalidFdOutputFile = 32,
+ kTracedEnableTracingFailedToCreateFile = 33,
+ kTracedEnableTracingOom = 34,
+ kTracedEnableTracingUnknown = 35,
+ kTracedStartTracingInvalidSessionState = 36,
+ kTracedEnableTracingInvalidFilter = 47,
+ kTracedEnableTracingOobTargetBuffer = 48,
+ kTracedEnableTracingInvalidTriggerMode = 52,
+ kTracedEnableTracingInvalidBrFilename = 54,
+ kTracedEnableTracingFailedSessionSemaphoreCheck = 57,
+ kTracedEnablePriorityBoostInvalidConfig = 61,
+ kTracedEnablePriorityBoostOtherError = 62,
+ kTracedEnableTracingExclusiveSessionRejected = 63,
+ kTracedEnableTracingExclusiveSessionNotAllowed = 64,
+ kTracedEnableTracingDuplicateBufferName = 65,
- private:
- pthread_key_t tls_key_{};
-};
+ // Checkpoints inside perfetto_cmd after tracing has finished.
+ kOnTracingDisabled = 4,
+ kFinalizeTraceAndExit = 11,
+ kCmdFwReportBegin = 49,
+ kRebootTraceRecovered = 66,
+ kRebootTraceUploadTimeout = 67,
+ kRebootTraceUploadLeftover = 68,
+ kRebootTraceParseFailed = 69,
+ // Will be removed once incidentd is no longer used.
+ kUploadIncidentBegin = 8,
+ kNotUploadingEmptyTrace = 17,
-PlatformPosix* g_instance = nullptr;
+ // Guardrails inside perfetto_cmd after tracing has finished.
+ kCmdFwReportEmptyTrace = 50,
+ // Will be removed once incidentd is no longer used.
+ kUploadIncidentFailure = 10,
-using ThreadLocalObject = Platform::ThreadLocalObject;
+ // "Successful" terminal states inside perfetto_cmd.
+ kCmdFwReportHandoff = 51,
-PlatformPosix::PlatformPosix() {
- PERFETTO_CHECK(!g_instance);
- g_instance = this;
- auto tls_dtor = [](void* obj) {
- // The Posix TLS implementation resets the key before calling this dtor.
- // Here we re-reset it to the object we are about to delete. This is to
- // handle re-entrant usages of tracing in the PostTask done during the dtor
- // (see comments in TracingTLS::~TracingTLS()). Chromium's platform
- // implementation (which does NOT use this platform impl) has a similar
- // workaround (https://crrev.com/c/2748300).
- pthread_setspecific(g_instance->tls_key_, obj);
- delete static_cast<ThreadLocalObject*>(obj);
- pthread_setspecific(g_instance->tls_key_, nullptr);
- };
- PERFETTO_CHECK(pthread_key_create(&tls_key_, tls_dtor) == 0);
-}
+ // Deprecated as "success" is misleading; it simply means we were
+ // able to communicate with incidentd. Will be removed once
+ // incidentd is no longer used.
+ kUploadIncidentSuccess = 9,
-PlatformPosix::~PlatformPosix() {
- // pthread_key_delete doesn't call destructors, so do it manually for the
- // calling thread.
- void* tls_ptr = pthread_getspecific(tls_key_);
- delete static_cast<ThreadLocalObject*>(tls_ptr);
+ // Contained trigger begin/success/failure. Replaced by
+ // |PerfettoTriggerAtom| to allow aggregation using a count metric
+ // and reduce spam.
+ // reserved 12, 13, 14;
- pthread_key_delete(tls_key_);
- g_instance = nullptr;
-}
+ // Contained that a guardrail in perfetto_cmd was hit. Replaced with
+ // kCmd* guardrails.
+ // reserved 15;
-void PlatformPosix::Shutdown() {
- PERFETTO_CHECK(g_instance == this);
- delete this;
- PERFETTO_CHECK(!g_instance);
- // We're not clearing out the instance in GetDefaultPlatform() since it's not
- // possible to re-initialize Perfetto after calling this function anyway.
-}
+ // Contained status of Dropbox uploads. Removed as Perfetto no
+ // longer supports uploading traces using Dropbox.
+ // reserved 5, 6, 7;
-ThreadLocalObject* PlatformPosix::GetOrCreateThreadLocalObject() {
- // In chromium this should be implemented using base::ThreadLocalStorage.
- void* tls_ptr = pthread_getspecific(tls_key_);
+ // Contained status of guardrail state initialization and upload limit in
+ // perfetto_cmd. Removed as perfetto no longer manages stateful guardrails
+ // reserved 44, 45, 46;
- // This is needed to handle re-entrant calls during TLS dtor.
- // See comments in platform.cc and aosp/1712371 .
- ThreadLocalObject* tls = static_cast<ThreadLocalObject*>(tls_ptr);
- if (!tls) {
- tls = ThreadLocalObject::CreateInstance().release();
- pthread_setspecific(tls_key_, tls);
- }
- return tls;
-}
+ // Contained the guardrail for user build tracing. Removed as this guardrail
+ // causes more problem than it solves these days.
+ // reserved 43;
+};
-std::unique_ptr<base::TaskRunner> PlatformPosix::CreateTaskRunner(
- const CreateTaskRunnerArgs& args) {
- return std::unique_ptr<base::TaskRunner>(new base::ThreadTaskRunner(
- base::ThreadTaskRunner::CreateAndStart(args.name_for_debugging)));
-}
+// This must match the values of the PerfettoTrigger::TriggerType enum in:
+// frameworks/proto_logging/stats/atoms.proto
+enum PerfettoTriggerAtom {
+ kUndefined = 0,
-std::string PlatformPosix::GetCurrentProcessName() {
-#if PERFETTO_BUILDFLAG(PERFETTO_OS_LINUX) || \
- PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID)
- std::string cmdline;
- base::ReadFile("/proc/self/cmdline", &cmdline);
- return cmdline.substr(0, cmdline.find('\0'));
-#elif PERFETTO_BUILDFLAG(PERFETTO_OS_APPLE) || \
- PERFETTO_BUILDFLAG(PERFETTO_OS_FREEBSD)
- return std::string(getprogname());
-#else
- return "unknown_producer";
-#endif
-}
+ kTracedLimitProbability = 5,
+ kTracedLimitMaxPer24h = 6,
-} // namespace
+ kTracedTrigger = 9,
-// static
-Platform* Platform::GetDefaultPlatform() {
- static PlatformPosix* instance = new PlatformPosix();
- return instance;
-}
+ // Contained events of logging triggers through perfetto_cmd, probes and
+ // trigger_perfetto.
+ // Removed in W (Oct 2024) and replaced by |kTracedTrigger|.
+ // reserved 1, 2, 3, 4, 7, 8
+};
} // namespace perfetto
-#endif // OS_LINUX || OS_ANDROID || OS_APPLE || OS_FUCHSIA
-// gen_amalgamated begin source: src/tracing/platform_windows.cc
+
+#endif // SRC_ANDROID_STATS_PERFETTO_ATOMS_H_
/*
- * Copyright (C) 2021 The Android Open Source Project
+ * 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.
@@ -49966,171 +55205,110 @@ Platform* Platform::GetDefaultPlatform() {
* limitations under the License.
*/
-// gen_amalgamated expanded: #include "perfetto/base/build_config.h"
-
-#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
-
-#include <windows.h>
-
-// gen_amalgamated expanded: #include "perfetto/ext/base/thread_task_runner.h"
-// gen_amalgamated expanded: #include "perfetto/tracing/internal/tracing_tls.h"
-// gen_amalgamated expanded: #include "perfetto/tracing/platform.h"
+#ifndef SRC_ANDROID_STATS_STATSD_LOGGING_HELPER_H_
+#define SRC_ANDROID_STATS_STATSD_LOGGING_HELPER_H_
-// Thread Termination Callbacks.
-// Windows doesn't support a per-thread destructor with its
-// TLS primitives. So, we build it manually by inserting a
-// function to be called on each thread's exit.
-// This magic is from chromium's base/threading/thread_local_storage_win.cc
-// which in turn is from http://www.codeproject.com/threads/tls.asp.
+#include <stdint.h>
+#include <optional>
+#include <string>
+#include <vector>
-#ifdef _WIN64
-#pragma comment(linker, "/INCLUDE:_tls_used")
-#pragma comment(linker, "/INCLUDE:perfetto_thread_callback_base")
-#else
-#pragma comment(linker, "/INCLUDE:__tls_used")
-#pragma comment(linker, "/INCLUDE:_perfetto_thread_callback_base")
-#endif
+// gen_amalgamated expanded: #include "src/android_stats/perfetto_atoms.h"
namespace perfetto {
+namespace android_stats {
-namespace {
-
-class PlatformWindows : public Platform {
- public:
- static PlatformWindows* instance;
- PlatformWindows();
- ~PlatformWindows() override;
-
- ThreadLocalObject* GetOrCreateThreadLocalObject() override;
- std::unique_ptr<base::TaskRunner> CreateTaskRunner(
- const CreateTaskRunnerArgs&) override;
- std::string GetCurrentProcessName() override;
- void OnThreadExit();
-
- private:
- DWORD tls_key_{};
-};
-
-using ThreadLocalObject = Platform::ThreadLocalObject;
-
-// static
-PlatformWindows* PlatformWindows::instance = nullptr;
-
-PlatformWindows::PlatformWindows() {
- instance = this;
- tls_key_ = ::TlsAlloc();
- PERFETTO_CHECK(tls_key_ != TLS_OUT_OF_INDEXES);
-}
-
-PlatformWindows::~PlatformWindows() {
- // TlsFree doesn't call destructors, so do it manually for the calling
- // thread.
- OnThreadExit();
- ::TlsFree(tls_key_);
- instance = nullptr;
-}
-
-void PlatformWindows::OnThreadExit() {
- auto tls = static_cast<ThreadLocalObject*>(::TlsGetValue(tls_key_));
- if (tls) {
- // At this point we rely on the TLS object to be still set to the TracingTLS
- // we are deleting. See comments in TracingTLS::~TracingTLS().
- delete tls;
- }
-}
-
-ThreadLocalObject* PlatformWindows::GetOrCreateThreadLocalObject() {
- void* tls_ptr = ::TlsGetValue(tls_key_);
-
- auto* tls = static_cast<ThreadLocalObject*>(tls_ptr);
- if (!tls) {
- tls = ThreadLocalObject::CreateInstance().release();
- ::TlsSetValue(tls_key_, tls);
- }
- return tls;
-}
-
-std::unique_ptr<base::TaskRunner> PlatformWindows::CreateTaskRunner(
- const CreateTaskRunnerArgs& args) {
- return std::unique_ptr<base::TaskRunner>(new base::ThreadTaskRunner(
- base::ThreadTaskRunner::CreateAndStart(args.name_for_debugging)));
-}
-
-std::string PlatformWindows::GetCurrentProcessName() {
- char buf[MAX_PATH];
- auto len = ::GetModuleFileNameA(nullptr /*current*/, buf, sizeof(buf));
- std::string name(buf, static_cast<size_t>(len));
- size_t sep = name.find_last_of('\\');
- if (sep != std::string::npos)
- name = name.substr(sep + 1);
- return name;
-}
+// Functions in this file are only active on built in the Android
+// tree. On other platforms (including Android standalone and Chromium
+// on Android) these functions are a noop.
-} // namespace
+// Logs the upload event to statsd if built in the Android tree.
+void MaybeLogUploadEvent(PerfettoStatsdAtom atom,
+ int64_t uuid_lsb,
+ int64_t uuid_msb,
+ const std::string& trigger_name = "");
-// static
-Platform* Platform::GetDefaultPlatform() {
- static PlatformWindows* thread_safe_init_instance = new PlatformWindows();
- return thread_safe_init_instance;
-}
+// Logs the trigger events to statsd if built in the Android tree.
+void MaybeLogTriggerEvent(PerfettoTriggerAtom atom,
+ int64_t uuid_lsb,
+ const std::string& trigger);
+} // namespace android_stats
} // namespace perfetto
-// -----------------------
-// Thread-local destructor
-// -----------------------
-
-// .CRT$XLA to .CRT$XLZ is an array of PIMAGE_TLS_CALLBACK pointers that are
-// called automatically by the OS loader code (not the CRT) when the module is
-// loaded and on thread creation. They are NOT called if the module has been
-// loaded by a LoadLibrary() call. It must have implicitly been loaded at
-// process startup.
-// See VC\crt\src\tlssup.c for reference.
-
-// extern "C" suppresses C++ name mangling so we know the symbol name for the
-// linker /INCLUDE:symbol pragma above.
-extern "C" {
-// The linker must not discard perfetto_thread_callback_base. (We force a
-// reference to this variable with a linker /INCLUDE:symbol pragma to ensure
-// that.) If this variable is discarded, the OnThreadExit function will never be
-// called.
+#endif // SRC_ANDROID_STATS_STATSD_LOGGING_HELPER_H_
+/*
+ * 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.
+ */
-void NTAPI PerfettoOnThreadExit(PVOID, DWORD, PVOID);
-void NTAPI PerfettoOnThreadExit(PVOID, DWORD reason, PVOID) {
- if (reason == DLL_THREAD_DETACH || reason == DLL_PROCESS_DETACH) {
- if (perfetto::PlatformWindows::instance)
- perfetto::PlatformWindows::instance->OnThreadExit();
- }
-}
+// gen_amalgamated expanded: #include "src/android_stats/statsd_logging_helper.h"
-#ifdef _WIN64
+#include <cstdint>
+#include <string>
+#include <vector>
-// .CRT section is merged with .rdata on x64 so it must be constant data.
-#pragma const_seg(".CRT$XLP")
+// gen_amalgamated expanded: #include "perfetto/base/build_config.h"
+// gen_amalgamated expanded: #include "src/android_stats/perfetto_atoms.h"
-// When defining a const variable, it must have external linkage to be sure the
-// linker doesn't discard it.
-extern const PIMAGE_TLS_CALLBACK perfetto_thread_callback_base;
-const PIMAGE_TLS_CALLBACK perfetto_thread_callback_base = PerfettoOnThreadExit;
+#if PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID) && \
+ PERFETTO_BUILDFLAG(PERFETTO_ANDROID_BUILD)
+// gen_amalgamated expanded: #include "src/android_internal/lazy_library_loader.h" // nogncheck
+// gen_amalgamated expanded: #include "src/android_internal/statsd_logging.h" // nogncheck
+#endif
-// Reset the default section.
-#pragma const_seg()
+namespace perfetto::android_stats {
-#else // _WIN64
+// Make sure we don't accidentally log on non-Android tree build. Note that even
+// removing this ifdef still doesn't make uploads work on OS_ANDROID.
+// PERFETTO_LAZY_LOAD will return a nullptr on non-Android and non-in-tree
+// builds as libperfetto_android_internal will not be available.
+#if PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID) && \
+ PERFETTO_BUILDFLAG(PERFETTO_ANDROID_BUILD)
-#pragma data_seg(".CRT$XLP")
-PIMAGE_TLS_CALLBACK perfetto_thread_callback_base = PerfettoOnThreadExit;
-// Reset the default section.
-#pragma data_seg()
+void MaybeLogUploadEvent(PerfettoStatsdAtom atom,
+ int64_t uuid_lsb,
+ int64_t uuid_msb,
+ const std::string& trigger_name) {
+ PERFETTO_LAZY_LOAD(android_internal::StatsdLogUploadEvent, log_event_fn);
+ if (log_event_fn) {
+ log_event_fn(atom, uuid_lsb, uuid_msb, trigger_name.c_str());
+ }
+}
-#endif // _WIN64
+void MaybeLogTriggerEvent(PerfettoTriggerAtom atom,
+ int64_t uuid_lsb,
+ const std::string& trigger_name) {
+ PERFETTO_LAZY_LOAD(android_internal::StatsdLogTriggerEvent, log_event_fn);
+ if (log_event_fn) {
+ log_event_fn(atom, uuid_lsb, trigger_name.c_str());
+ }
+}
-} // extern "C"
+#else
+void MaybeLogUploadEvent(PerfettoStatsdAtom,
+ int64_t,
+ int64_t,
+ const std::string&) {}
+void MaybeLogTriggerEvent(PerfettoTriggerAtom, int64_t, const std::string&) {}
+#endif
-#endif // OS_WIN
-// gen_amalgamated begin source: src/tracing/traced_value.cc
+} // namespace perfetto::android_stats
+// gen_amalgamated begin source: src/base/regex/regex.cc
+// gen_amalgamated begin header: include/perfetto/ext/base/regex.h
/*
- * Copyright (C) 2021 The Android Open Source Project
+ * Copyright (C) 2026 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.
@@ -50145,177 +55323,180 @@ PIMAGE_TLS_CALLBACK perfetto_thread_callback_base = PerfettoOnThreadExit;
* limitations under the License.
*/
-// gen_amalgamated expanded: #include "perfetto/tracing/traced_value.h"
-
-// gen_amalgamated expanded: #include "perfetto/base/logging.h"
-// gen_amalgamated expanded: #include "perfetto/tracing/debug_annotation.h"
-// gen_amalgamated expanded: #include "perfetto/tracing/internal/track_event_interned_fields.h"
-// gen_amalgamated expanded: #include "protos/perfetto/trace/track_event/debug_annotation.pbzero.h"
-
-namespace perfetto {
-
-namespace internal {
-
-TracedValue CreateTracedValueFromProto(
- protos::pbzero::DebugAnnotation* annotation,
- EventContext* event_context) {
- return TracedValue::CreateFromProto(annotation, event_context);
-}
-
-} // namespace internal
-
-// static
-TracedValue TracedValue::CreateFromProto(
- protos::pbzero::DebugAnnotation* annotation,
- EventContext* event_context) {
- return TracedValue(annotation, event_context, nullptr);
-}
-
-TracedValue::TracedValue(TracedValue&&) = default;
-TracedValue::~TracedValue() = default;
-
-void TracedValue::WriteInt64(int64_t value) && {
- PERFETTO_DCHECK(checked_scope_.is_active());
- annotation_->set_int_value(value);
-}
+#ifndef INCLUDE_PERFETTO_EXT_BASE_REGEX_H_
+#define INCLUDE_PERFETTO_EXT_BASE_REGEX_H_
-void TracedValue::WriteUInt64(uint64_t value) && {
- PERFETTO_DCHECK(checked_scope_.is_active());
- annotation_->set_uint_value(value);
-}
+#include <cstdint>
+#include <memory>
+#include <optional>
+#include <string>
+#include <string_view>
+#include <vector>
-void TracedValue::WriteDouble(double value) && {
- PERFETTO_DCHECK(checked_scope_.is_active());
- annotation_->set_double_value(value);
-}
+// gen_amalgamated expanded: #include "perfetto/ext/base/status_or.h"
-void TracedValue::WriteBoolean(bool value) && {
- PERFETTO_DCHECK(checked_scope_.is_active());
- annotation_->set_bool_value(value);
-}
+namespace perfetto {
+namespace base {
-void TracedValue::WriteString(const char* value) && {
- PERFETTO_DCHECK(checked_scope_.is_active());
- annotation_->set_string_value(value);
-}
+// Pimpl for the regex engine. Defined in src/base/regex/regex.cc.
+class RegexImpl;
-void TracedValue::WriteString(const char* value, size_t len) && {
- PERFETTO_DCHECK(checked_scope_.is_active());
- annotation_->set_string_value(value, len);
-}
+// A regular expression abstraction that hides the underlying engine.
+//
+// Construct via the two static factories:
+// - Create() – fallible; returns StatusOr<Regex>.
+// - CreateOrCheck() – infallible; crashes on invalid pattern.
+// Use for compile-time constant patterns only.
+//
+// Regex is movable but NOT copyable. Use CopyableRegex when copy semantics
+// are needed (e.g. for storage in copyable containers).
+//
+// Patterns use ECMAScript syntax, supporting Perl-style shorthands (\d, \w,
+// \s).
+//
+// Operations:
+// GlobalReplace() – global substitution; returns a new string.
+// FullMatch() – anchored, no groups.
+// FullMatchWithGroups() – anchored, with capture groups.
+// PartialMatch() – unanchored, no groups.
+// PartialMatchWithGroups() – unanchored, with capture groups.
+// PartialMatchAll() – iterator over all non-overlapping matches.
+class Regex {
+ public:
+ // Controls whether matching is case-sensitive or case-insensitive.
+ enum class CaseSensitivity : uint8_t {
+ kSensitive,
+ kInsensitive,
+ };
-void TracedValue::WriteString(const std::string& value) && {
- PERFETTO_DCHECK(checked_scope_.is_active());
- annotation_->set_string_value(value);
-}
+ Regex(Regex&&) noexcept;
+ Regex& operator=(Regex&&) noexcept;
+ ~Regex();
-void TracedValue::WriteString(std::string_view value) && {
- PERFETTO_DCHECK(checked_scope_.is_active());
- annotation_->set_string_value(value.data(), value.size());
-}
+ // Regex is not copyable. Use CopyableRegex for copy semantics.
+ Regex(const Regex&) = delete;
+ Regex& operator=(const Regex&) = delete;
-void TracedValue::WritePointer(const void* value) && {
- PERFETTO_DCHECK(checked_scope_.is_active());
- annotation_->set_pointer_value(reinterpret_cast<uint64_t>(value));
-}
+ // Compiles |pattern| into a Regex.
+ // Returns an error if the pattern syntax is invalid.
+ static StatusOr<Regex> Create(
+ std::string_view pattern,
+ CaseSensitivity cs = CaseSensitivity::kSensitive);
-TracedDictionary TracedValue::WriteDictionary() && {
- // Note: this passes |checked_scope_.is_active_| bit to the parent to be
- // picked up later by the new TracedDictionary.
- PERFETTO_DCHECK(checked_scope_.is_active());
- checked_scope_.Reset();
+ // Like Create(), but crashes (PERFETTO_CHECK) on an invalid pattern.
+ // Use only for patterns that are known at compile time.
+ static Regex CreateOrCheck(std::string_view pattern,
+ CaseSensitivity cs = CaseSensitivity::kSensitive);
- PERFETTO_DCHECK(!annotation_->is_finalized());
- return TracedDictionary(annotation_,
- protos::pbzero::DebugAnnotation::kDictEntries,
- event_context_, checked_scope_.parent_scope());
-}
+ // Replaces every occurrence of the regex in |s| with |replacement| and
+ // returns the resulting string. |s| is unchanged.
+ std::string GlobalReplace(std::string_view s,
+ std::string_view replacement) const;
-TracedArray TracedValue::WriteArray() && {
- // Note: this passes |checked_scope_.is_active_| bit to the parent to be
- // picked up later by the new TracedDictionary.
- PERFETTO_DCHECK(checked_scope_.is_active());
- checked_scope_.Reset();
+ // Returns true if the regex matches the entirety of |s|.
+ bool FullMatch(std::string_view s) const;
- PERFETTO_DCHECK(!annotation_->is_finalized());
- return TracedArray(annotation_, event_context_,
- checked_scope_.parent_scope());
-}
+ // Like FullMatch(), but also fills |out| with captured groups on success.
+ // out[0] – the full match.
+ // out[1..N] – the parenthesised sub-groups.
+ // Returns false (and clears |out|) when there is no match.
+ //
+ // The string_views in |out| point into |s|; they are invalidated if |s| is
+ // modified or destroyed.
+ bool FullMatchWithGroups(std::string_view s,
+ std::vector<std::string_view>& out) const;
-protozero::Message* TracedValue::WriteProtoInternal(const char* name) {
- if (event_context_) {
- annotation_->set_proto_type_name_iid(
- internal::InternedDebugAnnotationValueTypeName::Get(event_context_,
- name));
- } else {
- annotation_->set_proto_type_name(name);
- }
- return annotation_->template BeginNestedMessage<protozero::Message>(
- protos::pbzero::DebugAnnotation::kProtoValueFieldNumber);
-}
+ // Returns true if the regex matches any substring of |s|.
+ bool PartialMatch(std::string_view s) const;
-TracedArray::TracedArray(TracedValue annotation)
- : TracedArray(std::move(annotation).WriteArray()) {}
+ // Like PartialMatch(), but also fills |out| with captured groups on success.
+ // out[0] – the full match.
+ // out[1..N] – the parenthesised sub-groups.
+ // Returns false (and clears |out|) when there is no match.
+ //
+ // The string_views in |out| point into |s|; they are invalidated if |s| is
+ // modified or destroyed.
+ bool PartialMatchWithGroups(std::string_view s,
+ std::vector<std::string_view>& out) const;
-TracedValue TracedArray::AppendItem() {
- PERFETTO_DCHECK(checked_scope_.is_active());
- return TracedValue(annotation_->add_array_values(), event_context_,
- &checked_scope_);
-}
+ // Iterator over all non-overlapping matches in a string.
+ class PartialMatchIterator {
+ public:
+ // Returns the next match, or std::nullopt when no more matches remain.
+ std::optional<std::string_view> Next();
-TracedDictionary TracedArray::AppendDictionary() {
- PERFETTO_DCHECK(checked_scope_.is_active());
- return AppendItem().WriteDictionary();
-}
+ // Returns the next match with capture groups. Groups are filled into
+ // |groups|. Returns std::nullopt when no more matches remain.
+ std::optional<std::string_view> NextWithGroups(
+ std::vector<std::string_view>& groups);
-TracedArray TracedArray::AppendArray() {
- PERFETTO_DCHECK(checked_scope_.is_active());
- return AppendItem().WriteArray();
-}
+ private:
+ friend class Regex;
+ PartialMatchIterator(const Regex* re, std::string_view input);
+ const Regex* re_;
+ std::string_view input_;
+ size_t offset_ = 0;
+ std::vector<std::string_view> groups_; // Cached for Next().
+ };
-TracedDictionary::TracedDictionary(TracedValue annotation)
- : TracedDictionary(std::move(annotation).WriteDictionary()) {}
+ // Returns an iterator that yields all non-overlapping matches in |s|.
+ PartialMatchIterator PartialMatchAll(std::string_view s) const;
-TracedValue TracedDictionary::AddItem(StaticString key) {
- PERFETTO_DCHECK(checked_scope_.is_active());
- protos::pbzero::DebugAnnotation* item =
- message_->BeginNestedMessage<protos::pbzero::DebugAnnotation>(field_id_);
- item->set_name(key.value);
- return TracedValue(item, event_context_, &checked_scope_);
-}
+ // Accessors for pattern and case sensitivity (used by CopyableRegex).
+ const std::string& pattern() const { return pattern_; }
+ CaseSensitivity case_sensitivity() const { return cs_; }
-TracedValue TracedDictionary::AddItem(DynamicString key) {
- PERFETTO_DCHECK(checked_scope_.is_active());
- protos::pbzero::DebugAnnotation* item =
- message_->BeginNestedMessage<protos::pbzero::DebugAnnotation>(field_id_);
- item->set_name(key.value);
- return TracedValue(item, event_context_, &checked_scope_);
-}
+ private:
+ Regex() = default;
+ std::unique_ptr<RegexImpl> impl_;
+ std::string pattern_;
+ CaseSensitivity cs_ = CaseSensitivity::kSensitive;
+};
-TracedDictionary TracedDictionary::AddDictionary(StaticString key) {
- PERFETTO_DCHECK(checked_scope_.is_active());
- return AddItem(key).WriteDictionary();
-}
+// A copyable wrapper around Regex. Copying re-compiles the pattern from the
+// stored string, so prefer moving when the source is no longer needed.
+//
+// Use this class when Regex needs to be stored in a copyable container
+// (e.g. std::optional in a copyable struct).
+class CopyableRegex {
+ public:
+ explicit CopyableRegex(Regex regex);
-TracedDictionary TracedDictionary::AddDictionary(DynamicString key) {
- PERFETTO_DCHECK(checked_scope_.is_active());
- return AddItem(key).WriteDictionary();
-}
+ CopyableRegex(const CopyableRegex& other);
+ CopyableRegex& operator=(const CopyableRegex& other);
+ CopyableRegex(CopyableRegex&&) noexcept = default;
+ CopyableRegex& operator=(CopyableRegex&&) noexcept = default;
+ ~CopyableRegex() = default;
-TracedArray TracedDictionary::AddArray(StaticString key) {
- PERFETTO_DCHECK(checked_scope_.is_active());
- return AddItem(key).WriteArray();
-}
+ std::string GlobalReplace(std::string_view s,
+ std::string_view replacement) const {
+ return regex_.GlobalReplace(s, replacement);
+ }
+ bool FullMatch(std::string_view s) const { return regex_.FullMatch(s); }
+ bool FullMatchWithGroups(std::string_view s,
+ std::vector<std::string_view>& out) const {
+ return regex_.FullMatchWithGroups(s, out);
+ }
+ bool PartialMatch(std::string_view s) const { return regex_.PartialMatch(s); }
+ bool PartialMatchWithGroups(std::string_view s,
+ std::vector<std::string_view>& out) const {
+ return regex_.PartialMatchWithGroups(s, out);
+ }
+ Regex::PartialMatchIterator PartialMatchAll(std::string_view s) const {
+ return regex_.PartialMatchAll(s);
+ }
-TracedArray TracedDictionary::AddArray(DynamicString key) {
- PERFETTO_DCHECK(checked_scope_.is_active());
- return AddItem(key).WriteArray();
-}
+ private:
+ Regex regex_;
+};
+} // namespace base
} // namespace perfetto
-// gen_amalgamated begin source: src/tracing/tracing.cc
+
+#endif // INCLUDE_PERFETTO_EXT_BASE_REGEX_H_
+// gen_amalgamated begin header: src/base/regex/regex_pcre2.h
/*
- * Copyright (C) 2019 The Android Open Source Project
+ * Copyright (C) 2026 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.
@@ -50330,214 +55511,199 @@ TracedArray TracedDictionary::AddArray(DynamicString key) {
* limitations under the License.
*/
-// gen_amalgamated expanded: #include "perfetto/tracing/tracing.h"
-
-#include <atomic>
-#include <condition_variable>
-#include <mutex>
-
-// gen_amalgamated expanded: #include "perfetto/base/time.h"
-// gen_amalgamated expanded: #include "perfetto/ext/base/no_destructor.h"
-// gen_amalgamated expanded: #include "perfetto/ext/base/waitable_event.h"
-// gen_amalgamated expanded: #include "perfetto/tracing/internal/track_event_data_source.h"
-// gen_amalgamated expanded: #include "perfetto/tracing/internal/track_event_internal.h"
-// gen_amalgamated expanded: #include "src/tracing/internal/tracing_muxer_impl.h"
-
-namespace perfetto {
-namespace {
-bool g_was_initialized = false;
-
-// Wrapped in a function to avoid global constructor
-std::mutex& InitializedMutex() {
- static base::NoDestructor<std::mutex> initialized_mutex;
- return initialized_mutex.ref();
-}
-} // namespace
-
-// static
-void Tracing::InitializeInternal(const TracingInitArgs& args) {
- base::InitializeTime();
- std::unique_lock<std::mutex> lock(InitializedMutex());
- // If it's the first time Initialize is called, set some global params.
- if (!g_was_initialized) {
- // Make sure the headers and implementation files agree on the build config.
- PERFETTO_CHECK(args.dcheck_is_on_ == PERFETTO_DCHECK_IS_ON());
- if (args.log_message_callback) {
- base::SetLogMessageCallback(args.log_message_callback);
- }
-
- if (args.use_monotonic_clock) {
- PERFETTO_CHECK(!args.use_monotonic_raw_clock);
- internal::TrackEventInternal::SetClockId(
- protos::pbzero::BUILTIN_CLOCK_MONOTONIC);
- } else if (args.use_monotonic_raw_clock) {
- internal::TrackEventInternal::SetClockId(
- protos::pbzero::BUILTIN_CLOCK_MONOTONIC_RAW);
- }
-
- if (args.disallow_merging_with_system_tracks) {
- internal::TrackEventInternal::SetDisallowMergingWithSystemTracks(true);
- }
-
- internal::TrackEventInternal::SetBufferExhaustedPolicy(
- args.track_event_buffer_exhausted_policy);
- }
-
- internal::TracingMuxerImpl::InitializeInstance(args);
- internal::TrackRegistry::InitializeInstance(args.process_uuid);
- g_was_initialized = true;
-}
-
-// static
-bool Tracing::IsInitialized() {
- std::unique_lock<std::mutex> lock(InitializedMutex());
- return g_was_initialized;
-}
+#ifndef SRC_BASE_REGEX_REGEX_PCRE2_H_
+#define SRC_BASE_REGEX_REGEX_PCRE2_H_
-// static
-void Tracing::Shutdown() {
- std::unique_lock<std::mutex> lock(InitializedMutex());
- if (!g_was_initialized)
- return;
- internal::TracingMuxerImpl::Shutdown();
- g_was_initialized = false;
-}
+// gen_amalgamated expanded: #include "perfetto/base/build_config.h"
-// static
-void Tracing::ResetForTesting() {
- std::unique_lock<std::mutex> lock(InitializedMutex());
- if (!g_was_initialized)
- return;
- base::SetLogMessageCallback(nullptr);
- internal::TracingMuxerImpl::ResetForTesting();
- internal::TrackRegistry::ResetForTesting();
- internal::TrackEventDataSource::ResetForTesting();
- g_was_initialized = false;
-}
+// See note in regex_re2.h. Also honor PERFETTO_REGEX_FORCE_STD: targets that
+// define it (e.g. libperfetto_client_experimental) opt out of the optional
+// backends and must not pull in <pcre2.h>, even when PERFETTO_PCRE2 is set.
+#if PERFETTO_BUILDFLAG(PERFETTO_PCRE2) && !defined(PERFETTO_REGEX_FORCE_STD)
-// static
-std::unique_ptr<TracingSession> Tracing::NewTraceInternal(
- BackendType backend,
- TracingConsumerBackend* (*system_backend_factory)()) {
- return static_cast<internal::TracingMuxerImpl*>(internal::TracingMuxer::Get())
- ->CreateTracingSession(backend, system_backend_factory);
-}
+#include <limits>
+#include <memory>
+#include <string>
+#include <string_view>
+#include <vector>
-// static
-std::unique_ptr<StartupTracingSession> Tracing::SetupStartupTracing(
- const TraceConfig& config,
- Tracing::SetupStartupTracingOpts opts) {
- return static_cast<internal::TracingMuxerImpl*>(internal::TracingMuxer::Get())
- ->CreateStartupTracingSession(config, std::move(opts));
-}
+// gen_amalgamated expanded: #include "perfetto/ext/base/status_or.h"
-// static
-std::unique_ptr<StartupTracingSession> Tracing::SetupStartupTracingBlocking(
- const TraceConfig& config,
- Tracing::SetupStartupTracingOpts opts) {
- return static_cast<internal::TracingMuxerImpl*>(internal::TracingMuxer::Get())
- ->CreateStartupTracingSessionBlocking(config, std::move(opts));
-}
+#define PCRE2_CODE_UNIT_WIDTH 8
+#include <pcre2.h>
-// static
-void Tracing::ActivateTriggers(const std::vector<std::string>& triggers,
- uint32_t ttl_ms) {
- internal::TracingMuxer::Get()->ActivateTriggers(triggers, ttl_ms);
-}
+namespace perfetto {
+namespace base {
-TracingSession::~TracingSession() = default;
+struct Pcre2CodeDeleter {
+ void operator()(pcre2_code* p) const { pcre2_code_free(p); }
+};
-void TracingSession::CloneTrace(CloneTraceArgs, CloneTraceCallback) {}
+struct Pcre2MatchDataDeleter {
+ void operator()(pcre2_match_data* p) const { pcre2_match_data_free(p); }
+};
-// Can be called from any thread.
-bool TracingSession::FlushBlocking(uint32_t timeout_ms) {
- std::atomic<bool> flush_result;
- base::WaitableEvent flush_ack;
+using ScopedPcre2Code = std::unique_ptr<pcre2_code, Pcre2CodeDeleter>;
+using ScopedPcre2MatchData =
+ std::unique_ptr<pcre2_match_data, Pcre2MatchDataDeleter>;
- // The non blocking Flush() can be called on any thread. It does the PostTask
- // internally.
- Flush(
- [&flush_ack, &flush_result](bool res) {
- flush_result = res;
- flush_ack.Notify();
- },
- timeout_ms);
- flush_ack.Wait();
- return flush_result;
-}
+// PCRE2 backend for Regex.
+// Header-only so the compiler can inline through unique_ptr<RegexImpl>.
+class RegexPcre2 {
+ public:
+ RegexPcre2(RegexPcre2&&) noexcept = default;
+ RegexPcre2& operator=(RegexPcre2&&) noexcept = default;
+ ~RegexPcre2() = default;
-std::vector<char> TracingSession::ReadTraceBlocking() {
- std::vector<char> raw_trace;
- std::mutex mutex;
- std::condition_variable cv;
+ RegexPcre2(const RegexPcre2&) = delete;
+ RegexPcre2& operator=(const RegexPcre2&) = delete;
- bool all_read = false;
+ static StatusOr<RegexPcre2> Create(std::string_view pattern,
+ bool case_insensitive) {
+ RegexPcre2 result;
+ int error_code;
+ size_t error_offset;
+ uint32_t pcre2_flags = 0;
+ if (case_insensitive) {
+ pcre2_flags |= PCRE2_CASELESS;
+ }
+ result.code_.reset(pcre2_compile(
+ reinterpret_cast<PCRE2_SPTR>(pattern.data()), pattern.size(),
+ pcre2_flags, &error_code, &error_offset, nullptr));
+ if (!result.code_) {
+ PCRE2_UCHAR buffer[256];
+ pcre2_get_error_message(error_code, buffer, sizeof(buffer));
+ return ErrStatus("PCRE2 compile error at offset %zu: %s", error_offset,
+ reinterpret_cast<char*>(buffer));
+ }
+ // JIT-compile for faster matching. Non-fatal if JIT is unavailable.
+ pcre2_jit_compile(result.code_.get(), PCRE2_JIT_COMPLETE);
+ result.match_data_.reset(
+ pcre2_match_data_create_from_pattern(result.code_.get(), nullptr));
+ return std::move(result);
+ }
- ReadTrace([&mutex, &raw_trace, &all_read, &cv](ReadTraceCallbackArgs cb) {
- raw_trace.insert(raw_trace.end(), cb.data, cb.data + cb.size);
- std::unique_lock<std::mutex> lock(mutex);
- all_read = !cb.has_more;
- if (all_read)
- cv.notify_one();
- });
+ std::string GlobalReplace(std::string_view s,
+ std::string_view replacement) const {
+ std::string out;
+ size_t out_len = s.size() + replacement.size() * 2 + 64;
+ auto do_substitute = [&](size_t* len) {
+ out.resize(*len);
+ return pcre2_substitute(
+ code_.get(), reinterpret_cast<PCRE2_SPTR>(s.data()), s.size(),
+ /*startoffset=*/0,
+ PCRE2_SUBSTITUTE_GLOBAL | PCRE2_SUBSTITUTE_OVERFLOW_LENGTH,
+ /*match_data=*/nullptr, /*mcontext=*/nullptr,
+ reinterpret_cast<PCRE2_SPTR>(replacement.data()), replacement.size(),
+ reinterpret_cast<PCRE2_UCHAR*>(out.data()), len);
+ };
+ int rc = do_substitute(&out_len);
+ if (rc == PCRE2_ERROR_NOMEMORY) {
+ // PCRE2_SUBSTITUTE_OVERFLOW_LENGTH sets out_len to the required size.
+ rc = do_substitute(&out_len);
+ }
+ if (rc >= 0) {
+ out.resize(out_len);
+ return out;
+ }
+ return std::string(s);
+ }
- {
- std::unique_lock<std::mutex> lock(mutex);
- cv.wait(lock, [&all_read] { return all_read; });
+ bool FullMatch(std::string_view s) const {
+ int rc = pcre2_match(code_.get(), reinterpret_cast<PCRE2_SPTR>(s.data()),
+ s.size(),
+ /*startoffset=*/0, PCRE2_ANCHORED | PCRE2_ENDANCHORED,
+ match_data_.get(), /*mcontext=*/nullptr);
+ return rc >= 0;
}
- return raw_trace;
-}
-TracingSession::GetTraceStatsCallbackArgs
-TracingSession::GetTraceStatsBlocking() {
- std::mutex mutex;
- std::condition_variable cv;
- GetTraceStatsCallbackArgs result;
- bool stats_read = false;
+ bool FullMatchWithGroups(std::string_view s,
+ std::vector<std::string_view>& out) const {
+ out.clear();
+ int rc = pcre2_match(code_.get(), reinterpret_cast<PCRE2_SPTR>(s.data()),
+ s.size(),
+ /*startoffset=*/0, PCRE2_ANCHORED | PCRE2_ENDANCHORED,
+ match_data_.get(), /*mcontext=*/nullptr);
+ if (rc <= 0)
+ return false;
+ FillGroups(s, out);
+ return true;
+ }
- GetTraceStats(
- [&mutex, &result, &stats_read, &cv](GetTraceStatsCallbackArgs args) {
- result = std::move(args);
- std::unique_lock<std::mutex> lock(mutex);
- stats_read = true;
- cv.notify_one();
- });
+ bool PartialMatch(std::string_view s) const {
+ int rc = pcre2_match(code_.get(), reinterpret_cast<PCRE2_SPTR>(s.data()),
+ s.size(),
+ /*startoffset=*/0, /*options=*/0, match_data_.get(),
+ /*mcontext=*/nullptr);
+ return rc >= 0;
+ }
- {
- std::unique_lock<std::mutex> lock(mutex);
- cv.wait(lock, [&stats_read] { return stats_read; });
+ bool PartialMatchWithGroups(std::string_view s,
+ std::vector<std::string_view>& out) const {
+ out.clear();
+ int rc = pcre2_match(code_.get(), reinterpret_cast<PCRE2_SPTR>(s.data()),
+ s.size(),
+ /*startoffset=*/0, /*options=*/0, match_data_.get(),
+ /*mcontext=*/nullptr);
+ if (rc <= 0)
+ return false;
+ FillGroups(s, out);
+ return true;
}
- return result;
-}
-TracingSession::QueryServiceStateCallbackArgs
-TracingSession::QueryServiceStateBlocking() {
- std::mutex mutex;
- std::condition_variable cv;
- QueryServiceStateCallbackArgs result;
- bool status_read = false;
+ bool SearchWithOffset(std::string_view s,
+ size_t start_offset,
+ std::vector<std::string_view>& out) const {
+ out.clear();
+ if (start_offset > s.size())
+ return false;
+ int rc =
+ pcre2_match(code_.get(), reinterpret_cast<PCRE2_SPTR>(s.data()),
+ s.size(), start_offset, /*options=*/0, match_data_.get(),
+ /*mcontext=*/nullptr);
+ if (rc <= 0)
+ return false;
+ FillGroups(s, out);
+ return true;
+ }
- QueryServiceState(
- [&mutex, &result, &status_read, &cv](QueryServiceStateCallbackArgs args) {
- result = std::move(args);
- std::unique_lock<std::mutex> lock(mutex);
- status_read = true;
- cv.notify_one();
- });
+ private:
+ RegexPcre2() = default;
- {
- std::unique_lock<std::mutex> lock(mutex);
- cv.wait(lock, [&status_read] { return status_read; });
+ void FillGroups(std::string_view s,
+ std::vector<std::string_view>& out) const {
+ uint32_t count = pcre2_get_ovector_count(match_data_.get());
+ size_t* ovector = pcre2_get_ovector_pointer(match_data_.get());
+ for (uint32_t i = 0; i < count; ++i) {
+ if (ovector[2 * i] == std::numeric_limits<PCRE2_SIZE>::max()) {
+ out.emplace_back();
+ } else {
+ out.emplace_back(s.data() + ovector[2 * i],
+ ovector[2 * i + 1] - ovector[2 * i]);
+ }
+ }
}
- return result;
-}
-StartupTracingSession::~StartupTracingSession() = default;
+ ScopedPcre2Code code_;
+ // pcre2_match() requires a non-null match_data even when capture groups
+ // aren't needed (FullMatch, PartialMatch). A separate minimal match_data
+ // with ovecsize=1 could be used for those cases, but the savings are
+ // negligible: PCRE2's internal backtracking frame size depends on the
+ // pattern's capture groups regardless of ovector size. We reuse a single
+ // cached match_data created from the pattern to avoid per-call allocation.
+ mutable ScopedPcre2MatchData match_data_;
+};
+} // namespace base
} // namespace perfetto
-// gen_amalgamated begin source: src/tracing/tracing_policy.cc
+
+#endif // PERFETTO_BUILDFLAG(PERFETTO_PCRE2) &&
+ // !defined(PERFETTO_REGEX_FORCE_STD)
+
+#endif // SRC_BASE_REGEX_REGEX_PCRE2_H_
+// gen_amalgamated begin header: src/base/regex/regex_re2.h
/*
- * Copyright (C) 2021 The Android Open Source Project
+ * Copyright (C) 2026 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.
@@ -50552,16 +55718,125 @@ StartupTracingSession::~StartupTracingSession() = default;
* limitations under the License.
*/
-// gen_amalgamated expanded: #include "perfetto/tracing/tracing_policy.h"
+#ifndef SRC_BASE_REGEX_REGEX_RE2_H_
+#define SRC_BASE_REGEX_REGEX_RE2_H_
+
+// gen_amalgamated expanded: #include "perfetto/base/build_config.h"
+
+// Guarded because gen_amalgamated inlines the body even when the include
+// site in regex.cc is preprocessed out. Also honor PERFETTO_REGEX_FORCE_STD:
+// targets that define it opt out of the optional backends and must not pull in
+// <re2/re2.h>, even when PERFETTO_RE2 is set.
+#if PERFETTO_BUILDFLAG(PERFETTO_RE2) && !defined(PERFETTO_REGEX_FORCE_STD)
+
+#include <memory>
+#include <string>
+#include <string_view>
+#include <vector>
+
+// gen_amalgamated expanded: #include "perfetto/ext/base/status_or.h"
+
+// Using quotes instead of angle brackets because Bazel passes external repo
+// paths via -iquote (not -isystem), which only covers quoted includes.
+// See google/re2 commit baeed1c and bazelbuild/bazel#18974.
+#include "re2/re2.h" // gen_amalgamated:keep
namespace perfetto {
+namespace base {
-TracingPolicy::~TracingPolicy() = default;
+// RE2 backend for Regex. Used on non-Android builds (standalone, Chromium).
+// Header-only so the compiler can inline through unique_ptr<RegexImpl>.
+class RegexRe2 {
+ public:
+ RegexRe2(RegexRe2&&) noexcept = default;
+ RegexRe2& operator=(RegexRe2&&) noexcept = default;
+ ~RegexRe2() = default;
+
+ RegexRe2(const RegexRe2&) = delete;
+ RegexRe2& operator=(const RegexRe2&) = delete;
+
+ static StatusOr<RegexRe2> Create(std::string_view pattern,
+ bool case_insensitive) {
+ RegexRe2 result;
+ re2::RE2::Options options;
+ options.set_log_errors(false);
+ options.set_case_sensitive(!case_insensitive);
+ result.re_ = std::make_unique<re2::RE2>(std::string(pattern), options);
+ if (!result.re_->ok()) {
+ return ErrStatus("RE2 compile error: %s", result.re_->error().c_str());
+ }
+ result.groups_.resize(
+ static_cast<size_t>(result.re_->NumberOfCapturingGroups() + 1));
+ return std::move(result);
+ }
+
+ std::string GlobalReplace(std::string_view s,
+ std::string_view replacement) const {
+ std::string out(s);
+ re2::RE2::GlobalReplace(&out, *re_, replacement);
+ return out;
+ }
+
+ bool FullMatch(std::string_view s) const {
+ return re2::RE2::FullMatch(s, *re_);
+ }
+
+ bool FullMatchWithGroups(std::string_view s,
+ std::vector<std::string_view>& out) const {
+ out.clear();
+ int n = static_cast<int>(groups_.size());
+ if (!re_->Match(s, 0, s.size(), re2::RE2::ANCHOR_BOTH, groups_.data(), n))
+ return false;
+ out.assign(groups_.begin(), groups_.begin() + n);
+ return true;
+ }
+
+ bool PartialMatch(std::string_view s) const {
+ return re2::RE2::PartialMatch(s, *re_);
+ }
+
+ bool PartialMatchWithGroups(std::string_view s,
+ std::vector<std::string_view>& out) const {
+ out.clear();
+ int n = static_cast<int>(groups_.size());
+ if (!re_->Match(s, 0, s.size(), re2::RE2::UNANCHORED, groups_.data(), n))
+ return false;
+ out.assign(groups_.begin(), groups_.begin() + n);
+ return true;
+ }
+
+ bool SearchWithOffset(std::string_view s,
+ size_t start_offset,
+ std::vector<std::string_view>& out) const {
+ out.clear();
+ if (start_offset > s.size())
+ return false;
+ int n = static_cast<int>(groups_.size());
+ if (!re_->Match(s, start_offset, s.size(), re2::RE2::UNANCHORED,
+ groups_.data(), n))
+ return false;
+ out.assign(groups_.begin(), groups_.begin() + n);
+ return true;
+ }
+
+ private:
+ RegexRe2() = default;
+ std::unique_ptr<re2::RE2> re_;
+ // Must be absl::string_view, not std::string_view, to match RE2::Match()
+ // signature. These can be distinct types in different builds.
+ mutable std::vector<absl::string_view> groups_;
+};
+} // namespace base
} // namespace perfetto
-// gen_amalgamated begin source: src/tracing/track.cc
+
+#endif // PERFETTO_BUILDFLAG(PERFETTO_RE2) &&
+ // !defined(PERFETTO_REGEX_FORCE_STD)
+
+#endif // SRC_BASE_REGEX_REGEX_RE2_H_
+// gen_amalgamated begin header: src/base/regex/regex_std.h
/*
- * Copyright (C) 2019 The Android Open Source Project
+ * Copyright (C) 2026 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.
@@ -50576,259 +55851,110 @@ TracingPolicy::~TracingPolicy() = default;
* limitations under the License.
*/
-// gen_amalgamated expanded: #include "perfetto/tracing/track.h"
-
-// gen_amalgamated expanded: #include "perfetto/ext/base/file_utils.h"
-// gen_amalgamated expanded: #include "perfetto/ext/base/fnv_hash.h"
-// gen_amalgamated expanded: #include "perfetto/ext/base/scoped_file.h"
-// gen_amalgamated expanded: #include "perfetto/ext/base/string_splitter.h"
-// gen_amalgamated expanded: #include "perfetto/ext/base/string_utils.h"
-// gen_amalgamated expanded: #include "perfetto/ext/base/thread_utils.h"
-// gen_amalgamated expanded: #include "perfetto/ext/base/uuid.h"
-// gen_amalgamated expanded: #include "perfetto/tracing/internal/track_event_data_source.h"
-// gen_amalgamated expanded: #include "perfetto/tracing/internal/track_event_internal.h"
-// gen_amalgamated expanded: #include "protos/perfetto/trace/track_event/counter_descriptor.gen.h"
-// gen_amalgamated expanded: #include "protos/perfetto/trace/track_event/process_descriptor.gen.h"
-// gen_amalgamated expanded: #include "protos/perfetto/trace/track_event/process_descriptor.pbzero.h"
-// gen_amalgamated expanded: #include "protos/perfetto/trace/track_event/thread_descriptor.gen.h"
-// gen_amalgamated expanded: #include "protos/perfetto/trace/track_event/thread_descriptor.pbzero.h"
+#ifndef SRC_BASE_REGEX_REGEX_STD_H_
+#define SRC_BASE_REGEX_REGEX_STD_H_
-namespace perfetto {
+#include <regex>
+#include <string>
+#include <string_view>
+#include <vector>
-// static
-uint64_t Track::process_uuid = 0;
+// gen_amalgamated expanded: #include "perfetto/ext/base/status_or.h"
-protos::gen::TrackDescriptor Track::Serialize() const {
- protos::gen::TrackDescriptor desc;
- desc.set_uuid(uuid);
- if (parent_uuid)
- desc.set_parent_uuid(parent_uuid);
- return desc;
-}
+namespace perfetto {
+namespace base {
-void Track::Serialize(protos::pbzero::TrackDescriptor* desc) const {
- auto bytes = Serialize().SerializeAsString();
- desc->AppendRawProtoBytes(bytes.data(), bytes.size());
-}
+// std::regex backend for Regex. Uses ECMAScript syntax for Perl-style
+// shorthands (\d, \w, \s).
+class RegexStd {
+ public:
+ RegexStd(RegexStd&&) noexcept = default;
+ RegexStd& operator=(RegexStd&&) noexcept = default;
+ ~RegexStd() = default;
-// static
-Track Track::ThreadScoped(const void* ptr, Track parent) {
- if (parent.uuid == 0)
- return Track::FromPointer(ptr, ThreadTrack::Current());
- return Track::FromPointer(ptr, parent);
-}
+ RegexStd(const RegexStd&) = delete;
+ RegexStd& operator=(const RegexStd&) = delete;
-protos::gen::TrackDescriptor ProcessTrack::Serialize() const {
- auto desc = Track::Serialize();
- auto pd = desc.mutable_process();
- pd->set_pid(static_cast<int32_t>(pid));
-#if PERFETTO_BUILDFLAG(PERFETTO_OS_LINUX) || \
- PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID)
- std::string cmdline;
- if (base::ReadFile("/proc/self/cmdline", &cmdline)) {
- // Since cmdline is a zero-terminated list of arguments, this ends up
- // writing just the first element, i.e., the process name, into the process
- // name field.
- pd->set_process_name(cmdline.c_str());
- base::StringSplitter splitter(std::move(cmdline), '\0');
- while (splitter.Next()) {
- pd->add_cmdline(
- std::string(splitter.cur_token(), splitter.cur_token_size()));
+ static StatusOr<RegexStd> Create(std::string_view pattern,
+ bool case_insensitive) {
+ RegexStd result;
+ auto flags = std::regex::ECMAScript;
+ if (case_insensitive) {
+ flags |= std::regex::icase;
}
+ result.re_ = std::regex(std::string(pattern), flags);
+ return std::move(result);
}
- // TODO(skyostil): Record command line on Windows, FreeBSD and Mac.
-#endif
- return desc;
-}
-
-void ProcessTrack::Serialize(protos::pbzero::TrackDescriptor* desc) const {
- auto bytes = Serialize().SerializeAsString();
- desc->AppendRawProtoBytes(bytes.data(), bytes.size());
-}
-
-protos::gen::TrackDescriptor ThreadTrack::Serialize() const {
- auto desc = Track::Serialize();
- auto td = desc.mutable_thread();
- td->set_pid(static_cast<int32_t>(pid));
- td->set_tid(static_cast<int32_t>(tid));
- if (disallow_merging_with_system_tracks) {
- desc.set_disallow_merging_with_system_tracks(true);
- }
- std::string thread_name;
- if (base::GetThreadName(thread_name))
- td->set_thread_name(thread_name);
- return desc;
-}
-
-// static
-ThreadTrack ThreadTrack::Current() {
- return ThreadTrack(
- internal::TracingMuxer::Get()->GetCurrentThreadId(),
- internal::TrackEventInternal::GetDisallowMergingWithSystemTracks());
-}
-
-// static
-ThreadTrack ThreadTrack::ForThread(base::PlatformThreadId tid_) {
- return ThreadTrack(
- tid_, internal::TrackEventInternal::GetDisallowMergingWithSystemTracks());
-}
-
-void ThreadTrack::Serialize(protos::pbzero::TrackDescriptor* desc) const {
- auto bytes = Serialize().SerializeAsString();
- desc->AppendRawProtoBytes(bytes.data(), bytes.size());
-}
-protos::gen::TrackDescriptor NamedTrack::Serialize() const {
- auto desc = NamedTrackBase::Serialize();
- if (sibling_merge_behavior_ != perfetto::protos::gen::TrackDescriptor::
- SIBLING_MERGE_BEHAVIOR_UNSPECIFIED) {
- desc.set_sibling_merge_behavior(sibling_merge_behavior_);
- }
- if (sibling_merge_key_) {
- desc.set_sibling_merge_key(sibling_merge_key_);
- } else if (sibling_merge_key_int_.has_value()) {
- desc.set_sibling_merge_key_int(*sibling_merge_key_int_);
+ std::string GlobalReplace(std::string_view s,
+ std::string_view replacement) const {
+ return std::regex_replace(std::string(s), re_, std::string(replacement));
}
- return desc;
-}
-
-protos::gen::TrackDescriptor StateTrack::Serialize() const {
- auto desc = NamedTrackBase::Serialize();
- // Initialize the state submessage to mark this track as a StateTrack.
- desc.mutable_state();
- return desc;
-}
-protos::gen::TrackDescriptor CounterTrack::Serialize() const {
- auto desc = Track::Serialize();
- auto* counter = desc.mutable_counter();
- if (static_name_) {
- desc.set_static_name(static_name_.value);
- } else {
- desc.set_name(dynamic_name_.value);
+ bool FullMatch(std::string_view s) const {
+ return std::regex_match(s.data(), s.data() + s.size(), re_);
}
- if (category_)
- counter->add_categories(category_);
- if (unit_ != perfetto::protos::pbzero::CounterDescriptor::UNIT_UNSPECIFIED)
- counter->set_unit(static_cast<protos::gen::CounterDescriptor_Unit>(unit_));
- {
- // if |type| is set, we don't want to emit |unit_name|. Trace processor
- // infers the track name from the type in that case.
- if (type_ !=
- perfetto::protos::gen::CounterDescriptor::COUNTER_UNSPECIFIED) {
- counter->set_type(type_);
- } else if (unit_name_) {
- counter->set_unit_name(unit_name_);
- }
+ bool FullMatchWithGroups(std::string_view s,
+ std::vector<std::string_view>& out) const {
+ out.clear();
+ if (!std::regex_match(s.data(), s.data() + s.size(), match_data_, re_))
+ return false;
+ FillGroups(s.data(), out);
+ return true;
}
- if (unit_multiplier_ != 1)
- counter->set_unit_multiplier(unit_multiplier_);
- if (is_incremental_)
- counter->set_is_incremental(is_incremental_);
- return desc;
-}
-
-void CounterTrack::Serialize(protos::pbzero::TrackDescriptor* desc) const {
- auto bytes = Serialize().SerializeAsString();
- desc->AppendRawProtoBytes(bytes.data(), bytes.size());
-}
-namespace internal {
-namespace {
-
-uint64_t GetProcessStartTime() {
-#if !PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
- std::string stat;
- if (!base::ReadFile("/proc/self/stat", &stat))
- return 0u;
- // The stat file is a single line split into space-separated fields as "pid
- // (comm) state ppid ...". However because the command name can contain any
- // characters (including parentheses and spaces), we need to skip past it
- // before parsing the rest of the fields. To do that, we look for the last
- // instance of ") " (parentheses followed by space) and parse forward from
- // that point.
- size_t comm_end = stat.rfind(") ");
- if (comm_end == std::string::npos)
- return 0u;
- stat = stat.substr(comm_end + strlen(") "));
- base::StringSplitter splitter(stat, ' ');
- for (size_t skip = 0; skip < 20; skip++) {
- if (!splitter.Next())
- return 0u;
+ bool PartialMatch(std::string_view s) const {
+ return std::regex_search(s.data(), s.data() + s.size(), re_);
}
- return base::CStringToUInt64(splitter.cur_token()).value_or(0u);
-#else
- return 0;
-#endif // !PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
-}
-
-} // namespace
-
-// static
-TrackRegistry* TrackRegistry::instance_;
-
-TrackRegistry::TrackRegistry() = default;
-TrackRegistry::~TrackRegistry() = default;
-// static
-void TrackRegistry::InitializeInstance(std::optional<uint64_t> process_uuid) {
- if (instance_)
- return;
- instance_ = new TrackRegistry();
- if (process_uuid) {
- Track::process_uuid = *process_uuid;
- } else {
- Track::process_uuid = ComputeProcessUuid();
+ bool PartialMatchWithGroups(std::string_view s,
+ std::vector<std::string_view>& out) const {
+ out.clear();
+ if (!std::regex_search(s.data(), s.data() + s.size(), match_data_, re_))
+ return false;
+ FillGroups(s.data(), out);
+ return true;
}
-}
-// static
-uint64_t TrackRegistry::ComputeProcessUuid() {
- // Use the process start time + pid as the unique identifier for this process.
- // This ensures that if there are two independent copies of the Perfetto SDK
- // in the same process (e.g., one in the app and another in a system
- // framework), events emitted by each will be consistently interleaved on
- // common thread and process tracks.
- uint64_t random;
- if (uint64_t start_time = GetProcessStartTime()) {
- random = start_time;
- } else {
- // Fall back to a randomly generated identifier.
- static uint64_t random_once = static_cast<uint64_t>(base::Uuidv4().lsb());
- random = random_once;
+ bool SearchWithOffset(std::string_view s,
+ size_t start_offset,
+ std::vector<std::string_view>& out) const {
+ out.clear();
+ const char* begin = s.data() + start_offset;
+ const char* end = s.data() + s.size();
+ if (begin > end)
+ return false;
+ if (!std::regex_search(begin, end, match_data_, re_))
+ return false;
+ FillGroups(begin, out);
+ return true;
}
- return base::FnvHasher::Combine(random, Platform::GetCurrentProcessId());
-}
-
-void TrackRegistry::ResetForTesting() {
- instance_->tracks_.clear();
-}
-void TrackRegistry::UpdateTrack(Track track,
- const std::string& serialized_desc) {
- std::lock_guard<std::mutex> lock(mutex_);
- tracks_[track.uuid] = {serialized_desc, track.parent_uuid};
-}
+ private:
+ RegexStd() = default;
-void TrackRegistry::EraseTrack(Track track) {
- std::lock_guard<std::mutex> lock(mutex_);
- tracks_.erase(track.uuid);
-}
+ void FillGroups(const char* base, std::vector<std::string_view>& out) const {
+ for (size_t i = 0; i < match_data_.size(); ++i) {
+ if (match_data_[i].matched) {
+ out.emplace_back(base + match_data_.position(i),
+ static_cast<size_t>(match_data_.length(i)));
+ } else {
+ out.emplace_back();
+ }
+ }
+ }
-// static
-void TrackRegistry::WriteTrackDescriptor(
- const SerializedTrackDescriptor& desc,
- protozero::MessageHandle<protos::pbzero::TracePacket> packet) {
- packet->AppendString(
- perfetto::protos::pbzero::TracePacket::kTrackDescriptorFieldNumber, desc);
-}
+ std::regex re_;
+ mutable std::cmatch match_data_;
+};
-} // namespace internal
+} // namespace base
} // namespace perfetto
-// gen_amalgamated begin source: src/tracing/track_event_category_registry.cc
+
+#endif // SRC_BASE_REGEX_REGEX_STD_H_
/*
- * Copyright (C) 2019 The Android Open Source Project
+ * Copyright (C) 2026 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.
@@ -50843,145 +55969,158 @@ void TrackRegistry::WriteTrackDescriptor(
* limitations under the License.
*/
-// gen_amalgamated expanded: #include "perfetto/tracing/track_event_category_registry.h"
+// gen_amalgamated expanded: #include "perfetto/ext/base/regex.h"
+
+#include <optional>
+#include <string>
+#include <string_view>
+#include <vector>
+
+// gen_amalgamated expanded: #include "perfetto/base/build_config.h"
+// gen_amalgamated expanded: #include "perfetto/base/logging.h"
+// gen_amalgamated expanded: #include "perfetto/ext/base/status_macros.h"
+
+// Unconditional: each header self-guards, so the amalgamator can see through.
+// gen_amalgamated expanded: #include "src/base/regex/regex_pcre2.h"
+// gen_amalgamated expanded: #include "src/base/regex/regex_re2.h"
+// gen_amalgamated expanded: #include "src/base/regex/regex_std.h"
+
+// Picks the regex backend and exposes it as PERFETTO_REGEX_BACKEND.
+// Preference order:
+// 1. PERFETTO_REGEX_FORCE_STD -> std::regex
+// 2. PCRE2 (when enabled)
+// 3. RE2 (when enabled)
+// 4. std::regex (fallback)
+#if defined(PERFETTO_REGEX_FORCE_STD)
+#define PERFETTO_REGEX_BACKEND ::perfetto::base::RegexStd
+#elif PERFETTO_BUILDFLAG(PERFETTO_PCRE2)
+#define PERFETTO_REGEX_BACKEND ::perfetto::base::RegexPcre2
+#elif PERFETTO_BUILDFLAG(PERFETTO_RE2)
+#define PERFETTO_REGEX_BACKEND ::perfetto::base::RegexRe2
+#else
+#define PERFETTO_REGEX_BACKEND ::perfetto::base::RegexStd
+#endif
namespace perfetto {
-namespace {
+namespace base {
-static constexpr const char kLegacySlowPrefix[] = "disabled-by-default-";
-static constexpr const char kSlowTag[] = "slow";
+// Pimpl for Regex. Holds the selected backend; Regex reaches into `backend`
+// directly (Regex is a friend below).
+class RegexImpl {
+ public:
+ using Backend = PERFETTO_REGEX_BACKEND;
+ explicit RegexImpl(Backend b) : backend(std::move(b)) {}
-} // namespace
+ private:
+ friend class Regex;
+ Backend backend;
+};
+#undef PERFETTO_REGEX_BACKEND
-// static
-Category Category::FromDynamicCategory(const char* name) {
- if (GetNthNameSize(1, name, name)) {
- Category group(Group(name));
- PERFETTO_DCHECK(group.name);
- return group;
- }
- Category category(name);
- PERFETTO_DCHECK(category.name);
- // Disabled-by-default categories get a "slow" tag.
- if (!strncmp(name, kLegacySlowPrefix, strlen(kLegacySlowPrefix))) {
- return category.SetTags(kSlowTag);
- }
- return category;
+Regex::Regex(Regex&&) noexcept = default;
+Regex& Regex::operator=(Regex&&) noexcept = default;
+Regex::~Regex() = default;
+
+StatusOr<Regex> Regex::Create(std::string_view pattern,
+ Regex::CaseSensitivity cs) {
+ bool insensitive = (cs == CaseSensitivity::kInsensitive);
+ ASSIGN_OR_RETURN(auto backend,
+ RegexImpl::Backend::Create(pattern, insensitive));
+ Regex regex;
+ regex.pattern_ = std::string(pattern);
+ regex.cs_ = cs;
+ regex.impl_ = std::make_unique<RegexImpl>(std::move(backend));
+ return std::move(regex);
}
-Category Category::FromDynamicCategory(
- const DynamicCategory& dynamic_category) {
- return FromDynamicCategory(dynamic_category.name.c_str());
+Regex Regex::CreateOrCheck(std::string_view pattern,
+ Regex::CaseSensitivity cs) {
+ auto re_or = Create(pattern, cs);
+ PERFETTO_CHECK(re_or.ok());
+ return std::move(*re_or);
}
-namespace internal {
+std::string Regex::GlobalReplace(std::string_view s,
+ std::string_view replacement) const {
+ PERFETTO_DCHECK(impl_);
+ return impl_->backend.GlobalReplace(s, replacement);
+}
-perfetto::DynamicCategory NullCategory(const perfetto::DynamicCategory&) {
- return perfetto::DynamicCategory{};
+bool Regex::FullMatch(std::string_view s) const {
+ PERFETTO_DCHECK(impl_);
+ return impl_->backend.FullMatch(s);
}
-void TrackEventCategoryRegistry::EnableCategoryForInstance(
- size_t category_index,
- uint32_t instance_index) const {
- PERFETTO_DCHECK(instance_index < kMaxDataSourceInstances);
- PERFETTO_DCHECK(category_index < category_count_);
- // Matches the acquire_load in DataSource::Trace().
- state_storage_[category_index].fetch_or(
- static_cast<uint8_t>(1u << instance_index), std::memory_order_release);
+bool Regex::FullMatchWithGroups(std::string_view s,
+ std::vector<std::string_view>& out) const {
+ PERFETTO_DCHECK(impl_);
+ return impl_->backend.FullMatchWithGroups(s, out);
}
-void TrackEventCategoryRegistry::DisableCategoryForInstance(
- size_t category_index,
- uint32_t instance_index) const {
- PERFETTO_DCHECK(instance_index < kMaxDataSourceInstances);
- PERFETTO_DCHECK(category_index < category_count_);
- // Matches the acquire_load in DataSource::Trace().
- state_storage_[category_index].fetch_and(
- static_cast<uint8_t>(~(1u << instance_index)), std::memory_order_release);
+bool Regex::PartialMatch(std::string_view s) const {
+ PERFETTO_DCHECK(impl_);
+ return impl_->backend.PartialMatch(s);
}
-} // namespace internal
-} // namespace perfetto
-// gen_amalgamated begin source: src/tracing/track_event_legacy.cc
-/*
- * 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.
- */
+bool Regex::PartialMatchWithGroups(std::string_view s,
+ std::vector<std::string_view>& out) const {
+ PERFETTO_DCHECK(impl_);
+ return impl_->backend.PartialMatchWithGroups(s, out);
+}
-// gen_amalgamated expanded: #include "perfetto/tracing/track_event_legacy.h"
+// --- PartialMatchIterator ---
-// gen_amalgamated expanded: #include "perfetto/ext/base/fnv_hash.h"
-// gen_amalgamated expanded: #include "perfetto/tracing/track.h"
+Regex::PartialMatchIterator::PartialMatchIterator(const Regex* re,
+ std::string_view input)
+ : re_(re), input_(input) {}
-namespace perfetto {
-namespace legacy {
+std::optional<std::string_view> Regex::PartialMatchIterator::Next() {
+ return NextWithGroups(groups_);
+}
-template <>
-ThreadTrack ConvertThreadId(const PerfettoLegacyCurrentThreadId&) {
- // Because of the short-circuit in PERFETTO_INTERNAL_LEGACY_EVENT, we should
- // never get here.
- PERFETTO_DCHECK(false);
- return ThreadTrack::Current();
+std::optional<std::string_view> Regex::PartialMatchIterator::NextWithGroups(
+ std::vector<std::string_view>& groups) {
+ if (offset_ > input_.size())
+ return std::nullopt;
+ PERFETTO_DCHECK(re_->impl_);
+ if (!re_->impl_->backend.SearchWithOffset(input_, offset_, groups))
+ return std::nullopt;
+ if (groups.empty())
+ return std::nullopt;
+ std::string_view match = groups[0];
+ size_t match_end =
+ static_cast<size_t>(match.data() - input_.data()) + match.size();
+ // Advance past the match. If match is empty, advance by one to avoid
+ // infinite loops.
+ offset_ = match.size() == 0 ? match_end + 1 : match_end;
+ return match;
}
-} // namespace legacy
+Regex::PartialMatchIterator Regex::PartialMatchAll(std::string_view s) const {
+ return PartialMatchIterator(this, s);
+}
-namespace internal {
+// --- CopyableRegex ---
-void LegacyTraceId::Write(protos::pbzero::TrackEvent::LegacyEvent* event,
- uint32_t event_flags) const {
- // Legacy flow events always use bind_id.
- if (event_flags &
- (legacy::kTraceEventFlagFlowOut | legacy::kTraceEventFlagFlowIn)) {
- // Flow bind_ids don't have scopes, so we need to mangle in-process ones to
- // avoid collisions.
- if (id_flags_ & legacy::kTraceEventFlagHasLocalId) {
- event->set_bind_id(raw_id_ ^ ProcessTrack::Current().uuid);
- } else {
- event->set_bind_id(raw_id_);
- }
- return;
- }
+CopyableRegex::CopyableRegex(Regex regex) : regex_(std::move(regex)) {}
- uint32_t scope_flags = id_flags_ & (legacy::kTraceEventFlagHasId |
- legacy::kTraceEventFlagHasLocalId |
- legacy::kTraceEventFlagHasGlobalId);
- uint64_t id = raw_id_;
- if (scope_ && scope_flags != legacy::kTraceEventFlagHasGlobalId) {
- id = base::FnvHasher::Combine(id, scope_);
- }
+CopyableRegex::CopyableRegex(const CopyableRegex& other)
+ : regex_(Regex::CreateOrCheck(other.regex_.pattern(),
+ other.regex_.case_sensitivity())) {}
- switch (scope_flags) {
- case legacy::kTraceEventFlagHasId:
- event->set_unscoped_id(id);
- break;
- case legacy::kTraceEventFlagHasLocalId:
- event->set_local_id(id);
- break;
- case legacy::kTraceEventFlagHasGlobalId:
- event->set_global_id(id);
- break;
+CopyableRegex& CopyableRegex::operator=(const CopyableRegex& other) {
+ if (this != &other) {
+ this->~CopyableRegex();
+ new (this) CopyableRegex(other);
}
- if (scope_)
- event->set_id_scope(scope_);
+ return *this;
}
-} // namespace internal
+} // namespace base
} // namespace perfetto
-// gen_amalgamated begin source: src/tracing/track_event_state_tracker.cc
+// gen_amalgamated begin source: src/base/clock_snapshots.cc
/*
- * Copyright (C) 2020 The Android Open Source Project
+ * Copyright (C) 2024 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.
@@ -50996,282 +56135,131 @@ void LegacyTraceId::Write(protos::pbzero::TrackEvent::LegacyEvent* event,
* limitations under the License.
*/
-// gen_amalgamated expanded: #include "perfetto/tracing/track_event_state_tracker.h"
-
-// gen_amalgamated expanded: #include "perfetto/ext/base/fnv_hash.h"
-// gen_amalgamated expanded: #include "perfetto/tracing/internal/track_event_internal.h"
-
-// gen_amalgamated expanded: #include "protos/perfetto/common/interceptor_descriptor.gen.h"
-// gen_amalgamated expanded: #include "protos/perfetto/trace/clock_snapshot.pbzero.h"
-// gen_amalgamated expanded: #include "protos/perfetto/trace/interned_data/interned_data.pbzero.h"
-// gen_amalgamated expanded: #include "protos/perfetto/trace/trace_packet.pbzero.h"
-// gen_amalgamated expanded: #include "protos/perfetto/trace/trace_packet_defaults.pbzero.h"
-// gen_amalgamated expanded: #include "protos/perfetto/trace/track_event/debug_annotation.pbzero.h"
-// gen_amalgamated expanded: #include "protos/perfetto/trace/track_event/process_descriptor.pbzero.h"
-// gen_amalgamated expanded: #include "protos/perfetto/trace/track_event/thread_descriptor.pbzero.h"
-// gen_amalgamated expanded: #include "protos/perfetto/trace/track_event/track_descriptor.pbzero.h"
-// gen_amalgamated expanded: #include "protos/perfetto/trace/track_event/track_event.pbzero.h"
-
-namespace perfetto {
-
-using internal::TrackEventIncrementalState;
-
-TrackEventStateTracker::~TrackEventStateTracker() = default;
-TrackEventStateTracker::Delegate::~Delegate() = default;
-
-// static
-void TrackEventStateTracker::ProcessTracePacket(
- Delegate& delegate,
- SequenceState& sequence_state,
- const protos::pbzero::TracePacket_Decoder& packet) {
- UpdateIncrementalState(delegate, sequence_state, packet);
-
- if (!packet.has_track_event())
- return;
- perfetto::protos::pbzero::TrackEvent::Decoder track_event(
- packet.track_event());
-
- auto clock_id = packet.timestamp_clock_id();
- if (!packet.has_timestamp_clock_id())
- clock_id = sequence_state.default_clock_id;
- uint64_t timestamp = packet.timestamp();
- // TODO(mohitms): Incorporate unit multiplier as well.
- if (clock_id == internal::TrackEventIncrementalState::kClockIdIncremental) {
- timestamp += sequence_state.most_recent_absolute_time_ns;
- sequence_state.most_recent_absolute_time_ns = timestamp;
- }
-
- Track* track = &sequence_state.track;
- if (track_event.has_track_uuid()) {
- auto* session_state = delegate.GetSessionState();
- if (!session_state)
- return; // Tracing must have ended.
- track = &session_state->tracks[track_event.track_uuid()];
- }
-
- // We only log the first category of each event.
- protozero::ConstChars category{};
- uint64_t category_iid = 0;
- if (auto iid_it = track_event.category_iids()) {
- category_iid = *iid_it;
- category.data = sequence_state.event_categories[category_iid].data();
- category.size = sequence_state.event_categories[category_iid].size();
- } else if (auto cat_it = track_event.categories()) {
- category.data = reinterpret_cast<const char*>(cat_it->data());
- category.size = cat_it->size();
- }
-
- protozero::ConstChars name{};
- uint64_t name_iid = track_event.name_iid();
- uint64_t name_hash = 0;
- uint64_t duration = 0;
- if (name_iid) {
- name.data = sequence_state.event_names[name_iid].data();
- name.size = sequence_state.event_names[name_iid].size();
- } else if (track_event.has_name()) {
- name.data = track_event.name().data;
- name.size = track_event.name().size;
- }
-
- if (name.data) {
- base::FnvHasher hash;
- hash.Update(name.data, name.size);
- name_hash = hash.digest();
- }
-
- size_t depth = track->stack.size();
- switch (track_event.type()) {
- case protos::pbzero::TrackEvent::TYPE_SLICE_BEGIN: {
- StackFrame frame;
- frame.timestamp = timestamp;
- frame.name_hash = name_hash;
- if (track_event.has_track_uuid()) {
- frame.name = name.ToStdString();
- frame.category = category.ToStdString();
- } else {
- frame.name_iid = name_iid;
- frame.category_iid = category_iid;
- }
- track->stack.push_back(std::move(frame));
- break;
- }
- case protos::pbzero::TrackEvent::TYPE_SLICE_END:
- if (!track->stack.empty()) {
- const auto& prev_frame = track->stack.back();
- if (prev_frame.name_iid) {
- name.data = sequence_state.event_names[prev_frame.name_iid].data();
- name.size = sequence_state.event_names[prev_frame.name_iid].size();
- } else {
- name.data = prev_frame.name.data();
- name.size = prev_frame.name.size();
- }
- name_hash = prev_frame.name_hash;
- if (prev_frame.category_iid) {
- category.data =
- sequence_state.event_categories[prev_frame.category_iid].data();
- category.size =
- sequence_state.event_categories[prev_frame.category_iid].size();
- } else {
- category.data = prev_frame.category.data();
- category.size = prev_frame.category.size();
- }
- duration = timestamp - prev_frame.timestamp;
- depth--;
- }
- break;
- case protos::pbzero::TrackEvent::TYPE_INSTANT:
- break;
- case protos::pbzero::TrackEvent::TYPE_COUNTER:
- case protos::pbzero::TrackEvent::TYPE_UNSPECIFIED:
- // TODO(skyostil): Support counters.
- return;
- }
-
- ParsedTrackEvent parsed_event{track_event};
- parsed_event.timestamp_ns = timestamp;
- parsed_event.duration_ns = duration;
- parsed_event.stack_depth = depth;
- parsed_event.category = category;
- parsed_event.name = name;
- parsed_event.name_hash = name_hash;
- delegate.OnTrackEvent(*track, parsed_event);
-
- if (track_event.type() == protos::pbzero::TrackEvent::TYPE_SLICE_END &&
- !track->stack.empty()) {
- track->stack.pop_back();
- }
-}
+// gen_amalgamated expanded: #include "perfetto/ext/base/clock_snapshots.h"
-// static
-void TrackEventStateTracker::UpdateIncrementalState(
- Delegate& delegate,
- SequenceState& sequence_state,
- const protos::pbzero::TracePacket_Decoder& packet) {
-#if PERFETTO_DCHECK_IS_ON()
- if (!sequence_state.sequence_id) {
- sequence_state.sequence_id = packet.trusted_packet_sequence_id();
- } else {
- PERFETTO_DCHECK(sequence_state.sequence_id ==
- packet.trusted_packet_sequence_id());
- }
-#endif
+// gen_amalgamated expanded: #include "perfetto/base/build_config.h"
+// gen_amalgamated expanded: #include "perfetto/base/time.h"
+// gen_amalgamated expanded: #include "protos/perfetto/common/builtin_clock.pbzero.h"
- perfetto::protos::pbzero::ClockSnapshot::Decoder snapshot(
- packet.clock_snapshot());
- for (auto it = snapshot.clocks(); it; ++it) {
- perfetto::protos::pbzero::ClockSnapshot::Clock::Decoder clock(*it);
- // TODO(mohitms) : Handle the incremental clock other than default one.
- if (clock.is_incremental() &&
- clock.clock_id() ==
- internal::TrackEventIncrementalState::kClockIdIncremental) {
- sequence_state.most_recent_absolute_time_ns =
- clock.timestamp() * clock.unit_multiplier_ns();
- break;
- }
- }
+namespace perfetto::base {
- if (packet.sequence_flags() &
- perfetto::protos::pbzero::TracePacket::SEQ_INCREMENTAL_STATE_CLEARED) {
- // Convert any existing event names and categories on the stack to
- // non-interned strings so we can look up their names even after the
- // incremental state is gone.
- for (auto& frame : sequence_state.track.stack) {
- if (frame.name_iid) {
- frame.name = sequence_state.event_names[frame.name_iid];
- frame.name_iid = 0u;
- }
- if (frame.category_iid) {
- frame.category = sequence_state.event_categories[frame.category_iid];
- frame.category_iid = 0u;
- }
- }
- sequence_state.event_names.clear();
- sequence_state.event_categories.clear();
- sequence_state.debug_annotation_names.clear();
- sequence_state.track.uuid = 0u;
- sequence_state.track.index = 0u;
- }
- if (packet.has_interned_data()) {
- perfetto::protos::pbzero::InternedData::Decoder interned_data(
- packet.interned_data());
- for (auto it = interned_data.event_names(); it; it++) {
- perfetto::protos::pbzero::EventName::Decoder entry(*it);
- sequence_state.event_names[entry.iid()] = entry.name().ToStdString();
- }
- for (auto it = interned_data.event_categories(); it; it++) {
- perfetto::protos::pbzero::EventCategory::Decoder entry(*it);
- sequence_state.event_categories[entry.iid()] = entry.name().ToStdString();
- }
- for (auto it = interned_data.debug_annotation_names(); it; it++) {
- perfetto::protos::pbzero::DebugAnnotationName::Decoder entry(*it);
- sequence_state.debug_annotation_names[entry.iid()] =
- entry.name().ToStdString();
- }
+ClockSnapshotVector CaptureClockSnapshots() {
+ ClockSnapshotVector snapshot_data;
+#if !PERFETTO_BUILDFLAG(PERFETTO_OS_APPLE) && \
+ !PERFETTO_BUILDFLAG(PERFETTO_OS_WIN) && \
+ !PERFETTO_BUILDFLAG(PERFETTO_OS_FREEBSD) && \
+ !PERFETTO_BUILDFLAG(PERFETTO_OS_NACL) && \
+ !PERFETTO_BUILDFLAG(PERFETTO_OS_QNX)
+ struct {
+ clockid_t id;
+ protos::pbzero::BuiltinClock type;
+ struct timespec ts;
+ } clocks[] = {
+ {CLOCK_BOOTTIME, protos::pbzero::BUILTIN_CLOCK_BOOTTIME, {0, 0}},
+ {CLOCK_REALTIME_COARSE,
+ protos::pbzero::BUILTIN_CLOCK_REALTIME_COARSE,
+ {0, 0}},
+ {CLOCK_MONOTONIC_COARSE,
+ protos::pbzero::BUILTIN_CLOCK_MONOTONIC_COARSE,
+ {0, 0}},
+ {CLOCK_REALTIME, protos::pbzero::BUILTIN_CLOCK_REALTIME, {0, 0}},
+ {CLOCK_MONOTONIC, protos::pbzero::BUILTIN_CLOCK_MONOTONIC, {0, 0}},
+ {CLOCK_MONOTONIC_RAW,
+ protos::pbzero::BUILTIN_CLOCK_MONOTONIC_RAW,
+ {0, 0}},
+ };
+ // First snapshot all the clocks as atomically as we can.
+ for (auto& clock : clocks) {
+ if (clock_gettime(clock.id, &clock.ts) == -1)
+ PERFETTO_DLOG("clock_gettime failed for clock %d", clock.id);
}
- if (packet.has_trace_packet_defaults()) {
- perfetto::protos::pbzero::TracePacketDefaults::Decoder defaults(
- packet.trace_packet_defaults());
- if (defaults.has_track_event_defaults()) {
- perfetto::protos::pbzero::TrackEventDefaults::Decoder
- track_event_defaults(defaults.track_event_defaults());
- sequence_state.track.uuid = track_event_defaults.track_uuid();
- if (defaults.has_timestamp_clock_id())
- sequence_state.default_clock_id = defaults.timestamp_clock_id();
- }
+ for (auto& clock : clocks) {
+ snapshot_data.push_back(ClockReading(
+ static_cast<uint32_t>(clock.type),
+ static_cast<uint64_t>(base::FromPosixTimespec(clock.ts).count())));
}
- if (packet.has_track_descriptor()) {
- perfetto::protos::pbzero::TrackDescriptor::Decoder track_descriptor(
- packet.track_descriptor());
- auto* session_state = delegate.GetSessionState();
- auto& track = session_state->tracks[track_descriptor.uuid()];
- if (!track.index)
- track.index = static_cast<uint32_t>(session_state->tracks.size() + 1);
- track.uuid = track_descriptor.uuid();
+#else // OS_APPLE || OS_WIN && OS_NACL
+ auto wall_time_ns = static_cast<uint64_t>(base::GetWallTimeNs().count());
+ // The default trace clock is boot time, so we always need to emit a path to
+ // it. However since we don't actually have a boot time source on these
+ // platforms, pretend that wall time equals boot time.
+ snapshot_data.push_back(
+ ClockReading(protos::pbzero::BUILTIN_CLOCK_BOOTTIME, wall_time_ns));
+ snapshot_data.push_back(
+ ClockReading(protos::pbzero::BUILTIN_CLOCK_MONOTONIC, wall_time_ns));
+#endif
- if (track_descriptor.has_name()) {
- track.name = track_descriptor.name().ToStdString();
- } else if (track_descriptor.has_static_name()) {
- track.name = track_descriptor.static_name().ToStdString();
- }
- track.pid = 0;
- track.tid = 0;
- if (track_descriptor.has_process()) {
- perfetto::protos::pbzero::ProcessDescriptor::Decoder process(
- track_descriptor.process());
- track.pid = process.pid();
- if (track.name.empty())
- track.name = process.process_name().ToStdString();
- } else if (track_descriptor.has_thread()) {
- perfetto::protos::pbzero::ThreadDescriptor::Decoder thread(
- track_descriptor.thread());
- track.pid = thread.pid();
- track.tid = thread.tid();
- if (track.name.empty())
- track.name = thread.thread_name().ToStdString();
- }
- delegate.OnTrackUpdated(track);
+#if PERFETTO_BUILDFLAG(PERFETTO_ARCH_CPU_X86_64)
+ // X86-specific but OS-independent TSC clocksource
+ snapshot_data.push_back(
+ ClockReading(protos::pbzero::BUILTIN_CLOCK_TSC, base::Rdtsc()));
+#endif // PERFETTO_BUILDFLAG(PERFETTO_ARCH_CPU_X86_64)
- // Mirror properties to the default track of the sequence. Note that
- // this does not catch updates to the default track written through other
- // sequences.
- if (track.uuid == sequence_state.track.uuid) {
- sequence_state.track.index = track.index;
- sequence_state.track.name = track.name;
- sequence_state.track.pid = track.pid;
- sequence_state.track.tid = track.tid;
- sequence_state.track.user_data = track.user_data;
- }
- }
+ return snapshot_data;
}
-TrackEventStateTracker::ParsedTrackEvent::ParsedTrackEvent(
- const perfetto::protos::pbzero::TrackEvent::Decoder& track_event_)
- : track_event(track_event_) {}
+} // namespace perfetto::base
+// gen_amalgamated begin source: src/base/version.cc
+// gen_amalgamated begin header: include/perfetto/ext/base/version.h
+/*
+ * 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.
+ */
+
+#ifndef INCLUDE_PERFETTO_EXT_BASE_VERSION_H_
+#define INCLUDE_PERFETTO_EXT_BASE_VERSION_H_
+
+namespace perfetto {
+namespace base {
+
+// The returned pointer is a static string and safe to pass around.
+// Returns a human readable string currently of the approximate form:
+// Perfetto v42.1-deadbeef0 (deadbeef03c641e4b4ea9cf38e9b5696670175a9)
+// However you should not depend on the format of this string.
+// It maybe not be possible to determine the version. In which case the
+// string will be of the approximate form:
+// Perfetto v0.0 (unknown)
+const char* GetVersionString();
+
+// The returned pointer is a static string and safe to pass around.
+// Returns the short code used to identity the version:
+// v42.1-deadbeef0
+// It maybe not be possible to determine the version. In which case
+// this returns nullptr.
+// This can be compared with equality to other
+// version codes to detect matched builds (for example to see if
+// trace_processor_shell and the UI were built at the same revision)
+// but you should not attempt to parse it as the format may change
+// without warning.
+const char* GetVersionCode();
+} // namespace base
} // namespace perfetto
-// gen_amalgamated begin source: src/tracing/virtual_destructors.cc
+
+#endif // INCLUDE_PERFETTO_EXT_BASE_VERSION_H_
+// gen_amalgamated begin header: gen/perfetto_version.gen.h
+// Generated by write_version_header.py
+
+#ifndef GEN_PERFETTO_VERSION_GEN_H_
+#define GEN_PERFETTO_VERSION_GEN_H_
+
+#define PERFETTO_VERSION_STRING() "v59.1-1e9c61e98"
+#define PERFETTO_VERSION_SCM_REVISION() "1e9c61e9844affd7dccd3d42d9ea9f3a3d10cf6d"
+
+#endif // GEN_PERFETTO_VERSION_GEN_H_
/*
- * Copyright (C) 2019 The Android Open Source Project
+ * 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.
@@ -51286,47 +56274,48 @@ TrackEventStateTracker::ParsedTrackEvent::ParsedTrackEvent(
* limitations under the License.
*/
-// gen_amalgamated expanded: #include "perfetto/tracing/internal/tracing_tls.h"
-// gen_amalgamated expanded: #include "perfetto/tracing/tracing.h"
-// gen_amalgamated expanded: #include "perfetto/tracing/tracing_backend.h"
+// gen_amalgamated expanded: #include "perfetto/ext/base/version.h"
-// This translation unit contains the definitions for the destructor of pure
-// virtual interfaces for the src/public:public target. The alternative would be
-// introducing a one-liner .cc file for each pure virtual interface, which is
-// overkill. This is for compliance with -Wweak-vtables.
+// gen_amalgamated expanded: #include "perfetto/base/build_config.h"
+
+#include <stdio.h>
+
+#if PERFETTO_BUILDFLAG(PERFETTO_VERSION_GEN)
+// gen_amalgamated expanded: #include "perfetto_version.gen.h"
+#else
+#define PERFETTO_VERSION_STRING() nullptr
+#define PERFETTO_VERSION_SCM_REVISION() "unknown"
+#endif
namespace perfetto {
-namespace internal {
+namespace base {
-TracingTLS::~TracingTLS() {
- // Avoid entering trace points while the thread is being torn down.
- // This is the problem: when a thread exits, the at-thread-exit destroys the
- // TracingTLS. As part of that the various TraceWriter for the active data
- // sources are destroyd. A TraceWriter dtor will issue a PostTask on the IPC
- // thread to issue a final flush and unregister its ID with the service.
- // The PostTask, in chromium, might have a trace event that will try to
- // re-enter the tracing system.
- // We fix this by resetting the TLS key to the TracingTLS object that is
- // being destroyed in the platform impl (platform_posix.cc,
- // platform_windows.cc, chromium's platform.cc). We carefully rely on the fact
- // that all the tracing path that will be invoked during thread exit will
- // early out if |is_in_trace_point| == true and will not depend on the other
- // TLS state that has been destroyed.
- is_in_trace_point = true;
+const char* GetVersionCode() {
+ return PERFETTO_VERSION_STRING();
}
-} // namespace internal
-
-TracingProducerBackend::~TracingProducerBackend() = default;
-TracingConsumerBackend::~TracingConsumerBackend() = default;
-TracingBackend::~TracingBackend() = default;
+const char* GetVersionString() {
+ static const char* version_str = [] {
+ static constexpr size_t kMaxLen = 256;
+ const char* version_code = PERFETTO_VERSION_STRING();
+ if (version_code == nullptr) {
+ version_code = "v0.0";
+ }
+ char* version = new char[kMaxLen + 1];
+ snprintf(version, kMaxLen, "Perfetto %s (%s)", version_code,
+ PERFETTO_VERSION_SCM_REVISION());
+ return version;
+ }();
+ return version_str;
+}
+} // namespace base
} // namespace perfetto
-// gen_amalgamated begin source: src/android_stats/statsd_logging_helper.cc
-// gen_amalgamated begin header: src/android_stats/statsd_logging_helper.h
-// gen_amalgamated begin header: src/android_stats/perfetto_atoms.h
+// gen_amalgamated begin source: src/protovm/allocator.cc
+// gen_amalgamated begin header: src/protovm/allocator.h
+// gen_amalgamated begin header: src/protovm/error_handling.h
/*
- * Copyright (C) 2020 The Android Open Source Project
+ * Copyright (C) 2025 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.
@@ -51341,136 +56330,341 @@ TracingBackend::~TracingBackend() = default;
* limitations under the License.
*/
-#ifndef SRC_ANDROID_STATS_PERFETTO_ATOMS_H_
-#define SRC_ANDROID_STATS_PERFETTO_ATOMS_H_
+#ifndef SRC_PROTOVM_ERROR_HANDLING_H_
+#define SRC_PROTOVM_ERROR_HANDLING_H_
+
+#include <cstdarg>
+#include <cstdint>
+#include <memory>
+#include <new>
+#include <string>
+#include <type_traits>
+#include <vector>
+
+// gen_amalgamated expanded: #include "perfetto/base/compiler.h"
+// gen_amalgamated expanded: #include "perfetto/base/logging.h"
+
+#if defined(__GNUC__) || defined(__clang__)
+#if defined(__clang__)
+#pragma clang diagnostic push
+// Fix 'error: #pragma system_header ignored in main file' for amalgamated
+// build.
+#pragma clang diagnostic ignored "-Wpragma-system-header-outside-header"
+#endif
+
+// Ignore GCC warning about a missing argument for a variadic macro parameter.
+#pragma GCC system_header
+
+#if defined(__clang__)
+#pragma clang diagnostic pop
+#endif
+#endif
namespace perfetto {
+namespace protovm {
-// This must match the values of the PerfettoUploadEvent enum in:
-// frameworks/proto_logging/stats/atoms.proto
-enum class PerfettoStatsdAtom {
- kUndefined = 0,
+using Stacktrace = std::vector<std::string>;
- // Checkpoints inside perfetto_cmd before tracing is finished.
- kTraceBegin = 1,
- kBackgroundTraceBegin = 2,
- kCmdCloneTraceBegin = 55,
- kCmdCloneTriggerTraceBegin = 56,
- kOnConnect = 3,
- kCmdOnSessionClone = 58,
- kCmdOnTriggerSessionClone = 59,
+void LogStacktraceMessage(Stacktrace& stacktrace,
+ const char* file_name,
+ int file_line,
+ const char* fmt,
+ ...) PERFETTO_PRINTF_FORMAT(4, 5);
- // Guardrails inside perfetto_cmd before tracing is finished.
- kOnTimeout = 16,
+// overload for calls without message args
+void LogStacktraceMessage(Stacktrace& stacktrace,
+ const char* file_name,
+ int file_line);
- // Checkpoints inside traced.
- kTracedEnableTracing = 37,
- kTracedStartTracing = 38,
- kTracedDisableTracing = 39,
- kTracedNotifyTracingDisabled = 40,
+#define PROTOVM_ABORT(fmt, ...) \
+ do { \
+ auto status_abort = StatusOr<void>::Abort(); \
+ LogStacktraceMessage(status_abort.stacktrace(), \
+ ::perfetto::base::LoggingBasename(__FILE__), \
+ __LINE__, fmt, ##__VA_ARGS__); \
+ return status_abort; \
+ } while (0)
- // Trigger checkpoints inside traced.
- // These atoms are special because, along with the UUID,
- // they log the trigger name.
- kTracedTriggerStartTracing = 41,
- kTracedTriggerStopTracing = 42,
- kTracedTriggerCloneSnapshot = 53,
+#define PROTOVM_RETURN(s, ...) \
+ do { \
+ if (s.IsAbort()) { \
+ LogStacktraceMessage(s.stacktrace(), \
+ ::perfetto::base::LoggingBasename(__FILE__), \
+ __LINE__, ##__VA_ARGS__); \
+ } \
+ return s; \
+ } while (0)
- // Guardrails inside traced.
- kTracedEnableTracingExistingTraceSession = 18,
- kTracedEnableTracingTooLongTrace = 19,
- kTracedEnableTracingInvalidTriggerTimeout = 20,
- kTracedEnableTracingDurationWithTrigger = 21,
- kTracedEnableTracingStopTracingWriteIntoFile = 22,
- kTracedEnableTracingDuplicateTriggerName = 23,
- kTracedEnableTracingInvalidDeferredStart = 24,
- kTracedEnableTracingInvalidBufferSize = 25,
- kTracedEnableTracingBufferSizeTooLarge = 26,
- kTracedEnableTracingTooManyBuffers = 27,
- kTracedEnableTracingDuplicateSessionName = 28,
- kTracedEnableTracingSessionNameTooRecent = 29,
- kTracedEnableTracingTooManySessionsForUid = 30,
- kTracedEnableTracingTooManyConcurrentSessions = 31,
- kTracedEnableTracingInvalidFdOutputFile = 32,
- kTracedEnableTracingFailedToCreateFile = 33,
- kTracedEnableTracingOom = 34,
- kTracedEnableTracingUnknown = 35,
- kTracedStartTracingInvalidSessionState = 36,
- kTracedEnableTracingInvalidFilter = 47,
- kTracedEnableTracingOobTargetBuffer = 48,
- kTracedEnableTracingInvalidTriggerMode = 52,
- kTracedEnableTracingInvalidBrFilename = 54,
- kTracedEnableTracingFailedSessionSemaphoreCheck = 57,
- kTracedEnablePriorityBoostInvalidConfig = 61,
- kTracedEnablePriorityBoostOtherError = 62,
- kTracedEnableTracingExclusiveSessionRejected = 63,
- kTracedEnableTracingExclusiveSessionNotAllowed = 64,
- kTracedEnableTracingDuplicateBufferName = 65,
+#define PROTOVM_RETURN_IF_NOT_OK(s, ...) \
+ do { \
+ if (s.IsAbort()) { \
+ LogStacktraceMessage(s.stacktrace(), \
+ ::perfetto::base::LoggingBasename(__FILE__), \
+ __LINE__, ##__VA_ARGS__); \
+ return s; \
+ } \
+ if (!s.IsOk()) { \
+ return s; \
+ } \
+ } while (0)
- // Checkpoints inside perfetto_cmd after tracing has finished.
- kOnTracingDisabled = 4,
- kFinalizeTraceAndExit = 11,
- kCmdFwReportBegin = 49,
- // Will be removed once incidentd is no longer used.
- kUploadIncidentBegin = 8,
- kNotUploadingEmptyTrace = 17,
+#define PROTOVM_INTERNAL_CONCAT_IMPL(x, y) x##y
+#define PROTOVM_INTERNAL_MACRO_CONCAT(x, y) PROTOVM_INTERNAL_CONCAT_IMPL(x, y)
- // Guardrails inside perfetto_cmd after tracing has finished.
- kCmdFwReportEmptyTrace = 50,
- // Will be removed once incidentd is no longer used.
- kUploadIncidentFailure = 10,
+// Evaluates |rhs| which should return a StatusOr<T> and assigns this
+// to |lhs|. If the status is an error status, returns the status from the
+// current function.
+#define PROTOVM_ASSIGN_OR_RETURN(lhs, rhs) \
+ PROTOVM_INTERNAL_MACRO_CONCAT(auto status_or, __LINE__) = rhs; \
+ PROTOVM_RETURN_IF_NOT_OK( \
+ PROTOVM_INTERNAL_MACRO_CONCAT(status_or, __LINE__)); \
+ lhs = std::move(PROTOVM_INTERNAL_MACRO_CONCAT(status_or, __LINE__).value())
- // "Successful" terminal states inside perfetto_cmd.
- kCmdFwReportHandoff = 51,
+enum class Status : uint8_t {
+ kOk,
+ kError,
+
+ // It causes an abort of the whole VM's program. Typically indicates a
+ // fundamental issue with the program and requires developer's intervention.
+ kAbort,
+};
+
+namespace internal {
+
+template <class T, class Arg, class... Args>
+static constexpr bool is_copy_or_move_ctor_arg_v =
+ sizeof...(Args) == 0 && std::is_same_v<T, std::decay_t<Arg>>;
+
+template <class T>
+inline constexpr std::size_t sizeof_v = sizeof(T);
+
+template <>
+inline constexpr std::size_t sizeof_v<void> = 0;
+
+template <class T>
+inline constexpr std::size_t alignof_v = alignof(T);
+
+template <>
+inline constexpr std::size_t alignof_v<void> = 0;
+
+} // namespace internal
+
+template <class T>
+class StatusOr {
+ public:
+ // Factory methods to create empty instances (without value)
+ static StatusOr Ok() { return StatusOr{Status::kOk}; }
+ static StatusOr Error() { return StatusOr{Status::kError}; }
+ static StatusOr Abort() { return StatusOr{Status::kAbort}; }
+
+ StatusOr(const StatusOr&) = delete;
+
+ StatusOr(StatusOr&& other) : status_{other.status_} {
+ if (IsOk()) {
+ if constexpr (!std::is_same_v<T, void>) {
+ new (storage_) T(std::move(other.value()));
+ }
+ } else if (IsAbort()) {
+ new (storage_) std::unique_ptr<Stacktrace>(
+ std::move(other.GetStacktraceUniquePtr()));
+ }
+ }
+
+ // Intentionally implicit to allow idiomatic usage (return plain value to be
+ // implicitly converted to StatusOr)
+ template <
+ class... Args,
+ // sfinae to avoid clashing with copy/move constructors
+ std::enable_if_t<!internal::is_copy_or_move_ctor_arg_v<StatusOr, Args...>,
+ int> = 0>
+ StatusOr(Args&&... args) : status_{Status::kOk} {
+ if constexpr (!std::is_same_v<T, void>) {
+ new (storage_) T(std::forward<Args>(args)...);
+ }
+ }
+
+ // Intentionally implicit to allow idiomatic usage (e.g. return StatusOr<A> to
+ // be implicitely converted to StatusOr<B>).
+ // When status is ok, the conversion is only allowed if B = void, otherwise it
+ // would require a conversion from A to non-void B.
+ template <class U, std::enable_if_t<!std::is_same_v<U, T>, int> = 0>
+ StatusOr(StatusOr<U>&& other) : status_{other.status_} {
+ if (IsOk()) {
+ PERFETTO_DCHECK((std::is_same_v<T, void>));
+ } else if (IsAbort()) {
+ new (storage_) std::unique_ptr<Stacktrace>(
+ std::move(other.GetStacktraceUniquePtr()));
+ }
+ }
+
+ ~StatusOr() {
+ if (IsOk()) {
+ if constexpr (!std::is_same_v<T, void>) {
+ value().~T();
+ }
+ }
+ if (IsAbort()) {
+ GetStacktraceUniquePtr().~unique_ptr();
+ }
+ }
+
+ bool IsOk() const { return status_ == Status::kOk; }
+ bool IsError() const { return status_ == Status::kError; }
+ bool IsAbort() const { return status_ == Status::kAbort; }
+
+ template <class U = T>
+ std::enable_if_t<!std::is_same_v<U, void>, U&> value() {
+ PERFETTO_DCHECK(IsOk());
+ return *std::launder(reinterpret_cast<T*>(storage_));
+ }
+
+ template <class U = T>
+ std::enable_if_t<!std::is_same_v<U, void>, const U&> value() const {
+ return const_cast<StatusOr*>(this)->value();
+ }
+
+ template <class U = T>
+ std::enable_if_t<!std::is_same_v<U, void>, U&> operator*() {
+ return value();
+ }
+
+ template <class U = T>
+ std::enable_if_t<!std::is_same_v<U, void>, const U&> operator*() const {
+ return value();
+ }
+
+ template <class U = T>
+ std::enable_if_t<!std::is_same_v<U, void>, U*> operator->() {
+ return &value();
+ }
+
+ template <class U = T>
+ std::enable_if_t<!std::is_same_v<U, void>, const U*> operator->() const {
+ return &value();
+ }
+
+ Stacktrace& stacktrace() {
+ PERFETTO_DCHECK(IsAbort());
+ return **std::launder(
+ reinterpret_cast<std::unique_ptr<Stacktrace>*>(storage_));
+ }
+
+ private:
+ template <class U>
+ friend class StatusOr;
+
+ // Intentionally private to encourage the use of factory methods, instead of
+ // plain status values. E.g. StatusOr::Abort() instead of Status::kAbort.
+ // Plain status value don't include stacktrace information in case of an
+ // abort.
+ explicit StatusOr(Status status) : status_{status} {
+ PERFETTO_DCHECK((std::is_same_v<T, void>) || !IsOk());
+ if (IsAbort()) {
+ new (storage_) std::unique_ptr<Stacktrace>{new Stacktrace{}};
+ }
+ }
- // Deprecated as "success" is misleading; it simply means we were
- // able to communicate with incidentd. Will be removed once
- // incidentd is no longer used.
- kUploadIncidentSuccess = 9,
+ std::unique_ptr<Stacktrace>& GetStacktraceUniquePtr() {
+ PERFETTO_DCHECK(IsAbort());
+ return *std::launder(
+ reinterpret_cast<std::unique_ptr<Stacktrace>*>(storage_));
+ }
- // Contained trigger begin/success/failure. Replaced by
- // |PerfettoTriggerAtom| to allow aggregation using a count metric
- // and reduce spam.
- // reserved 12, 13, 14;
+ Status status_;
- // Contained that a guardrail in perfetto_cmd was hit. Replaced with
- // kCmd* guardrails.
- // reserved 15;
+ static constexpr size_t kStorageAlign =
+ std::max(internal::alignof_v<T>, alignof(std::unique_ptr<Stacktrace>));
+ static constexpr size_t kStorageSize =
+ std::max(internal::sizeof_v<T>, sizeof(std::unique_ptr<Stacktrace>));
+ alignas(kStorageAlign) unsigned char storage_[kStorageSize];
+};
- // Contained status of Dropbox uploads. Removed as Perfetto no
- // longer supports uploading traces using Dropbox.
- // reserved 5, 6, 7;
+} // namespace protovm
+} // namespace perfetto
- // Contained status of guardrail state initialization and upload limit in
- // perfetto_cmd. Removed as perfetto no longer manages stateful guardrails
- // reserved 44, 45, 46;
+#endif // SRC_PROTOVM_ERROR_HANDLING_H_
+// gen_amalgamated begin header: src/protovm/node.h
+// gen_amalgamated begin header: src/protovm/owned_ptr.h
+/*
+ * Copyright (C) 2025 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.
+ */
- // Contained the guardrail for user build tracing. Removed as this guardrail
- // causes more problem than it solves these days.
- // reserved 43;
-};
+#ifndef SRC_PROTOVM_OWNED_PTR_H_
+#define SRC_PROTOVM_OWNED_PTR_H_
-// This must match the values of the PerfettoTrigger::TriggerType enum in:
-// frameworks/proto_logging/stats/atoms.proto
-enum PerfettoTriggerAtom {
- kUndefined = 0,
+// gen_amalgamated expanded: #include "perfetto/base/logging.h"
- kTracedLimitProbability = 5,
- kTracedLimitMaxPer24h = 6,
+namespace perfetto {
+namespace protovm {
- kTracedTrigger = 9,
+// OwnedPtr is essentially a std::unique_ptr that doesn't perform any deletion
+// itself. Its purpose is to clearly express ownership semantics for objects
+// that are managed with a custom allocators.
+//
+// It is not a unique_ptr, because that's not guaranteed to be standard layout
+//
+// OwnedPtr is extensively used within RwProto to manage the lifecycle and
+// clarify ownership of the internal, manually-allocated nodes.
+template <class T>
+class OwnedPtr {
+ public:
+ using pointer = T*;
+ OwnedPtr(const OwnedPtr&) = delete;
+ OwnedPtr(OwnedPtr&& other) {
+ p_ = other.p_;
+ other.p_ = nullptr;
+ }
+ OwnedPtr(T* p) noexcept : p_(p) {} // NOLINT: explicit
+ ~OwnedPtr() noexcept { reset(); }
+ OwnedPtr& operator=(const OwnedPtr&) = delete;
+ OwnedPtr& operator=(OwnedPtr&& other) noexcept {
+ if (this == &other) {
+ return *this;
+ }
+ reset();
+ p_ = other.p_;
+ other.p_ = nullptr;
+ return *this;
+ }
+ T* get() const noexcept { return p_; }
+ T* release() noexcept {
+ T* p = p_;
+ p_ = nullptr;
+ return p;
+ }
+ typename std::add_lvalue_reference<T>::type operator*() const noexcept {
+ return *p_;
+ }
+ explicit operator bool() const noexcept { return get() != nullptr; }
+ T* operator->() const noexcept { return p_; }
+ void reset(T* p = pointer()) noexcept {
+ PERFETTO_DCHECK(p_ == nullptr);
+ p_ = p;
+ }
- // Contained events of logging triggers through perfetto_cmd, probes and
- // trigger_perfetto.
- // Removed in W (Oct 2024) and replaced by |kTracedTrigger|.
- // reserved 1, 2, 3, 4, 7, 8
+ private:
+ T* p_ = nullptr;
};
+} // namespace protovm
} // namespace perfetto
-#endif // SRC_ANDROID_STATS_PERFETTO_ATOMS_H_
+#endif // SRC_PROTOVM_OWNED_PTR_H_
+// gen_amalgamated begin header: src/protovm/scalar.h
/*
- * Copyright (C) 2020 The Android Open Source Project
+ * Copyright (C) 2025 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.
@@ -51485,40 +56679,43 @@ enum PerfettoTriggerAtom {
* limitations under the License.
*/
-#ifndef SRC_ANDROID_STATS_STATSD_LOGGING_HELPER_H_
-#define SRC_ANDROID_STATS_STATSD_LOGGING_HELPER_H_
-
-#include <stdint.h>
-#include <optional>
-#include <string>
-#include <vector>
+#ifndef SRC_PROTOVM_SCALAR_H_
+#define SRC_PROTOVM_SCALAR_H_
-// gen_amalgamated expanded: #include "src/android_stats/perfetto_atoms.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/proto_utils.h"
namespace perfetto {
-namespace android_stats {
+namespace protovm {
-// Functions in this file are only active on built in the Android
-// tree. On other platforms (including Android standalone and Chromium
-// on Android) these functions are a noop.
+struct Scalar {
+ static Scalar Fixed32(uint32_t value) {
+ return Scalar{protozero::proto_utils::ProtoWireType::kFixed32, value};
+ }
-// Logs the upload event to statsd if built in the Android tree.
-void MaybeLogUploadEvent(PerfettoStatsdAtom atom,
- int64_t uuid_lsb,
- int64_t uuid_msb,
- const std::string& trigger_name = "");
+ static Scalar Fixed64(uint64_t value) {
+ return Scalar{protozero::proto_utils::ProtoWireType::kFixed64, value};
+ }
-// Logs the trigger events to statsd if built in the Android tree.
-void MaybeLogTriggerEvent(PerfettoTriggerAtom atom,
- int64_t uuid_lsb,
- const std::string& trigger);
+ static Scalar VarInt(uint64_t value) {
+ return Scalar{protozero::proto_utils::ProtoWireType::kVarInt, value};
+ }
-} // namespace android_stats
+ bool operator==(const Scalar& other) const {
+ return wire_type == other.wire_type && value == other.value;
+ }
+
+ bool operator!=(const Scalar& other) const { return !(*this == other); }
+
+ protozero::proto_utils::ProtoWireType wire_type;
+ uint64_t value;
+};
+
+} // namespace protovm
} // namespace perfetto
-#endif // SRC_ANDROID_STATS_STATSD_LOGGING_HELPER_H_
+#endif // SRC_PROTOVM_SCALAR_H_
/*
- * Copyright (C) 2020 The Android Open Source Project
+ * Copyright (C) 2025 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.
@@ -51533,62 +56730,92 @@ void MaybeLogTriggerEvent(PerfettoTriggerAtom atom,
* limitations under the License.
*/
-// gen_amalgamated expanded: #include "src/android_stats/statsd_logging_helper.h"
+#ifndef SRC_PROTOVM_NODE_H_
+#define SRC_PROTOVM_NODE_H_
-#include <cstdint>
-#include <string>
-#include <vector>
+#include <type_traits>
+#include <variant>
-// gen_amalgamated expanded: #include "perfetto/base/build_config.h"
-// gen_amalgamated expanded: #include "src/android_stats/perfetto_atoms.h"
+// gen_amalgamated expanded: #include "perfetto/ext/base/intrusive_tree.h"
+// gen_amalgamated expanded: #include "src/protovm/owned_ptr.h"
+// gen_amalgamated expanded: #include "src/protovm/scalar.h"
-#if PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID) && \
- PERFETTO_BUILDFLAG(PERFETTO_ANDROID_BUILD)
-// gen_amalgamated expanded: #include "src/android_internal/lazy_library_loader.h" // nogncheck
-// gen_amalgamated expanded: #include "src/android_internal/statsd_logging.h" // nogncheck
-#endif
+namespace perfetto {
+namespace protovm {
-namespace perfetto::android_stats {
+struct Node;
-// Make sure we don't accidentally log on non-Android tree build. Note that even
-// removing this ifdef still doesn't make uploads work on OS_ANDROID.
-// PERFETTO_LAZY_LOAD will return a nullptr on non-Android and non-in-tree
-// builds as libperfetto_android_internal will not be available.
-#if PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID) && \
- PERFETTO_BUILDFLAG(PERFETTO_ANDROID_BUILD)
+struct MapNode {
+ struct Traits {
+ using KeyType = uint64_t;
+ static constexpr size_t NodeOffset() {
+ static_assert(std::is_standard_layout_v<MapNode>);
+ return offsetof(MapNode, node);
+ }
+ static const KeyType& GetKey(const MapNode& n) { return n.key; }
+ };
-void MaybeLogUploadEvent(PerfettoStatsdAtom atom,
- int64_t uuid_lsb,
- int64_t uuid_msb,
- const std::string& trigger_name) {
- PERFETTO_LAZY_LOAD(android_internal::StatsdLogUploadEvent, log_event_fn);
- if (log_event_fn) {
- log_event_fn(atom, uuid_lsb, uuid_msb, trigger_name.c_str());
+ MapNode(uint64_t k, OwnedPtr<Node> v) : key{k}, value{std::move(v)} {}
+
+ base::IntrusiveTreeNode node{};
+ uint64_t key;
+ OwnedPtr<Node> value;
+};
+
+using IntrusiveMap = base::IntrusiveTree<MapNode, MapNode::Traits>;
+
+struct Node {
+ struct Bytes {
+ OwnedPtr<void> data;
+ size_t size;
+ };
+
+ struct Empty {};
+
+ struct MappedRepeatedField {
+ IntrusiveMap key_to_node;
+ };
+
+ struct IndexedRepeatedField {
+ IntrusiveMap index_to_node;
+ };
+
+ struct Message {
+ IntrusiveMap field_id_to_node;
+ };
+
+ template <class T>
+ T* GetIf() {
+ return std::get_if<T>(&value);
}
-}
-void MaybeLogTriggerEvent(PerfettoTriggerAtom atom,
- int64_t uuid_lsb,
- const std::string& trigger_name) {
- PERFETTO_LAZY_LOAD(android_internal::StatsdLogTriggerEvent, log_event_fn);
- if (log_event_fn) {
- log_event_fn(atom, uuid_lsb, trigger_name.c_str());
+ template <class T>
+ const T* GetIf() const {
+ return std::get_if<T>(&value);
}
-}
-#else
-void MaybeLogUploadEvent(PerfettoStatsdAtom,
- int64_t,
- int64_t,
- const std::string&) {}
-void MaybeLogTriggerEvent(PerfettoTriggerAtom, int64_t, const std::string&) {}
-#endif
+ const char* GetTypeName() const;
-} // namespace perfetto::android_stats
-// gen_amalgamated begin source: src/base/regex/regex.cc
-// gen_amalgamated begin header: include/perfetto/ext/base/regex.h
+ std::variant<Bytes,
+ Empty,
+ IndexedRepeatedField,
+ MappedRepeatedField,
+ Message,
+ Scalar>
+ value;
+
+ // Flag needed to track the merge state of repeated fields
+ // (see implementation of Merge operation in RW proto)
+ bool has_been_merged = false;
+};
+
+} // namespace protovm
+} // namespace perfetto
+
+#endif // SRC_PROTOVM_NODE_H_
+// gen_amalgamated begin header: src/protovm/slab_allocator.h
/*
- * Copyright (C) 2026 The Android Open Source Project
+ * Copyright (C) 2025 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.
@@ -51603,180 +56830,280 @@ void MaybeLogTriggerEvent(PerfettoTriggerAtom, int64_t, const std::string&) {}
* limitations under the License.
*/
-#ifndef INCLUDE_PERFETTO_EXT_BASE_REGEX_H_
-#define INCLUDE_PERFETTO_EXT_BASE_REGEX_H_
-
-#include <cstdint>
-#include <memory>
-#include <optional>
-#include <string>
-#include <string_view>
-#include <vector>
-
-// gen_amalgamated expanded: #include "perfetto/ext/base/status_or.h"
+#ifndef SRC_PROTOVM_SLAB_ALLOCATOR_H_
+#define SRC_PROTOVM_SLAB_ALLOCATOR_H_
-namespace perfetto {
-namespace base {
+#include <cstdlib>
+#include <new>
-// Pimpl for the regex engine. Defined in src/base/regex/regex.cc.
-class RegexImpl;
+// gen_amalgamated expanded: #include "perfetto/base/logging.h"
+// gen_amalgamated expanded: #include "perfetto/ext/base/flat_hash_map.h"
+// gen_amalgamated expanded: #include "perfetto/ext/base/intrusive_list.h"
+// gen_amalgamated expanded: #include "perfetto/ext/base/paged_memory.h"
-// A regular expression abstraction that hides the underlying engine.
+// An efficient allocator for elements with fixed size and alignment
+// requirements.
//
-// Construct via the two static factories:
-// - Create() – fallible; returns StatusOr<Regex>.
-// - CreateOrCheck() – infallible; crashes on invalid pattern.
-// Use for compile-time constant patterns only.
+// Design doc: go/perfetto-protovm-implementation
//
-// Regex is movable but NOT copyable. Use CopyableRegex when copy semantics
-// are needed (e.g. for storage in copyable containers).
+// Key features:
//
-// Patterns use ECMAScript syntax, supporting Perl-style shorthands (\d, \w,
-// \s).
+// - Slab allocation: Instead of requesting memory for each individual element,
+// this allocator pre-allocates large memory chunks (slabs). Each slab is
+// designed to hold multiple elements.
//
-// Operations:
-// GlobalReplace() – global substitution; returns a new string.
-// FullMatch() – anchored, no groups.
-// FullMatchWithGroups() – anchored, with capture groups.
-// PartialMatch() – unanchored, no groups.
-// PartialMatchWithGroups() – unanchored, with capture groups.
-// PartialMatchAll() – iterator over all non-overlapping matches.
-class Regex {
+// - Element free list: A free list tracks available elements within each
+// individual slab, allowing for O(1) access time during allocation.
+//
+// - Slab intrusive lists: Slabs are managed within one of two intrusive lists.
+// The "non-full slabs" list and the "full slabs" list. This organization
+// allows "non-full" slabs (those with available space for new allocations) to
+// be accessed in O(1) time.
+//
+// - Block-to-Slab hash map: A hash map links 4KB-aligned memory blocks to their
+// corresponding slab. This enables O(1) mapping of an element back to its
+// slab during deallocation.
+//
+// Allocation process:
+// 1. If there is no free slab
+// 1.1 Allocate a new slab, add it to the “non-full slabs” list, populate the
+// block-to-slab map
+// 2. Pick any slab from the “non-full slabs” list
+// 3. Allocate the element
+// 4. If needed, move the slab to the “full slabs” list
+//
+// Deallocation process:
+// 1. Find slab from the block-to-slab map
+// 2. Free element
+// 3. If needed, move to the “non-full slabs” list
+// 4. If needed, deallocate the slab.
+
+namespace perfetto {
+namespace protovm {
+
+namespace internal {
+static constexpr size_t k4KiloBytes = static_cast<size_t>(4096);
+}
+
+template <size_t ElementSize, size_t ElementAlign, size_t Blocks4KB>
+class Slab {
public:
- // Controls whether matching is case-sensitive or case-insensitive.
- enum class CaseSensitivity : uint8_t {
- kSensitive,
- kInsensitive,
+ struct IntrusiveListTraits {
+ static constexpr size_t node_offset() {
+ return offsetof(Slab, intrusive_list_node_);
+ }
};
- Regex(Regex&&) noexcept;
- Regex& operator=(Regex&&) noexcept;
- ~Regex();
+ Slab() : paged_memory_(base::PagedMemory::Allocate(ElementSize * kCapacity)) {
+ PERFETTO_CHECK(paged_memory_.IsValid());
- // Regex is not copyable. Use CopyableRegex for copy semantics.
- Regex(const Regex&) = delete;
- Regex& operator=(const Regex&) = delete;
+ // Expect allocated memory to be always 4KB-aligned
+ PERFETTO_CHECK(reinterpret_cast<uintptr_t>(paged_memory_.Get()) %
+ internal::k4KiloBytes ==
+ 0);
- // Compiles |pattern| into a Regex.
- // Returns an error if the pattern syntax is invalid.
- static StatusOr<Regex> Create(
- std::string_view pattern,
- CaseSensitivity cs = CaseSensitivity::kSensitive);
+ ConstructSlots();
+ InitializeSlotsFreeList();
+ }
- // Like Create(), but crashes (PERFETTO_CHECK) on an invalid pattern.
- // Use only for patterns that are known at compile time.
- static Regex CreateOrCheck(std::string_view pattern,
- CaseSensitivity cs = CaseSensitivity::kSensitive);
+ ~Slab() { DestroySlots(); }
- // Replaces every occurrence of the regex in |s| with |replacement| and
- // returns the resulting string. |s| is unchanged.
- std::string GlobalReplace(std::string_view s,
- std::string_view replacement) const;
+ void* Allocate() {
+ PERFETTO_DCHECK(next_free_slot_);
+ auto* slot = next_free_slot_;
+ next_free_slot_ = next_free_slot_->next;
+ ++size_;
+ return slot;
+ }
- // Returns true if the regex matches the entirety of |s|.
- bool FullMatch(std::string_view s) const;
+ void Free(void* p) {
+ auto* slot = static_cast<Slot*>(p);
+ PERFETTO_DCHECK(slot >= slots() && slot < slots() + kCapacity);
+ slot->next = next_free_slot_;
+ next_free_slot_ = slot;
+ --size_;
+ }
- // Like FullMatch(), but also fills |out| with captured groups on success.
- // out[0] – the full match.
- // out[1..N] – the parenthesised sub-groups.
- // Returns false (and clears |out|) when there is no match.
- //
- // The string_views in |out| point into |s|; they are invalidated if |s| is
- // modified or destroyed.
- bool FullMatchWithGroups(std::string_view s,
- std::vector<std::string_view>& out) const;
+ bool IsFull() const { return size_ == kCapacity; }
- // Returns true if the regex matches any substring of |s|.
- bool PartialMatch(std::string_view s) const;
+ bool IsEmpty() const { return size_ == 0; }
+
+ const void* GetBeginAddress() const {
+ return const_cast<Slab*>(this)->slots();
+ }
+
+ const void* GetEndAddress() const {
+ return const_cast<Slab*>(this)->slots() + kCapacity;
+ }
+
+ private:
+ static constexpr size_t kCapacity =
+ Blocks4KB * (internal::k4KiloBytes / ElementSize);
+
+ static_assert(kCapacity >= 128,
+ "The configured number of 4KB blocks per slab seems too small, "
+ "resulting in a low slab capacity. Slab allocation is "
+ "expensive (involves syscalls), so a high elements-to-slab "
+ "ratio is desirable to amortize the cost.");
+
+ static_assert(ElementAlign <= internal::k4KiloBytes,
+ "SlabAllocator currently supports alignment <= 4KB");
+
+ union Slot {
+ Slot* next;
+ alignas(ElementAlign) unsigned char element[ElementSize];
+ };
+
+ void InitializeSlotsFreeList() {
+ next_free_slot_ = &slots()[0];
+
+ for (size_t i = 0; i + 1 < kCapacity; ++i) {
+ auto& slot = slots()[i];
+ auto& next_slot = slots()[i + 1];
+ slot.next = &next_slot;
+ }
+
+ auto& last_slot = slots()[kCapacity - 1];
+ last_slot.next = nullptr;
+ }
+
+ void ConstructSlots() {
+ auto* slot = slots();
+ for (size_t i = 0; i < kCapacity; ++i) {
+ new (&slot[i]) Slot();
+ }
+ }
+
+ void DestroySlots() {
+ auto* slot = slots();
+ for (size_t i = 0; i < kCapacity; ++i) {
+ slot[i].~Slot();
+ }
+ }
+
+ Slot* slots() {
+ return std::launder(reinterpret_cast<Slot*>(paged_memory_.Get()));
+ }
+
+ Slot* next_free_slot_{nullptr};
+ size_t size_{0};
+ base::IntrusiveListNode intrusive_list_node_;
+ base::PagedMemory paged_memory_;
+};
+
+template <size_t ElementSize, size_t ElementAlign, size_t Blocks4KBPerSlab = 16>
+class SlabAllocator {
+ public:
+ ~SlabAllocator() {
+ DeleteSlabs(slabs_non_full_);
+ DeleteSlabs(slabs_full_);
+ }
- // Like PartialMatch(), but also fills |out| with captured groups on success.
- // out[0] – the full match.
- // out[1..N] – the parenthesised sub-groups.
- // Returns false (and clears |out|) when there is no match.
- //
- // The string_views in |out| point into |s|; they are invalidated if |s| is
- // modified or destroyed.
- bool PartialMatchWithGroups(std::string_view s,
- std::vector<std::string_view>& out) const;
+ void* Allocate() {
+ // Create new slab if needed
+ if (slabs_non_full_.empty()) {
+ auto* slab = new SlabType();
+ slabs_non_full_.PushFront(*slab);
+ ++slabs_non_full_size_;
+ InsertHashMapEntries(*slab);
+ }
- // Iterator over all non-overlapping matches in a string.
- class PartialMatchIterator {
- public:
- // Returns the next match, or std::nullopt when no more matches remain.
- std::optional<std::string_view> Next();
+ // Allocate using any non-full slab
+ auto& slab = slabs_non_full_.front();
+ auto* allocated = slab.Allocate();
+ PERFETTO_CHECK(allocated);
- // Returns the next match with capture groups. Groups are filled into
- // |groups|. Returns std::nullopt when no more matches remain.
- std::optional<std::string_view> NextWithGroups(
- std::vector<std::string_view>& groups);
+ // Move to "full slabs" list if needed
+ if (slab.IsFull()) {
+ slabs_non_full_.Erase(slab);
+ --slabs_non_full_size_;
+ slabs_full_.PushFront(slab);
+ }
- private:
- friend class Regex;
- PartialMatchIterator(const Regex* re, std::string_view input);
- const Regex* re_;
- std::string_view input_;
- size_t offset_ = 0;
- std::vector<std::string_view> groups_; // Cached for Next().
- };
+ return allocated;
+ }
- // Returns an iterator that yields all non-overlapping matches in |s|.
- PartialMatchIterator PartialMatchAll(std::string_view s) const;
+ void Free(void* p) {
+ auto& slab = FindSlabInHashMap(p);
- // Accessors for pattern and case sensitivity (used by CopyableRegex).
- const std::string& pattern() const { return pattern_; }
- CaseSensitivity case_sensitivity() const { return cs_; }
+ // Move to "non-full slabs" list if needed
+ if (slab.IsFull()) {
+ slabs_full_.Erase(slab);
+ slabs_non_full_.PushFront(slab);
+ ++slabs_non_full_size_;
+ }
- private:
- Regex() = default;
- std::unique_ptr<RegexImpl> impl_;
- std::string pattern_;
- CaseSensitivity cs_ = CaseSensitivity::kSensitive;
-};
+ slab.Free(p);
-// A copyable wrapper around Regex. Copying re-compiles the pattern from the
-// stored string, so prefer moving when the source is no longer needed.
-//
-// Use this class when Regex needs to be stored in a copyable container
-// (e.g. std::optional in a copyable struct).
-class CopyableRegex {
- public:
- explicit CopyableRegex(Regex regex);
+ // Deallocate the slab if it becomes empty and it's not the sole non-full
+ // slab.
+ //
+ // The "is not the sole non-full slab" condition avoids thrashing scenarios
+ // where a slab is repeatedly allocated and deallocated. For example:
+ // 1. Allocate element x -> a new slab is allocated.
+ // 2. Free element x -> slab becomes empty and is deallocated.
+ // 3. Allocate element y -> a new slab is allocated again.
+ // 4. And so on...
+ if (slab.IsEmpty() && slabs_non_full_size_ > 1) {
+ EraseHashMapEntries(slab);
+ slabs_non_full_.Erase(slab);
+ --slabs_non_full_size_;
+ delete &slab;
+ }
+ }
- CopyableRegex(const CopyableRegex& other);
- CopyableRegex& operator=(const CopyableRegex& other);
- CopyableRegex(CopyableRegex&&) noexcept = default;
- CopyableRegex& operator=(CopyableRegex&&) noexcept = default;
- ~CopyableRegex() = default;
+ private:
+ using SlabType = Slab<ElementSize, ElementAlign, Blocks4KBPerSlab>;
+ using SlabList =
+ base::IntrusiveList<SlabType, typename SlabType::IntrusiveListTraits>;
- std::string GlobalReplace(std::string_view s,
- std::string_view replacement) const {
- return regex_.GlobalReplace(s, replacement);
+ void InsertHashMapEntries(SlabType& slab) {
+ for (auto p = reinterpret_cast<uintptr_t>(slab.GetBeginAddress());
+ p < reinterpret_cast<uintptr_t>(slab.GetEndAddress());
+ p += internal::k4KiloBytes) {
+ PERFETTO_DCHECK(p % internal::k4KiloBytes == 0);
+ block_4KB_aligned_to_slab_.Insert(p, &slab);
+ }
}
- bool FullMatch(std::string_view s) const { return regex_.FullMatch(s); }
- bool FullMatchWithGroups(std::string_view s,
- std::vector<std::string_view>& out) const {
- return regex_.FullMatchWithGroups(s, out);
+
+ void EraseHashMapEntries(const SlabType& slab) {
+ for (auto p = reinterpret_cast<uintptr_t>(slab.GetBeginAddress());
+ p < reinterpret_cast<uintptr_t>(slab.GetEndAddress());
+ p += internal::k4KiloBytes) {
+ PERFETTO_DCHECK(p % internal::k4KiloBytes == 0);
+ block_4KB_aligned_to_slab_.Erase(p);
+ }
}
- bool PartialMatch(std::string_view s) const { return regex_.PartialMatch(s); }
- bool PartialMatchWithGroups(std::string_view s,
- std::vector<std::string_view>& out) const {
- return regex_.PartialMatchWithGroups(s, out);
+
+ SlabType& FindSlabInHashMap(const void* ptr) {
+ auto ptr_4KB_aligned = reinterpret_cast<uintptr_t>(ptr) &
+ ~(static_cast<uintptr_t>(internal::k4KiloBytes) - 1);
+ SlabType** slab = block_4KB_aligned_to_slab_.Find(ptr_4KB_aligned);
+ PERFETTO_CHECK(slab);
+ PERFETTO_CHECK(*slab);
+ return **slab;
}
- Regex::PartialMatchIterator PartialMatchAll(std::string_view s) const {
- return regex_.PartialMatchAll(s);
+
+ void DeleteSlabs(SlabList& slabs) {
+ while (!slabs.empty()) {
+ auto& slab = slabs.front();
+ slabs.PopFront();
+ delete &slab;
+ }
}
- private:
- Regex regex_;
+ base::FlatHashMap<uintptr_t, SlabType*> block_4KB_aligned_to_slab_;
+ SlabList slabs_full_;
+ SlabList slabs_non_full_;
+ size_t slabs_non_full_size_{0};
};
-} // namespace base
+} // namespace protovm
} // namespace perfetto
-#endif // INCLUDE_PERFETTO_EXT_BASE_REGEX_H_
-// gen_amalgamated begin header: src/base/regex/regex_pcre2.h
+#endif // SRC_PROTOVM_SLAB_ALLOCATOR_H_
/*
- * Copyright (C) 2026 The Android Open Source Project
+ * Copyright (C) 2025 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.
@@ -51791,199 +57118,85 @@ class CopyableRegex {
* limitations under the License.
*/
-#ifndef SRC_BASE_REGEX_REGEX_PCRE2_H_
-#define SRC_BASE_REGEX_REGEX_PCRE2_H_
-
-// gen_amalgamated expanded: #include "perfetto/base/build_config.h"
-
-// See note in regex_re2.h. Also honor PERFETTO_REGEX_FORCE_STD: targets that
-// define it (e.g. libperfetto_client_experimental) opt out of the optional
-// backends and must not pull in <pcre2.h>, even when PERFETTO_PCRE2 is set.
-#if PERFETTO_BUILDFLAG(PERFETTO_PCRE2) && !defined(PERFETTO_REGEX_FORCE_STD)
+#ifndef SRC_PROTOVM_ALLOCATOR_H_
+#define SRC_PROTOVM_ALLOCATOR_H_
-#include <limits>
-#include <memory>
-#include <string>
-#include <string_view>
-#include <vector>
+#include <algorithm>
+#include <cstdlib>
-// gen_amalgamated expanded: #include "perfetto/ext/base/status_or.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/field.h"
-#define PCRE2_CODE_UNIT_WIDTH 8
-#include <pcre2.h>
+// gen_amalgamated expanded: #include "src/protovm/error_handling.h"
+// gen_amalgamated expanded: #include "src/protovm/node.h"
+// gen_amalgamated expanded: #include "src/protovm/slab_allocator.h"
namespace perfetto {
-namespace base {
-
-struct Pcre2CodeDeleter {
- void operator()(pcre2_code* p) const { pcre2_code_free(p); }
-};
+namespace protovm {
-struct Pcre2MatchDataDeleter {
- void operator()(pcre2_match_data* p) const { pcre2_match_data_free(p); }
-};
+// A centralized allocator to manage all the memory requests from RwProto. It
+// enforces a strict memory usage limit, thus allowing fine-grained control of
+// the overall proto VM's memory footprint.
+class Allocator {
+ public:
+ static constexpr size_t kNodeSize = std::max(sizeof(Node), sizeof(MapNode));
+ static constexpr size_t kNodeAlign =
+ std::max(alignof(Node), alignof(MapNode));
-using ScopedPcre2Code = std::unique_ptr<pcre2_code, Pcre2CodeDeleter>;
-using ScopedPcre2MatchData =
- std::unique_ptr<pcre2_match_data, Pcre2MatchDataDeleter>;
+ explicit Allocator(size_t memory_limit_bytes);
-// PCRE2 backend for Regex. Used on Android when the use_pcre2 flag is enabled.
-// Header-only so the compiler can inline through unique_ptr<RegexImpl>.
-class RegexPcre2 {
- public:
- RegexPcre2(RegexPcre2&&) noexcept = default;
- RegexPcre2& operator=(RegexPcre2&&) noexcept = default;
- ~RegexPcre2() = default;
+ template <class T, class... Args>
+ StatusOr<OwnedPtr<Node>> CreateNode(Args&&... args) {
+ auto p = Allocate();
+ PROTOVM_RETURN_IF_NOT_OK(p);
- RegexPcre2(const RegexPcre2&) = delete;
- RegexPcre2& operator=(const RegexPcre2&) = delete;
+ // 1. Construct node's inner value T passing args (struct aggregate
+ // initialization)
+ // 2. Construct node passing T (struct aggregate initialization)
+ new (*p) Node{T{std::forward<Args>(args)...}};
- static StatusOr<RegexPcre2> Create(std::string_view pattern,
- bool case_insensitive) {
- RegexPcre2 result;
- int error_code;
- size_t error_offset;
- uint32_t pcre2_flags = 0;
- if (case_insensitive) {
- pcre2_flags |= PCRE2_CASELESS;
- }
- result.code_.reset(pcre2_compile(
- reinterpret_cast<PCRE2_SPTR>(pattern.data()), pattern.size(),
- pcre2_flags, &error_code, &error_offset, nullptr));
- if (!result.code_) {
- PCRE2_UCHAR buffer[256];
- pcre2_get_error_message(error_code, buffer, sizeof(buffer));
- return ErrStatus("PCRE2 compile error at offset %zu: %s", error_offset,
- reinterpret_cast<char*>(buffer));
- }
- // JIT-compile for faster matching. Non-fatal if JIT is unavailable.
- pcre2_jit_compile(result.code_.get(), PCRE2_JIT_COMPLETE);
- result.match_data_.reset(
- pcre2_match_data_create_from_pattern(result.code_.get(), nullptr));
- return std::move(result);
+ return OwnedPtr<Node>(static_cast<Node*>(*p));
}
- std::string GlobalReplace(std::string_view s,
- std::string_view replacement) const {
- std::string out;
- size_t out_len = s.size() + replacement.size() * 2 + 64;
- auto do_substitute = [&](size_t* len) {
- out.resize(*len);
- return pcre2_substitute(
- code_.get(), reinterpret_cast<PCRE2_SPTR>(s.data()), s.size(),
- /*startoffset=*/0,
- PCRE2_SUBSTITUTE_GLOBAL | PCRE2_SUBSTITUTE_OVERFLOW_LENGTH,
- /*match_data=*/nullptr, /*mcontext=*/nullptr,
- reinterpret_cast<PCRE2_SPTR>(replacement.data()), replacement.size(),
- reinterpret_cast<PCRE2_UCHAR*>(out.data()), len);
- };
- int rc = do_substitute(&out_len);
- if (rc == PCRE2_ERROR_NOMEMORY) {
- // PCRE2_SUBSTITUTE_OVERFLOW_LENGTH sets out_len to the required size.
- rc = do_substitute(&out_len);
- }
- if (rc >= 0) {
- out.resize(out_len);
- return out;
- }
- return std::string(s);
- }
+ StatusOr<OwnedPtr<MapNode>> CreateMapNode(uint64_t key, OwnedPtr<Node> value);
- bool FullMatch(std::string_view s) const {
- int rc = pcre2_match(code_.get(), reinterpret_cast<PCRE2_SPTR>(s.data()),
- s.size(),
- /*startoffset=*/0, PCRE2_ANCHORED | PCRE2_ENDANCHORED,
- match_data_.get(), /*mcontext=*/nullptr);
- return rc >= 0;
- }
+ StatusOr<Node::Bytes> AllocateAndCopyBytes(protozero::ConstBytes data);
- bool FullMatchWithGroups(std::string_view s,
- std::vector<std::string_view>& out) const {
- out.clear();
- int rc = pcre2_match(code_.get(), reinterpret_cast<PCRE2_SPTR>(s.data()),
- s.size(),
- /*startoffset=*/0, PCRE2_ANCHORED | PCRE2_ENDANCHORED,
- match_data_.get(), /*mcontext=*/nullptr);
- if (rc <= 0)
- return false;
- FillGroups(s, out);
- return true;
- }
+ // Deeply delete a node and all the referenced data. E.g. if the node holds a
+ // Node::Message, recursively delete the message fields and finally delete the
+ // node.
+ void Delete(Node* node);
+ void Delete(MapNode* node);
- bool PartialMatch(std::string_view s) const {
- int rc = pcre2_match(code_.get(), reinterpret_cast<PCRE2_SPTR>(s.data()),
- s.size(),
- /*startoffset=*/0, /*options=*/0, match_data_.get(),
- /*mcontext=*/nullptr);
- return rc >= 0;
- }
+ // Deeply delete a node's referenced data, but do not delete the node itself.
+ // E.g. if the node holds a Node::Message, recursively delete the message
+ // fields.
+ void DeleteReferencedData(Node* node);
- bool PartialMatchWithGroups(std::string_view s,
- std::vector<std::string_view>& out) const {
- out.clear();
- int rc = pcre2_match(code_.get(), reinterpret_cast<PCRE2_SPTR>(s.data()),
- s.size(),
- /*startoffset=*/0, /*options=*/0, match_data_.get(),
- /*mcontext=*/nullptr);
- if (rc <= 0)
- return false;
- FillGroups(s, out);
- return true;
- }
+ // Recursively delete a message's fields, but do not delete the message
+ // itself.
+ void DeleteReferencedData(Node::Message* message);
- bool SearchWithOffset(std::string_view s,
- size_t start_offset,
- std::vector<std::string_view>& out) const {
- out.clear();
- if (start_offset > s.size())
- return false;
- int rc =
- pcre2_match(code_.get(), reinterpret_cast<PCRE2_SPTR>(s.data()),
- s.size(), start_offset, /*options=*/0, match_data_.get(),
- /*mcontext=*/nullptr);
- if (rc <= 0)
- return false;
- FillGroups(s, out);
- return true;
- }
+ // Delete the blob referenced by the Bytes struct, but do not delete the Bytes
+ // struct itself.
+ void DeleteReferencedData(Node::Bytes* bytes);
- private:
- RegexPcre2() = default;
+ size_t GetMemoryUsageBytes() const { return used_memory_bytes_; }
- void FillGroups(std::string_view s,
- std::vector<std::string_view>& out) const {
- uint32_t count = pcre2_get_ovector_count(match_data_.get());
- size_t* ovector = pcre2_get_ovector_pointer(match_data_.get());
- for (uint32_t i = 0; i < count; ++i) {
- if (ovector[2 * i] == std::numeric_limits<PCRE2_SIZE>::max()) {
- out.emplace_back();
- } else {
- out.emplace_back(s.data() + ovector[2 * i],
- ovector[2 * i + 1] - ovector[2 * i]);
- }
- }
- }
+ private:
+ void DeallocateBytes(OwnedPtr<void> p, size_t size);
+ StatusOr<void*> Allocate();
- ScopedPcre2Code code_;
- // pcre2_match() requires a non-null match_data even when capture groups
- // aren't needed (FullMatch, PartialMatch). A separate minimal match_data
- // with ovecsize=1 could be used for those cases, but the savings are
- // negligible: PCRE2's internal backtracking frame size depends on the
- // pattern's capture groups regardless of ovector size. We reuse a single
- // cached match_data created from the pattern to avoid per-call allocation.
- mutable ScopedPcre2MatchData match_data_;
+ size_t memory_limit_bytes_{0};
+ size_t used_memory_bytes_{0};
+ SlabAllocator<kNodeSize, kNodeAlign> slab_allocator_;
};
-} // namespace base
+} // namespace protovm
} // namespace perfetto
-#endif // PERFETTO_BUILDFLAG(PERFETTO_PCRE2) &&
- // !defined(PERFETTO_REGEX_FORCE_STD)
-
-#endif // SRC_BASE_REGEX_REGEX_PCRE2_H_
-// gen_amalgamated begin header: src/base/regex/regex_re2.h
+#endif // SRC_PROTOVM_ALLOCATOR_H_
/*
- * Copyright (C) 2026 The Android Open Source Project
+ * Copyright (C) 2025 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.
@@ -51998,125 +57211,121 @@ class RegexPcre2 {
* limitations under the License.
*/
-#ifndef SRC_BASE_REGEX_REGEX_RE2_H_
-#define SRC_BASE_REGEX_REGEX_RE2_H_
-
-// gen_amalgamated expanded: #include "perfetto/base/build_config.h"
-
-// Guarded because gen_amalgamated inlines the body even when the include
-// site in regex.cc is preprocessed out. Also honor PERFETTO_REGEX_FORCE_STD:
-// targets that define it opt out of the optional backends and must not pull in
-// <re2/re2.h>, even when PERFETTO_RE2 is set.
-#if PERFETTO_BUILDFLAG(PERFETTO_RE2) && !defined(PERFETTO_REGEX_FORCE_STD)
-
-#include <memory>
-#include <string>
-#include <string_view>
-#include <vector>
-
-// gen_amalgamated expanded: #include "perfetto/ext/base/status_or.h"
-
-// Using quotes instead of angle brackets because Bazel passes external repo
-// paths via -iquote (not -isystem), which only covers quoted includes.
-// See google/re2 commit baeed1c and bazelbuild/bazel#18974.
-#include "re2/re2.h" // gen_amalgamated:keep
+// gen_amalgamated expanded: #include "src/protovm/allocator.h"
namespace perfetto {
-namespace base {
-
-// RE2 backend for Regex. Used on non-Android builds (standalone, Chromium).
-// Header-only so the compiler can inline through unique_ptr<RegexImpl>.
-class RegexRe2 {
- public:
- RegexRe2(RegexRe2&&) noexcept = default;
- RegexRe2& operator=(RegexRe2&&) noexcept = default;
- ~RegexRe2() = default;
+namespace protovm {
- RegexRe2(const RegexRe2&) = delete;
- RegexRe2& operator=(const RegexRe2&) = delete;
+Allocator::Allocator(size_t memory_limit_bytes)
+ : memory_limit_bytes_{memory_limit_bytes}, used_memory_bytes_{0} {}
- static StatusOr<RegexRe2> Create(std::string_view pattern,
- bool case_insensitive) {
- RegexRe2 result;
- re2::RE2::Options options;
- options.set_log_errors(false);
- options.set_case_sensitive(!case_insensitive);
- result.re_ = std::make_unique<re2::RE2>(std::string(pattern), options);
- if (!result.re_->ok()) {
- return ErrStatus("RE2 compile error: %s", result.re_->error().c_str());
- }
- result.groups_.resize(
- static_cast<size_t>(result.re_->NumberOfCapturingGroups() + 1));
- return std::move(result);
+StatusOr<OwnedPtr<MapNode>> Allocator::CreateMapNode(uint64_t key,
+ OwnedPtr<Node> value) {
+ PERFETTO_DCHECK(value);
+ auto p = Allocate();
+ if (!p.IsOk()) {
+ Delete(value.release());
+ PROTOVM_RETURN(p);
}
+ new (*p) MapNode{key, std::move(value)};
+ return OwnedPtr<MapNode>(static_cast<MapNode*>(*p));
+}
- std::string GlobalReplace(std::string_view s,
- std::string_view replacement) const {
- std::string out(s);
- re2::RE2::GlobalReplace(&out, *re_, replacement);
- return out;
+StatusOr<Node::Bytes> Allocator::AllocateAndCopyBytes(
+ protozero::ConstBytes data) {
+ if (used_memory_bytes_ + data.size > memory_limit_bytes_) {
+ PROTOVM_ABORT(
+ "Failed to allocate %zu bytes. Memory limit: %zu bytes. Used: %zu "
+ "bytes.)",
+ data.size, memory_limit_bytes_, used_memory_bytes_);
}
- bool FullMatch(std::string_view s) const {
- return re2::RE2::FullMatch(s, *re_);
+ if (data.size == 0) {
+ return Node::Bytes{nullptr, 0};
}
- bool FullMatchWithGroups(std::string_view s,
- std::vector<std::string_view>& out) const {
- out.clear();
- int n = static_cast<int>(groups_.size());
- if (!re_->Match(s, 0, s.size(), re2::RE2::ANCHOR_BOTH, groups_.data(), n))
- return false;
- out.assign(groups_.begin(), groups_.begin() + n);
- return true;
+ auto copy = OwnedPtr<void>{malloc(data.size)};
+ if (!copy) {
+ PROTOVM_ABORT("Failed to malloc %zu bytes", data.size);
}
+ used_memory_bytes_ += data.size;
+ memcpy(copy.get(), data.data, data.size);
- bool PartialMatch(std::string_view s) const {
- return re2::RE2::PartialMatch(s, *re_);
- }
+ return Node::Bytes{std::move(copy), data.size};
+}
- bool PartialMatchWithGroups(std::string_view s,
- std::vector<std::string_view>& out) const {
- out.clear();
- int n = static_cast<int>(groups_.size());
- if (!re_->Match(s, 0, s.size(), re2::RE2::UNANCHORED, groups_.data(), n))
- return false;
- out.assign(groups_.begin(), groups_.begin() + n);
- return true;
+void Allocator::Delete(Node* node) {
+ DeleteReferencedData(node);
+ node->~Node();
+ slab_allocator_.Free(node);
+ used_memory_bytes_ -= kNodeSize;
+}
+
+void Allocator::Delete(MapNode* node) {
+ Delete(node->value.release());
+ node->~MapNode();
+ slab_allocator_.Free(node);
+ used_memory_bytes_ -= kNodeSize;
+}
+
+void Allocator::DeleteReferencedData(Node* node) {
+ if (auto* message = node->GetIf<Node::Message>()) {
+ DeleteReferencedData(message);
+ } else if (auto* indexed_fields = node->GetIf<Node::IndexedRepeatedField>()) {
+ for (auto it = indexed_fields->index_to_node.begin(); it;) {
+ auto& map_node = *it;
+ it = indexed_fields->index_to_node.Remove(it);
+ Delete(&map_node);
+ }
+ } else if (auto* mapped_fields = node->GetIf<Node::MappedRepeatedField>()) {
+ for (auto it = mapped_fields->key_to_node.begin(); it;) {
+ auto& map_node = *it;
+ it = mapped_fields->key_to_node.Remove(it);
+ Delete(&map_node);
+ }
+ } else if (auto* bytes = node->GetIf<Node::Bytes>()) {
+ DeleteReferencedData(bytes);
}
+}
- bool SearchWithOffset(std::string_view s,
- size_t start_offset,
- std::vector<std::string_view>& out) const {
- out.clear();
- if (start_offset > s.size())
- return false;
- int n = static_cast<int>(groups_.size());
- if (!re_->Match(s, start_offset, s.size(), re2::RE2::UNANCHORED,
- groups_.data(), n))
- return false;
- out.assign(groups_.begin(), groups_.begin() + n);
- return true;
+void Allocator::DeleteReferencedData(Node::Message* message) {
+ for (auto it = message->field_id_to_node.begin(); it;) {
+ auto& map_node = *it;
+ it = message->field_id_to_node.Remove(it);
+ Delete(&map_node);
}
+}
- private:
- RegexRe2() = default;
- std::unique_ptr<re2::RE2> re_;
- // Must be absl::string_view, not std::string_view, to match RE2::Match()
- // signature. These can be distinct types in different builds.
- mutable std::vector<absl::string_view> groups_;
-};
+void Allocator::DeleteReferencedData(Node::Bytes* bytes) {
+ DeallocateBytes(std::move(bytes->data), bytes->size);
+}
-} // namespace base
-} // namespace perfetto
+void Allocator::DeallocateBytes(OwnedPtr<void> p, size_t size) {
+ free(p.release());
+ used_memory_bytes_ -= size;
+}
-#endif // PERFETTO_BUILDFLAG(PERFETTO_RE2) &&
- // !defined(PERFETTO_REGEX_FORCE_STD)
+StatusOr<void*> Allocator::Allocate() {
+ if (used_memory_bytes_ + kNodeSize > memory_limit_bytes_) {
+ PROTOVM_ABORT(
+ "Failed to allocate element (%zu bytes). Memory limit: %zu [bytes]. "
+ "Used: %zu "
+ "[bytes].)",
+ kNodeSize, memory_limit_bytes_, used_memory_bytes_);
+ }
+ auto* p = slab_allocator_.Allocate();
+ if (!p) {
+ PROTOVM_ABORT("Failed to allocate node");
+ }
+ used_memory_bytes_ += kNodeSize;
+ return p;
+}
-#endif // SRC_BASE_REGEX_REGEX_RE2_H_
-// gen_amalgamated begin header: src/base/regex/regex_std.h
+} // namespace protovm
+} // namespace perfetto
+// gen_amalgamated begin source: src/protovm/error_handling.cc
/*
- * Copyright (C) 2026 The Android Open Source Project
+ * Copyright (C) 2025 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.
@@ -52131,110 +57340,62 @@ class RegexRe2 {
* limitations under the License.
*/
-#ifndef SRC_BASE_REGEX_REGEX_STD_H_
-#define SRC_BASE_REGEX_REGEX_STD_H_
-
-#include <regex>
-#include <string>
-#include <string_view>
-#include <vector>
-
-// gen_amalgamated expanded: #include "perfetto/ext/base/status_or.h"
+// gen_amalgamated expanded: #include "src/protovm/error_handling.h"
namespace perfetto {
-namespace base {
-
-// std::regex backend for Regex. Uses ECMAScript syntax for Perl-style
-// shorthands (\d, \w, \s).
-class RegexStd {
- public:
- RegexStd(RegexStd&&) noexcept = default;
- RegexStd& operator=(RegexStd&&) noexcept = default;
- ~RegexStd() = default;
-
- RegexStd(const RegexStd&) = delete;
- RegexStd& operator=(const RegexStd&) = delete;
+namespace protovm {
- static StatusOr<RegexStd> Create(std::string_view pattern,
- bool case_insensitive) {
- RegexStd result;
- auto flags = std::regex::ECMAScript;
- if (case_insensitive) {
- flags |= std::regex::icase;
- }
- result.re_ = std::regex(std::string(pattern), flags);
- return std::move(result);
- }
+void LogStacktraceMessage(Stacktrace& stacktrace,
+ const char* file_name,
+ int file_line,
+ const char* fmt,
+ ...) {
+ const char* const fmt_file_info = "%s:%d ";
+ auto size_file_info =
+ std::snprintf(nullptr, 0, fmt_file_info, file_name, file_line);
- std::string GlobalReplace(std::string_view s,
- std::string_view replacement) const {
- return std::regex_replace(std::string(s), re_, std::string(replacement));
- }
+ va_list args;
+ va_start(args, fmt);
+ auto size_message = std::vsnprintf(nullptr, 0, fmt, args);
+ va_end(args);
- bool FullMatch(std::string_view s) const {
- return std::regex_match(s.data(), s.data() + s.size(), re_);
- }
+ auto s = std::string(
+ static_cast<std::size_t>(size_file_info + size_message + 1), '.');
- bool FullMatchWithGroups(std::string_view s,
- std::vector<std::string_view>& out) const {
- out.clear();
- if (!std::regex_match(s.data(), s.data() + s.size(), match_data_, re_))
- return false;
- FillGroups(s.data(), out);
- return true;
- }
+ std::snprintf(s.data(), static_cast<size_t>(size_file_info) + 1,
+ fmt_file_info, file_name, file_line);
- bool PartialMatch(std::string_view s) const {
- return std::regex_search(s.data(), s.data() + s.size(), re_);
- }
+ va_start(args, fmt);
+ std::vsnprintf(s.data() + size_file_info,
+ static_cast<size_t>(size_message) + 1, fmt, args);
+ va_end(args);
- bool PartialMatchWithGroups(std::string_view s,
- std::vector<std::string_view>& out) const {
- out.clear();
- if (!std::regex_search(s.data(), s.data() + s.size(), match_data_, re_))
- return false;
- FillGroups(s.data(), out);
- return true;
- }
+ s.pop_back(); // null-terminating char
- bool SearchWithOffset(std::string_view s,
- size_t start_offset,
- std::vector<std::string_view>& out) const {
- out.clear();
- const char* begin = s.data() + start_offset;
- const char* end = s.data() + s.size();
- if (begin > end)
- return false;
- if (!std::regex_search(begin, end, match_data_, re_))
- return false;
- FillGroups(begin, out);
- return true;
- }
+ stacktrace.push_back(std::move(s));
+}
- private:
- RegexStd() = default;
+void LogStacktraceMessage(Stacktrace& stacktrace,
+ const char* file_name,
+ int file_line) {
+ const char* const fmt = "%s:%d <no message>";
+ auto size_message = std::snprintf(nullptr, 0, fmt, file_name, file_line);
+ auto s = std::string(static_cast<size_t>(size_message) + 1, '.');
+ std::snprintf(s.data(), static_cast<size_t>(size_message) + 1, fmt, file_name,
+ file_line);
- void FillGroups(const char* base, std::vector<std::string_view>& out) const {
- for (size_t i = 0; i < match_data_.size(); ++i) {
- if (match_data_[i].matched) {
- out.emplace_back(base + match_data_.position(i),
- static_cast<size_t>(match_data_.length(i)));
- } else {
- out.emplace_back();
- }
- }
- }
+ s.pop_back(); // null-terminating char
- std::regex re_;
- mutable std::cmatch match_data_;
-};
+ stacktrace.push_back(std::move(s));
+}
-} // namespace base
+} // namespace protovm
} // namespace perfetto
-
-#endif // SRC_BASE_REGEX_REGEX_STD_H_
+// gen_amalgamated begin source: src/protovm/executor.cc
+// gen_amalgamated begin header: src/protovm/executor.h
+// gen_amalgamated begin header: src/protovm/ro_cursor.h
/*
- * Copyright (C) 2026 The Android Open Source Project
+ * Copyright (C) 2025 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.
@@ -52249,159 +57410,65 @@ class RegexStd {
* limitations under the License.
*/
-// gen_amalgamated expanded: #include "perfetto/ext/base/regex.h"
-
-#include <optional>
-#include <string>
-#include <string_view>
-#include <vector>
+#ifndef SRC_PROTOVM_RO_CURSOR_H_
+#define SRC_PROTOVM_RO_CURSOR_H_
-// gen_amalgamated expanded: #include "perfetto/base/build_config.h"
-// gen_amalgamated expanded: #include "perfetto/base/logging.h"
-// gen_amalgamated expanded: #include "perfetto/ext/base/flags.h"
-// gen_amalgamated expanded: #include "perfetto/ext/base/status_macros.h"
+#include <cstdint>
+#include <variant>
-// Unconditional: each header self-guards, so the amalgamator can see through.
-// gen_amalgamated expanded: #include "src/base/regex/regex_pcre2.h"
-// gen_amalgamated expanded: #include "src/base/regex/regex_re2.h"
-// gen_amalgamated expanded: #include "src/base/regex/regex_std.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/field.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/proto_decoder.h"
-// Picks the regex backend and exposes it as PERFETTO_REGEX_BACKEND.
-// Preference order:
-// 1. PERFETTO_REGEX_FORCE_STD -> std::regex
-// 2. PCRE2 (when enabled and the runtime flag is on)
-// 3. RE2 (when enabled)
-// 4. std::regex (fallback)
-#if defined(PERFETTO_REGEX_FORCE_STD)
-#define PERFETTO_REGEX_BACKEND ::perfetto::base::RegexStd
-#elif PERFETTO_BUILDFLAG(PERFETTO_PCRE2) && PERFETTO_FLAGS_USE_PCRE2
-#define PERFETTO_REGEX_BACKEND ::perfetto::base::RegexPcre2
-#elif PERFETTO_BUILDFLAG(PERFETTO_RE2)
-#define PERFETTO_REGEX_BACKEND ::perfetto::base::RegexRe2
-#else
-#define PERFETTO_REGEX_BACKEND ::perfetto::base::RegexStd
-#endif
+// gen_amalgamated expanded: #include "src/protovm/error_handling.h"
+// gen_amalgamated expanded: #include "src/protovm/scalar.h"
namespace perfetto {
-namespace base {
+namespace protovm {
-// Pimpl for Regex. Holds the selected backend; Regex reaches into `backend`
-// directly (Regex is a friend below).
-class RegexImpl {
+class RoCursor {
public:
- using Backend = PERFETTO_REGEX_BACKEND;
- explicit RegexImpl(Backend b) : backend(std::move(b)) {}
-
- private:
- friend class Regex;
- Backend backend;
-};
-#undef PERFETTO_REGEX_BACKEND
-
-Regex::Regex(Regex&&) noexcept = default;
-Regex& Regex::operator=(Regex&&) noexcept = default;
-Regex::~Regex() = default;
-
-StatusOr<Regex> Regex::Create(std::string_view pattern,
- Regex::CaseSensitivity cs) {
- bool insensitive = (cs == CaseSensitivity::kInsensitive);
- ASSIGN_OR_RETURN(auto backend,
- RegexImpl::Backend::Create(pattern, insensitive));
- Regex regex;
- regex.pattern_ = std::string(pattern);
- regex.cs_ = cs;
- regex.impl_ = std::make_unique<RegexImpl>(std::move(backend));
- return std::move(regex);
-}
-
-Regex Regex::CreateOrCheck(std::string_view pattern,
- Regex::CaseSensitivity cs) {
- auto re_or = Create(pattern, cs);
- PERFETTO_CHECK(re_or.ok());
- return std::move(*re_or);
-}
-
-std::string Regex::GlobalReplace(std::string_view s,
- std::string_view replacement) const {
- PERFETTO_DCHECK(impl_);
- return impl_->backend.GlobalReplace(s, replacement);
-}
-
-bool Regex::FullMatch(std::string_view s) const {
- PERFETTO_DCHECK(impl_);
- return impl_->backend.FullMatch(s);
-}
-
-bool Regex::FullMatchWithGroups(std::string_view s,
- std::vector<std::string_view>& out) const {
- PERFETTO_DCHECK(impl_);
- return impl_->backend.FullMatchWithGroups(s, out);
-}
-
-bool Regex::PartialMatch(std::string_view s) const {
- PERFETTO_DCHECK(impl_);
- return impl_->backend.PartialMatch(s);
-}
-
-bool Regex::PartialMatchWithGroups(std::string_view s,
- std::vector<std::string_view>& out) const {
- PERFETTO_DCHECK(impl_);
- return impl_->backend.PartialMatchWithGroups(s, out);
-}
-
-// --- PartialMatchIterator ---
-
-Regex::PartialMatchIterator::PartialMatchIterator(const Regex* re,
- std::string_view input)
- : re_(re), input_(input) {}
-
-std::optional<std::string_view> Regex::PartialMatchIterator::Next() {
- return NextWithGroups(groups_);
-}
-
-std::optional<std::string_view> Regex::PartialMatchIterator::NextWithGroups(
- std::vector<std::string_view>& groups) {
- if (offset_ > input_.size())
- return std::nullopt;
- PERFETTO_DCHECK(re_->impl_);
- if (!re_->impl_->backend.SearchWithOffset(input_, offset_, groups))
- return std::nullopt;
- if (groups.empty())
- return std::nullopt;
- std::string_view match = groups[0];
- size_t match_end =
- static_cast<size_t>(match.data() - input_.data()) + match.size();
- // Advance past the match. If match is empty, advance by one to avoid
- // infinite loops.
- offset_ = match.size() == 0 ? match_end + 1 : match_end;
- return match;
-}
+ class RepeatedFieldIterator {
+ public:
+ RepeatedFieldIterator();
+ explicit RepeatedFieldIterator(protozero::ProtoDecoder decoder,
+ uint32_t field_id);
+ RepeatedFieldIterator& operator++();
+ RoCursor operator*();
+ explicit operator bool() const;
-Regex::PartialMatchIterator Regex::PartialMatchAll(std::string_view s) const {
- return PartialMatchIterator(this, s);
-}
+ private:
+ protozero::Field Advance();
-// --- CopyableRegex ---
+ protozero::ProtoDecoder decoder_;
+ uint32_t field_id_;
+ protozero::Field field_;
+ };
-CopyableRegex::CopyableRegex(Regex regex) : regex_(std::move(regex)) {}
+ RoCursor();
+ explicit RoCursor(protozero::ConstBytes data);
+ explicit RoCursor(protozero::Field data);
+ StatusOr<void> EnterField(uint32_t field_id);
+ StatusOr<void> EnterRepeatedFieldAt(uint32_t field_id, uint32_t index);
+ StatusOr<RepeatedFieldIterator> IterateRepeatedField(uint32_t field_id) const;
+ bool IsScalar() const;
+ bool IsBytes() const;
+ StatusOr<Scalar> GetScalar() const;
+ StatusOr<protozero::ConstBytes> GetBytes() const;
-CopyableRegex::CopyableRegex(const CopyableRegex& other)
- : regex_(Regex::CreateOrCheck(other.regex_.pattern(),
- other.regex_.case_sensitivity())) {}
+ private:
+ StatusOr<protozero::ConstBytes> GetLengthDelimitedData() const;
-CopyableRegex& CopyableRegex::operator=(const CopyableRegex& other) {
- if (this != &other) {
- this->~CopyableRegex();
- new (this) CopyableRegex(other);
- }
- return *this;
-}
+ std::variant<protozero::ConstBytes, protozero::Field> data_;
+};
-} // namespace base
+} // namespace protovm
} // namespace perfetto
-// gen_amalgamated begin source: src/base/clock_snapshots.cc
+
+#endif // SRC_PROTOVM_RO_CURSOR_H_
+// gen_amalgamated begin header: src/protovm/rw_proto.h
+// gen_amalgamated begin header: src/protovm/rw_proto_cursor.h
/*
- * Copyright (C) 2024 The Android Open Source Project
+ * Copyright (C) 2025 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.
@@ -52416,74 +57483,137 @@ CopyableRegex& CopyableRegex::operator=(const CopyableRegex& other) {
* limitations under the License.
*/
-// gen_amalgamated expanded: #include "perfetto/ext/base/clock_snapshots.h"
+#ifndef SRC_PROTOVM_RW_PROTO_CURSOR_H_
+#define SRC_PROTOVM_RW_PROTO_CURSOR_H_
-// gen_amalgamated expanded: #include "perfetto/base/build_config.h"
-// gen_amalgamated expanded: #include "perfetto/base/time.h"
-// gen_amalgamated expanded: #include "protos/perfetto/common/builtin_clock.pbzero.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/field.h"
-namespace perfetto::base {
+// gen_amalgamated expanded: #include "src/protovm/allocator.h"
+// gen_amalgamated expanded: #include "src/protovm/error_handling.h"
+// gen_amalgamated expanded: #include "src/protovm/node.h"
-ClockSnapshotVector CaptureClockSnapshots() {
- ClockSnapshotVector snapshot_data;
-#if !PERFETTO_BUILDFLAG(PERFETTO_OS_APPLE) && \
- !PERFETTO_BUILDFLAG(PERFETTO_OS_WIN) && \
- !PERFETTO_BUILDFLAG(PERFETTO_OS_FREEBSD) && \
- !PERFETTO_BUILDFLAG(PERFETTO_OS_NACL) && \
- !PERFETTO_BUILDFLAG(PERFETTO_OS_QNX)
- struct {
- clockid_t id;
- protos::pbzero::BuiltinClock type;
- struct timespec ts;
- } clocks[] = {
- {CLOCK_BOOTTIME, protos::pbzero::BUILTIN_CLOCK_BOOTTIME, {0, 0}},
- {CLOCK_REALTIME_COARSE,
- protos::pbzero::BUILTIN_CLOCK_REALTIME_COARSE,
- {0, 0}},
- {CLOCK_MONOTONIC_COARSE,
- protos::pbzero::BUILTIN_CLOCK_MONOTONIC_COARSE,
- {0, 0}},
- {CLOCK_REALTIME, protos::pbzero::BUILTIN_CLOCK_REALTIME, {0, 0}},
- {CLOCK_MONOTONIC, protos::pbzero::BUILTIN_CLOCK_MONOTONIC, {0, 0}},
- {CLOCK_MONOTONIC_RAW,
- protos::pbzero::BUILTIN_CLOCK_MONOTONIC_RAW,
- {0, 0}},
+namespace perfetto {
+namespace protovm {
+
+class RwProtoCursor {
+ public:
+ enum MergeFlags : uint32_t {
+ kNone = 0,
+ kSkipSubmessages = 1 << 0,
+ kDelIfSrcEmpty = 1 << 1,
+ };
+
+ class RepeatedFieldIterator {
+ public:
+ RepeatedFieldIterator();
+ RepeatedFieldIterator(Allocator* allocator, IntrusiveMap::Iterator it);
+ RepeatedFieldIterator& operator++();
+ RwProtoCursor GetCursor();
+ explicit operator bool() const;
+
+ private:
+ Allocator* allocator_{nullptr};
+ IntrusiveMap::Iterator it_;
+ };
+
+ RwProtoCursor();
+ explicit RwProtoCursor(Node* node, Allocator* allocator);
+
+ bool operator==(const RwProtoCursor& other) const;
+ bool operator!=(const RwProtoCursor& other) const;
+
+ StatusOr<bool> IsRoot() const;
+ StatusOr<bool> HasField(uint32_t field_id);
+ StatusOr<void> EnterField(uint32_t field_id);
+ StatusOr<void> EnterRepeatedFieldAt(uint32_t field_id, uint32_t index);
+ StatusOr<RepeatedFieldIterator> IterateRepeatedField(uint32_t field_id);
+
+ // Enters a specific repeated field, treating it as a map of key-value pairs.
+ //
+ // The function operates on the principle that the repeated field (identified
+ // by <field_id>) can be viewed as a collection of key-value pairs, where:
+ // - Each message element within the repetition is a "value".
+ // - A specific subfield within each message element (identified by
+ // <map_key_field_id>) serves as the unique key for that element.
+ //
+ // The function performs a lookup using the provided <key> and, if a match
+ // is found, moves the cursor into the corresponding repeated field.
+ //
+ // Example:
+ //
+ // // Message currently pointer by the cursor
+ // message CurrentMessage {
+ // repeated KeyValuePair entries = <field_id>;
+ // }
+ //
+ // message KeyValuePair {
+ // uint32 key = <map_key_field_id>;
+ // string value_x = ...;
+ // string value_y = ...;
+ // }
+ //
+ // In this example <field_id> points to CurrentMessage.entries,
+ // <map_key_field_id> points to KeyValuePair.key, and <key> = 10. So the
+ // function attempts to find and enter the KeyValuePair message where
+ // key == 10.
+ StatusOr<void> EnterRepeatedFieldByKey(uint32_t field_id,
+ uint32_t map_key_field_id,
+ uint64_t key);
+
+ StatusOr<Scalar> GetScalar() const;
+ StatusOr<void> SetBytes(protozero::ConstBytes data);
+ StatusOr<void> SetScalar(Scalar scalar);
+
+ // Perform a shallow (one level) merge of two messages.
+ // The cursor must currently point to a message and 'data' must contain a
+ // message. Merge fields from the 'data' message into the message pointed by
+ // cursor. Existing fields in the cursor's message are overwritten by fields
+ // from 'data'. Fields present in 'data' but not in the cursor's message are
+ // added/created. If skip_submessages is set to true, any message node already
+ // resolved in the dst are skipped, thus not overwritten by the parent merge.
+ StatusOr<void> Merge(protozero::ConstBytes data, uint32_t flags);
+
+ StatusOr<void> Delete();
+
+ private:
+ struct ParentLink {
+ Node* node;
+ IntrusiveMap* map;
+ MapNode* map_node;
};
- // First snapshot all the clocks as atomically as we can.
- for (auto& clock : clocks) {
- if (clock_gettime(clock.id, &clock.ts) == -1)
- PERFETTO_DLOG("clock_gettime failed for clock %d", clock.id);
- }
- for (auto& clock : clocks) {
- snapshot_data.push_back(ClockReading(
- static_cast<uint32_t>(clock.type),
- static_cast<uint64_t>(base::FromPosixTimespec(clock.ts).count())));
- }
-#else // OS_APPLE || OS_WIN && OS_NACL
- auto wall_time_ns = static_cast<uint64_t>(base::GetWallTimeNs().count());
- // The default trace clock is boot time, so we always need to emit a path to
- // it. However since we don't actually have a boot time source on these
- // platforms, pretend that wall time equals boot time.
- snapshot_data.push_back(
- ClockReading(protos::pbzero::BUILTIN_CLOCK_BOOTTIME, wall_time_ns));
- snapshot_data.push_back(
- ClockReading(protos::pbzero::BUILTIN_CLOCK_MONOTONIC, wall_time_ns));
-#endif
-#if PERFETTO_BUILDFLAG(PERFETTO_ARCH_CPU_X86_64)
- // X86-specific but OS-independent TSC clocksource
- snapshot_data.push_back(
- ClockReading(protos::pbzero::BUILTIN_CLOCK_TSC, base::Rdtsc()));
-#endif // PERFETTO_BUILDFLAG(PERFETTO_ARCH_CPU_X86_64)
+ StatusOr<void> ConvertToMessageIfNeeded(Node* node);
+ StatusOr<OwnedPtr<Node>> CreateNodeFromField(protozero::Field field);
+ StatusOr<void> ConvertToMappedRepeatedFieldIfNeeded(
+ Node* node,
+ uint32_t map_key_field_id);
+ StatusOr<void> ConvertToIndexedRepeatedFieldIfNeeded(Node* node);
+ StatusOr<IntrusiveMap::Iterator> FindOrCreateMessageField(Node* node,
+ uint32_t field_id);
+ StatusOr<IntrusiveMap::Iterator> FindOrCreateIndexedRepeatedField(
+ Node* node,
+ uint32_t index);
+ StatusOr<IntrusiveMap::Iterator> FindOrCreateMappedRepeatedField(
+ Node* node,
+ uint64_t key);
+ StatusOr<IntrusiveMap::Iterator> MapInsert(IntrusiveMap* map,
+ uint64_t key,
+ OwnedPtr<Node> map_value);
+ StatusOr<uint64_t> ReadScalarField(const Node& node, uint32_t field_id);
- return snapshot_data;
-}
+ StatusOr<void> CheckIsValid() const;
-} // namespace perfetto::base
-// gen_amalgamated begin source: src/base/version.cc
-// gen_amalgamated begin header: include/perfetto/ext/base/version.h
+ Node* node_ = nullptr;
+ ParentLink parent_link_ = {};
+ Allocator* allocator_ = nullptr;
+};
+
+} // namespace protovm
+} // namespace perfetto
+
+#endif // SRC_PROTOVM_RW_PROTO_CURSOR_H_
/*
- * Copyright (C) 2020 The Android Open Source Project
+ * Copyright (C) 2025 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.
@@ -52498,49 +57628,150 @@ ClockSnapshotVector CaptureClockSnapshots() {
* limitations under the License.
*/
-#ifndef INCLUDE_PERFETTO_EXT_BASE_VERSION_H_
-#define INCLUDE_PERFETTO_EXT_BASE_VERSION_H_
+#ifndef SRC_PROTOVM_RW_PROTO_H_
+#define SRC_PROTOVM_RW_PROTO_H_
-namespace perfetto {
-namespace base {
+// gen_amalgamated expanded: #include "perfetto/protozero/message.h"
-// The returned pointer is a static string and safe to pass around.
-// Returns a human readable string currently of the approximate form:
-// Perfetto v42.1-deadbeef0 (deadbeef03c641e4b4ea9cf38e9b5696670175a9)
-// However you should not depend on the format of this string.
-// It maybe not be possible to determine the version. In which case the
-// string will be of the approximate form:
-// Perfetto v0.0 (unknown)
-const char* GetVersionString();
+// gen_amalgamated expanded: #include "src/protovm/allocator.h"
+// gen_amalgamated expanded: #include "src/protovm/node.h"
+// gen_amalgamated expanded: #include "src/protovm/rw_proto_cursor.h"
-// The returned pointer is a static string and safe to pass around.
-// Returns the short code used to identity the version:
-// v42.1-deadbeef0
-// It maybe not be possible to determine the version. In which case
-// this returns nullptr.
-// This can be compared with equality to other
-// version codes to detect matched builds (for example to see if
-// trace_processor_shell and the UI were built at the same revision)
-// but you should not attempt to parse it as the format may change
-// without warning.
-const char* GetVersionCode();
+namespace perfetto {
+namespace protovm {
-} // namespace base
-} // namespace perfetto
+// RwProto provides an API to create and manipulate protobuf messages without
+// requiring prior knowledge of the schema. Meaning that protobuf messages can
+// be dynamically built on-the-fly, without pre-compiled .proto definitions.
+//
+// Key features:
+//
+// - Schema-agnostic: RwProto dynamically learns the schema as fields and
+// messages are added.
+//
+// - Tree-like representation: protobuf messages are represented internally as a
+// tree of nodes, mirroring the nested structure of protobufs. This tree can
+// be traversed and manipulated using a Cursor object.
+//
+// - Fine-grained Memory Management: a centralized allocator is used to manage
+// memory for nodes, ensuring good data locality and fine-grained control over
+// memory usage.
+//
+// Overview of RwProto's internal node structure:
+//
+// ┌─────────┐
+// │ │
+// │ Message │
+// │ │ Map<field_id, OwnedPtr<Node>>
+// └─┬┬┬┬┬┬──┘
+// │││││└────────────────────────────────┐
+// ││││└───────────────────────┐ │
+// ┌───────────────┘││└──────────────┐ │ │
+// │ ┌───┘└────┐ │ │ │
+// │ │ ┌────▼────┐ ┌───▼───┐ ┌───▼───┐ ┌───▼────┐
+// │ │ │ │ │ │ │ │ │ │
+// │ │ │ Message │ │ Empty │ │ Bytes │ │ Scalar │
+// │ │ │ │ │ │ │ │ │ │
+// │ │ └────┬────┘ └───────┘ └───────┘ └────────┘
+// │ │ ▼
+// │ │ ...
+// │ │
+// │ │
+// │ *********▼********
+// │ * *
+// │ * Mapped *
+// │ * RepeatedField *
+// │ * *
+// │ ****************** Map<key, OwnedPtr<Node>>
+// │ │ │
+// │ ┌───┘ └────┐
+// │ │ │
+// │ ┌────▼────┐ ┌───▼───┐
+// │ │ │ │ │
+// │ │ Message │ │ Bytes │
+// │ │ │ │ │
+// │ └────┬────┘ └───────┘
+// │ ▼
+// │ ...
+// │
+//
+// ********▼*********
+// * *
+// * Indexed *
+// * RepeatedField *
+// * *
+// ****************** Map<index, OwnedPtr<Node>>
+// ││││
+// ┌──────┘││└────────────────────┐
+// │ │└───────────┐ │
+// │ └──┐ │ │
+// │ │ │ │
+// ┌────▼────┐ ┌───▼───┐ ┌───▼───┐ ┌───▼────┐
+// │ │ │ │ │ │ │ │
+// │ Message │ │ Empty │ │ Bytes │ │ Scalar │
+// │ │ │ │ │ │ │ │
+// └────┬────┘ └───────┘ └───────┘ └────────┘
+// ▼
+// ...
+//
+//
+// ┌─┐
+// │ │ Data node: corresponds to an actual field/message in the proto schema
+// └─┘ and eventually becomes part of the final serialized proto.
+//
+// ***
+// * * Structural node: used to organize and provide access to message fields.
+// *** It is an internal helper and doesn't appear in the
+// final serialized proto.
+//
+//
+// Message: Represents a protobuf message. It maps field_id to corresponding
+// node/value. It allows accessing fields as well as adding and
+// removing them.
+//
+//
+// Empty: Represents an empty or uninitialized node. It is used as a
+// placeholder before a node's type is determined. E.g. between an
+// "enter field" and a "set field value" operation.
+//
+//
+// Bytes: Stores a sequence of bytes, typically representing a length-delimited
+// protobuf field.
+//
+//
+// Scalar: Stores a scalar value.
+//
+//
+// IndexedRepeatedField: Represents a protobuf repeated field where elements
+// are accessed by index.
+//
+//
+// MappedRepeatedField: Represents a protobuf repeated field where elements
+// are accessed by key.
+class RwProto {
+ public:
+ using Cursor = RwProtoCursor;
-#endif // INCLUDE_PERFETTO_EXT_BASE_VERSION_H_
-// gen_amalgamated begin header: gen/perfetto_version.gen.h
-// Generated by write_version_header.py
+ explicit RwProto(Allocator* allocator);
+ ~RwProto();
+ Cursor GetRoot();
+ void Serialize(protozero::Message*) const;
-#ifndef GEN_PERFETTO_VERSION_GEN_H_
-#define GEN_PERFETTO_VERSION_GEN_H_
+ private:
+ void SerializeField(uint32_t field_id,
+ const Node& node,
+ protozero::Message* proto) const;
+
+ Allocator* allocator_{nullptr};
+ Node root_;
+};
-#define PERFETTO_VERSION_STRING() "v58.2-add693d8b"
-#define PERFETTO_VERSION_SCM_REVISION() "add693d8b338ba9599dbcbc3e300b1ab8c000897"
+} // namespace protovm
+} // namespace perfetto
-#endif // GEN_PERFETTO_VERSION_GEN_H_
+#endif // SRC_PROTOVM_RW_PROTO_H_
/*
- * Copyright (C) 2020 The Android Open Source Project
+ * Copyright (C) 2025 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.
@@ -52555,46 +57786,68 @@ const char* GetVersionCode();
* limitations under the License.
*/
-// gen_amalgamated expanded: #include "perfetto/ext/base/version.h"
+#ifndef SRC_PROTOVM_EXECUTOR_H_
+#define SRC_PROTOVM_EXECUTOR_H_
-// gen_amalgamated expanded: #include "perfetto/base/build_config.h"
+#include <cstdint>
+#include <optional>
-#include <stdio.h>
+// gen_amalgamated expanded: #include "protos/perfetto/protovm/vm_program.pbzero.h"
-#if PERFETTO_BUILDFLAG(PERFETTO_VERSION_GEN)
-// gen_amalgamated expanded: #include "perfetto_version.gen.h"
-#else
-#define PERFETTO_VERSION_STRING() nullptr
-#define PERFETTO_VERSION_SCM_REVISION() "unknown"
-#endif
+// gen_amalgamated expanded: #include "src/protovm/error_handling.h"
+// gen_amalgamated expanded: #include "src/protovm/ro_cursor.h"
+// gen_amalgamated expanded: #include "src/protovm/rw_proto.h"
namespace perfetto {
-namespace base {
+namespace protovm {
-const char* GetVersionCode() {
- return PERFETTO_VERSION_STRING();
-}
+using CursorEnum = perfetto::protos::pbzero::VmCursorEnum;
-const char* GetVersionString() {
- static const char* version_str = [] {
- static constexpr size_t kMaxLen = 256;
- const char* version_code = PERFETTO_VERSION_STRING();
- if (version_code == nullptr) {
- version_code = "v0.0";
- }
- char* version = new char[kMaxLen + 1];
- snprintf(version, kMaxLen, "Perfetto %s (%s)", version_code,
- PERFETTO_VERSION_SCM_REVISION());
- return version;
- }();
- return version_str;
-}
+struct Cursors {
+ RoCursor src;
+ RwProto::Cursor dst;
+ CursorEnum selected{CursorEnum::VM_CURSOR_UNSPECIFIED};
+ bool create_if_not_exist{false};
-} // namespace base
+ // Used internally by Parser to detect illegal "del" operations.
+ // See detailed explanation in the Parser implementation.
+ const RwProto::Cursor* innermost_saved_dst{nullptr};
+};
+
+// Executor's methods are virtual to be overridden in tests
+class Executor {
+ public:
+ using MergeFlags = RwProto::Cursor::MergeFlags;
+
+ virtual ~Executor();
+ virtual StatusOr<void> EnterField(Cursors* cursors, uint32_t field_id) const;
+ virtual StatusOr<void> EnterRepeatedFieldAt(Cursors* cursors,
+ uint32_t field_id,
+ uint32_t index) const;
+ virtual StatusOr<void> EnterRepeatedFieldByKey(Cursors* cursors,
+ uint32_t field_id,
+ uint32_t map_key_field_id,
+ uint64_t key) const;
+ virtual StatusOr<RoCursor::RepeatedFieldIterator> IterateRepeatedField(
+ RoCursor* src,
+ uint32_t field_id) const;
+ virtual StatusOr<RwProto::Cursor::RepeatedFieldIterator> IterateRepeatedField(
+ RwProto::Cursor* dst,
+ uint32_t field_id) const;
+ virtual StatusOr<uint64_t> ReadRegister(uint8_t reg_id) const;
+ virtual StatusOr<void> WriteRegister(const Cursors& cursors, uint8_t reg_id);
+ virtual StatusOr<void> Delete(RwProto::Cursor* dst) const;
+ virtual StatusOr<void> Merge(Cursors* cursors, uint32_t flags) const;
+ virtual StatusOr<void> Set(Cursors* cursors) const;
+
+ private:
+ std::array<std::optional<uint64_t>, 32> registers_;
+};
+
+} // namespace protovm
} // namespace perfetto
-// gen_amalgamated begin source: src/protovm/allocator.cc
-// gen_amalgamated begin header: src/protovm/allocator.h
-// gen_amalgamated begin header: src/protovm/error_handling.h
+
+#endif // SRC_PROTOVM_EXECUTOR_H_
/*
* Copyright (C) 2025 The Android Open Source Project
*
@@ -52611,261 +57864,126 @@ const char* GetVersionString() {
* limitations under the License.
*/
-#ifndef SRC_PROTOVM_ERROR_HANDLING_H_
-#define SRC_PROTOVM_ERROR_HANDLING_H_
-
-#include <cstdarg>
-#include <cstdint>
-#include <memory>
-#include <new>
-#include <string>
-#include <type_traits>
-#include <vector>
-
-// gen_amalgamated expanded: #include "perfetto/base/compiler.h"
-// gen_amalgamated expanded: #include "perfetto/base/logging.h"
-
-#if defined(__GNUC__) || defined(__clang__)
-#if defined(__clang__)
-#pragma clang diagnostic push
-// Fix 'error: #pragma system_header ignored in main file' for amalgamated
-// build.
-#pragma clang diagnostic ignored "-Wpragma-system-header-outside-header"
-#endif
-
-// Ignore GCC warning about a missing argument for a variadic macro parameter.
-#pragma GCC system_header
-
-#if defined(__clang__)
-#pragma clang diagnostic pop
-#endif
-#endif
+// gen_amalgamated expanded: #include "src/protovm/executor.h"
namespace perfetto {
namespace protovm {
-using Stacktrace = std::vector<std::string>;
-
-void LogStacktraceMessage(Stacktrace& stacktrace,
- const char* file_name,
- int file_line,
- const char* fmt,
- ...) PERFETTO_PRINTF_FORMAT(4, 5);
-
-// overload for calls without message args
-void LogStacktraceMessage(Stacktrace& stacktrace,
- const char* file_name,
- int file_line);
-
-#define PROTOVM_ABORT(fmt, ...) \
- do { \
- auto status_abort = StatusOr<void>::Abort(); \
- LogStacktraceMessage(status_abort.stacktrace(), \
- ::perfetto::base::LoggingBasename(__FILE__), \
- __LINE__, fmt, ##__VA_ARGS__); \
- return status_abort; \
- } while (0)
-
-#define PROTOVM_RETURN(s, ...) \
- do { \
- if (s.IsAbort()) { \
- LogStacktraceMessage(s.stacktrace(), \
- ::perfetto::base::LoggingBasename(__FILE__), \
- __LINE__, ##__VA_ARGS__); \
- } \
- return s; \
- } while (0)
-
-#define PROTOVM_RETURN_IF_NOT_OK(s, ...) \
- do { \
- if (s.IsAbort()) { \
- LogStacktraceMessage(s.stacktrace(), \
- ::perfetto::base::LoggingBasename(__FILE__), \
- __LINE__, ##__VA_ARGS__); \
- return s; \
- } \
- if (!s.IsOk()) { \
- return s; \
- } \
- } while (0)
-
-#define PROTOVM_INTERNAL_CONCAT_IMPL(x, y) x##y
-#define PROTOVM_INTERNAL_MACRO_CONCAT(x, y) PROTOVM_INTERNAL_CONCAT_IMPL(x, y)
-
-// Evaluates |rhs| which should return a StatusOr<T> and assigns this
-// to |lhs|. If the status is an error status, returns the status from the
-// current function.
-#define PROTOVM_ASSIGN_OR_RETURN(lhs, rhs) \
- PROTOVM_INTERNAL_MACRO_CONCAT(auto status_or, __LINE__) = rhs; \
- PROTOVM_RETURN_IF_NOT_OK( \
- PROTOVM_INTERNAL_MACRO_CONCAT(status_or, __LINE__)); \
- lhs = std::move(PROTOVM_INTERNAL_MACRO_CONCAT(status_or, __LINE__).value())
-
-enum class Status : uint8_t {
- kOk,
- kError,
-
- // It causes an abort of the whole VM's program. Typically indicates a
- // fundamental issue with the program and requires developer's intervention.
- kAbort,
-};
-
-namespace internal {
-
-template <class T, class Arg, class... Args>
-static constexpr bool is_copy_or_move_ctor_arg_v =
- sizeof...(Args) == 0 && std::is_same_v<T, std::decay_t<Arg>>;
-
-template <class T>
-inline constexpr std::size_t sizeof_v = sizeof(T);
+Executor::~Executor() = default;
-template <>
-inline constexpr std::size_t sizeof_v<void> = 0;
+StatusOr<void> Executor::EnterField(Cursors* cursors, uint32_t field_id) const {
+ if (cursors->selected == CursorEnum::VM_CURSOR_SRC) {
+ return cursors->src.EnterField(field_id);
+ }
-template <class T>
-inline constexpr std::size_t alignof_v = alignof(T);
+ auto has_field = cursors->dst.HasField(field_id);
+ PROTOVM_RETURN_IF_NOT_OK(has_field);
-template <>
-inline constexpr std::size_t alignof_v<void> = 0;
+ if (!has_field.value() && !cursors->create_if_not_exist) {
+ return StatusOr<void>::Error();
+ }
-} // namespace internal
+ return cursors->dst.EnterField(field_id);
+}
-template <class T>
-class StatusOr {
- public:
- // Factory methods to create empty instances (without value)
- static StatusOr Ok() { return StatusOr{Status::kOk}; }
- static StatusOr Error() { return StatusOr{Status::kError}; }
- static StatusOr Abort() { return StatusOr{Status::kAbort}; }
+StatusOr<void> Executor::EnterRepeatedFieldAt(Cursors* cursors,
+ uint32_t field_id,
+ uint32_t index) const {
+ if (cursors->selected == CursorEnum::VM_CURSOR_SRC) {
+ return cursors->src.EnterRepeatedFieldAt(field_id, index);
+ }
- StatusOr(const StatusOr&) = delete;
+ return cursors->dst.EnterRepeatedFieldAt(field_id, index);
+}
- StatusOr(StatusOr&& other) : status_{other.status_} {
- if (IsOk()) {
- if constexpr (!std::is_same_v<T, void>) {
- new (storage_) T(std::move(other.value()));
- }
- } else if (IsAbort()) {
- new (storage_) std::unique_ptr<Stacktrace>(
- std::move(other.GetStacktraceUniquePtr()));
- }
+StatusOr<void> Executor::EnterRepeatedFieldByKey(Cursors* cursors,
+ uint32_t field_id,
+ uint32_t map_key_field_id,
+ uint64_t key) const {
+ if (cursors->selected == CursorEnum::VM_CURSOR_SRC) {
+ PROTOVM_ABORT(
+ "Mapped repeated fields are currently supported only in RwProto");
}
- // Intentionally implicit to allow idiomatic usage (return plain value to be
- // implicitly converted to StatusOr)
- template <
- class... Args,
- // sfinae to avoid clashing with copy/move constructors
- std::enable_if_t<!internal::is_copy_or_move_ctor_arg_v<StatusOr, Args...>,
- int> = 0>
- StatusOr(Args&&... args) : status_{Status::kOk} {
- if constexpr (!std::is_same_v<T, void>) {
- new (storage_) T(std::forward<Args>(args)...);
- }
- }
+ auto has_field = cursors->dst.HasField(field_id);
+ PROTOVM_RETURN_IF_NOT_OK(has_field);
- // Intentionally implicit to allow idiomatic usage (e.g. return StatusOr<A> to
- // be implicitely converted to StatusOr<B>).
- // When status is ok, the conversion is only allowed if B = void, otherwise it
- // would require a conversion from A to non-void B.
- template <class U, std::enable_if_t<!std::is_same_v<U, T>, int> = 0>
- StatusOr(StatusOr<U>&& other) : status_{other.status_} {
- if (IsOk()) {
- PERFETTO_DCHECK((std::is_same_v<T, void>));
- } else if (IsAbort()) {
- new (storage_) std::unique_ptr<Stacktrace>(
- std::move(other.GetStacktraceUniquePtr()));
- }
+ if (!has_field.value() && !cursors->create_if_not_exist) {
+ return StatusOr<void>::Error();
}
- ~StatusOr() {
- if (IsOk()) {
- if constexpr (!std::is_same_v<T, void>) {
- value().~T();
- }
- }
- if (IsAbort()) {
- GetStacktraceUniquePtr().~unique_ptr();
- }
- }
+ return cursors->dst.EnterRepeatedFieldByKey(field_id, map_key_field_id, key);
+}
- bool IsOk() const { return status_ == Status::kOk; }
- bool IsError() const { return status_ == Status::kError; }
- bool IsAbort() const { return status_ == Status::kAbort; }
+StatusOr<RoCursor::RepeatedFieldIterator> Executor::IterateRepeatedField(
+ RoCursor* src,
+ uint32_t field_id) const {
+ return src->IterateRepeatedField(field_id);
+}
- template <class U = T>
- std::enable_if_t<!std::is_same_v<U, void>, U&> value() {
- PERFETTO_DCHECK(IsOk());
- return *std::launder(reinterpret_cast<T*>(storage_));
- }
+StatusOr<RwProto::Cursor::RepeatedFieldIterator> Executor::IterateRepeatedField(
+ RwProto::Cursor* dst,
+ uint32_t field_id) const {
+ return dst->IterateRepeatedField(field_id);
+}
- template <class U = T>
- std::enable_if_t<!std::is_same_v<U, void>, const U&> value() const {
- return const_cast<StatusOr*>(this)->value();
+StatusOr<uint64_t> Executor::ReadRegister(uint8_t reg_id) const {
+ if (reg_id >= registers_.size()) {
+ PROTOVM_ABORT("Register (id = %d) is out of bounds", reg_id);
+ }
+ if (!registers_[reg_id]) {
+ PROTOVM_ABORT("Register (id = %d) is not initialized)", reg_id);
}
+ return StatusOr<uint64_t>{*registers_[reg_id]};
+}
- template <class U = T>
- std::enable_if_t<!std::is_same_v<U, void>, U&> operator*() {
- return value();
+StatusOr<void> Executor::WriteRegister(const Cursors& cursors, uint8_t reg_id) {
+ if (reg_id >= registers_.size()) {
+ PROTOVM_ABORT("Register (id = %d) is out of bounds", reg_id);
}
- template <class U = T>
- std::enable_if_t<!std::is_same_v<U, void>, const U&> operator*() const {
- return value();
- }
+ auto status_or_scalar = cursors.selected == CursorEnum::VM_CURSOR_SRC
+ ? cursors.src.GetScalar()
+ : cursors.dst.GetScalar();
+ PROTOVM_RETURN_IF_NOT_OK(status_or_scalar);
- template <class U = T>
- std::enable_if_t<!std::is_same_v<U, void>, U*> operator->() {
- return &value();
- }
+ registers_[reg_id] = status_or_scalar->value;
+ return StatusOr<void>::Ok();
+}
- template <class U = T>
- std::enable_if_t<!std::is_same_v<U, void>, const U*> operator->() const {
- return &value();
- }
+StatusOr<void> Executor::Delete(RwProto::Cursor* dst) const {
+ return dst->Delete();
+}
- Stacktrace& stacktrace() {
- PERFETTO_DCHECK(IsAbort());
- return **std::launder(
- reinterpret_cast<std::unique_ptr<Stacktrace>*>(storage_));
+StatusOr<void> Executor::Merge(Cursors* cursors, uint32_t flags) const {
+ if (!cursors->src.IsBytes()) {
+ PROTOVM_ABORT(
+ "Attempted MERGE operation but src cursor has incompatible data "
+ "type");
}
- private:
- template <class U>
- friend class StatusOr;
+ return cursors->dst.Merge(*cursors->src.GetBytes(), flags);
+}
- // Intentionally private to encourage the use of factory methods, instead of
- // plain status values. E.g. StatusOr::Abort() instead of Status::kAbort.
- // Plain status value don't include stacktrace information in case of an
- // abort.
- explicit StatusOr(Status status) : status_{status} {
- PERFETTO_DCHECK((std::is_same_v<T, void>) || !IsOk());
- if (IsAbort()) {
- new (storage_) std::unique_ptr<Stacktrace>{new Stacktrace{}};
- }
+StatusOr<void> Executor::Set(Cursors* cursors) const {
+ if (cursors->src.IsScalar()) {
+ auto status_or_scalar = cursors->src.GetScalar();
+ PROTOVM_RETURN_IF_NOT_OK(status_or_scalar);
+ return cursors->dst.SetScalar(*status_or_scalar);
}
- std::unique_ptr<Stacktrace>& GetStacktraceUniquePtr() {
- PERFETTO_DCHECK(IsAbort());
- return *std::launder(
- reinterpret_cast<std::unique_ptr<Stacktrace>*>(storage_));
+ if (cursors->src.IsBytes()) {
+ auto status_or_bytes = cursors->src.GetBytes();
+ PROTOVM_RETURN_IF_NOT_OK(status_or_bytes);
+ return cursors->dst.SetBytes(*status_or_bytes);
}
- Status status_;
-
- static constexpr size_t kStorageAlign =
- std::max(internal::alignof_v<T>, alignof(std::unique_ptr<Stacktrace>));
- static constexpr size_t kStorageSize =
- std::max(internal::sizeof_v<T>, sizeof(std::unique_ptr<Stacktrace>));
- alignas(kStorageAlign) unsigned char storage_[kStorageSize];
-};
+ PROTOVM_ABORT("Attempted SET operation but src cursor has no valid data");
+}
} // namespace protovm
} // namespace perfetto
-
-#endif // SRC_PROTOVM_ERROR_HANDLING_H_
-// gen_amalgamated begin header: src/protovm/node.h
-// gen_amalgamated begin header: src/protovm/owned_ptr.h
+// gen_amalgamated begin source: src/protovm/node.cc
/*
* Copyright (C) 2025 The Android Open Source Project
*
@@ -52882,68 +58000,38 @@ class StatusOr {
* limitations under the License.
*/
-#ifndef SRC_PROTOVM_OWNED_PTR_H_
-#define SRC_PROTOVM_OWNED_PTR_H_
-
-// gen_amalgamated expanded: #include "perfetto/base/logging.h"
+// gen_amalgamated expanded: #include "src/protovm/node.h"
namespace perfetto {
namespace protovm {
-// OwnedPtr is essentially a std::unique_ptr that doesn't perform any deletion
-// itself. Its purpose is to clearly express ownership semantics for objects
-// that are managed with a custom allocators.
-//
-// It is not a unique_ptr, because that's not guaranteed to be standard layout
-//
-// OwnedPtr is extensively used within RwProto to manage the lifecycle and
-// clarify ownership of the internal, manually-allocated nodes.
-template <class T>
-class OwnedPtr {
- public:
- using pointer = T*;
- OwnedPtr(const OwnedPtr&) = delete;
- OwnedPtr(OwnedPtr&& other) {
- p_ = other.p_;
- other.p_ = nullptr;
- }
- OwnedPtr(T* p) noexcept : p_(p) {} // NOLINT: explicit
- ~OwnedPtr() noexcept { reset(); }
- OwnedPtr& operator=(const OwnedPtr&) = delete;
- OwnedPtr& operator=(OwnedPtr&& other) noexcept {
- if (this == &other) {
- return *this;
- }
- reset();
- p_ = other.p_;
- other.p_ = nullptr;
- return *this;
- }
- T* get() const noexcept { return p_; }
- T* release() noexcept {
- T* p = p_;
- p_ = nullptr;
- return p;
- }
- typename std::add_lvalue_reference<T>::type operator*() const noexcept {
- return *p_;
- }
- explicit operator bool() const noexcept { return get() != nullptr; }
- T* operator->() const noexcept { return p_; }
- void reset(T* p = pointer()) noexcept {
- PERFETTO_DCHECK(p_ == nullptr);
- p_ = p;
- }
-
- private:
- T* p_ = nullptr;
-};
+const char* Node::GetTypeName() const {
+ return std::visit(
+ [](auto&& value) {
+ using T = std::decay_t<decltype(value)>;
+ if constexpr (std::is_same_v<T, Node::Bytes>) {
+ return "Bytes";
+ } else if constexpr (std::is_same_v<T, Node::Empty>) {
+ return "Empty";
+ } else if constexpr (std::is_same_v<T, Node::IndexedRepeatedField>) {
+ return "IndexedRepeatedField";
+ } else if constexpr (std::is_same_v<T, Node::MappedRepeatedField>) {
+ return "MappedRepeatedField";
+ } else if constexpr (std::is_same_v<T, Node::Message>) {
+ return "Message";
+ } else if constexpr (std::is_same_v<T, Scalar>) {
+ return "Scalar";
+ } else {
+ return "<unknown>";
+ }
+ },
+ value);
+}
} // namespace protovm
} // namespace perfetto
-
-#endif // SRC_PROTOVM_OWNED_PTR_H_
-// gen_amalgamated begin header: src/protovm/scalar.h
+// gen_amalgamated begin source: src/protovm/parser.cc
+// gen_amalgamated begin header: src/protovm/parser.h
/*
* Copyright (C) 2025 The Android Open Source Project
*
@@ -52960,41 +58048,50 @@ class OwnedPtr {
* limitations under the License.
*/
-#ifndef SRC_PROTOVM_SCALAR_H_
-#define SRC_PROTOVM_SCALAR_H_
+#ifndef SRC_PROTOVM_PARSER_H_
+#define SRC_PROTOVM_PARSER_H_
-// gen_amalgamated expanded: #include "perfetto/protozero/proto_utils.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/field.h"
+// gen_amalgamated expanded: #include "protos/perfetto/protovm/vm_program.pbzero.h"
+
+// gen_amalgamated expanded: #include "src/protovm/error_handling.h"
+// gen_amalgamated expanded: #include "src/protovm/executor.h"
+// gen_amalgamated expanded: #include "src/protovm/ro_cursor.h"
+// gen_amalgamated expanded: #include "src/protovm/rw_proto.h"
namespace perfetto {
namespace protovm {
-struct Scalar {
- static Scalar Fixed32(uint32_t value) {
- return Scalar{protozero::proto_utils::ProtoWireType::kFixed32, value};
- }
-
- static Scalar Fixed64(uint64_t value) {
- return Scalar{protozero::proto_utils::ProtoWireType::kFixed64, value};
- }
-
- static Scalar VarInt(uint64_t value) {
- return Scalar{protozero::proto_utils::ProtoWireType::kVarInt, value};
- }
-
- bool operator==(const Scalar& other) const {
- return wire_type == other.wire_type && value == other.value;
- }
+class Parser {
+ public:
+ Parser(protozero::ConstBytes program, Executor* executor);
+ StatusOr<void> Run(RoCursor src, RwProto::Cursor dst);
- bool operator!=(const Scalar& other) const { return !(*this == other); }
+ private:
+ StatusOr<void> ParseInstructions(
+ protozero::RepeatedFieldIterator<protozero::ConstBytes> it_instruction);
+ StatusOr<void> ParseInstruction(
+ const protos::pbzero::VmInstruction::Decoder& instruction);
+ StatusOr<void> ParseMerge(
+ const protos::pbzero::VmInstruction::Decoder& instruction);
+ StatusOr<void> ParseRegLoad(
+ const protos::pbzero::VmInstruction::Decoder& instruction);
+ StatusOr<void> ParseSelect(
+ const protos::pbzero::VmInstruction::Decoder& instruction);
+ StatusOr<void> ParseSelectRec(
+ const protos::pbzero::VmInstruction::Decoder& instruction,
+ protozero::RepeatedFieldIterator<protozero::ConstBytes>
+ it_path_component);
- protozero::proto_utils::ProtoWireType wire_type;
- uint64_t value;
+ protos::pbzero::VmProgram::Decoder program_;
+ Cursors cursors_;
+ Executor* executor_;
};
} // namespace protovm
} // namespace perfetto
-#endif // SRC_PROTOVM_SCALAR_H_
+#endif // SRC_PROTOVM_PARSER_H_
/*
* Copyright (C) 2025 The Android Open Source Project
*
@@ -53011,96 +58108,260 @@ struct Scalar {
* limitations under the License.
*/
-#ifndef SRC_PROTOVM_NODE_H_
-#define SRC_PROTOVM_NODE_H_
-
-#include <type_traits>
-#include <variant>
-
-// gen_amalgamated expanded: #include "perfetto/ext/base/intrusive_tree.h"
-// gen_amalgamated expanded: #include "src/protovm/owned_ptr.h"
-// gen_amalgamated expanded: #include "src/protovm/scalar.h"
+// gen_amalgamated expanded: #include "src/protovm/parser.h"
+// gen_amalgamated expanded: #include "protos/perfetto/protovm/vm_program.pbzero.h"
+// gen_amalgamated expanded: #include "src/protovm/error_handling.h"
namespace perfetto {
namespace protovm {
-struct Node;
+Parser::Parser(protozero::ConstBytes program, Executor* executor)
+ : program_{program}, executor_(executor) {}
-struct MapNode {
- struct Traits {
- using KeyType = uint64_t;
- static constexpr size_t NodeOffset() {
- static_assert(std::is_standard_layout_v<MapNode>);
- return offsetof(MapNode, node);
+StatusOr<void> Parser::Run(RoCursor src, RwProto::Cursor dst) {
+ cursors_.src = src;
+ cursors_.dst = dst;
+ cursors_.innermost_saved_dst = nullptr;
+ return ParseInstructions(program_.instructions());
+}
+
+StatusOr<void> Parser::ParseInstructions(
+ protozero::RepeatedFieldIterator<protozero::ConstBytes> it_instruction) {
+ int instruction_index = 0;
+ for (; it_instruction; ++it_instruction) {
+ auto instruction = protos::pbzero::VmInstruction::Decoder(*it_instruction);
+ auto status = ParseInstruction(instruction);
+
+ if (status.IsAbort()) {
+ PROTOVM_RETURN(status, "instruction[%d]", instruction_index);
}
- static const KeyType& GetKey(const MapNode& n) { return n.key; }
- };
- MapNode(uint64_t k, OwnedPtr<Node> v) : key{k}, value{std::move(v)} {}
+ if (status.IsError()) {
+ using AbortLevel = perfetto::protos::pbzero::VmInstruction::AbortLevel;
+ auto abort_level =
+ instruction.has_abort_level()
+ ? static_cast<AbortLevel>(instruction.abort_level())
+ : AbortLevel::SKIP_CURRENT_INSTRUCTION_AND_BREAK_OUTER;
+ if (abort_level == AbortLevel::SKIP_CURRENT_INSTRUCTION_AND_BREAK_OUTER) {
+ return StatusOr<void>::Error();
+ }
+ if (abort_level == AbortLevel::ABORT) {
+ PROTOVM_ABORT(
+ "instruction[%d]: returned status = error and instruction's "
+ "abort level = 'abort'",
+ instruction_index);
+ }
+ }
- base::IntrusiveTreeNode node{};
- uint64_t key;
- OwnedPtr<Node> value;
-};
+ ++instruction_index;
+ }
-using IntrusiveMap = base::IntrusiveTree<MapNode, MapNode::Traits>;
+ return StatusOr<void>::Ok();
+}
-struct Node {
- struct Bytes {
- OwnedPtr<void> data;
- size_t size;
- };
+StatusOr<void> Parser::ParseInstruction(
+ const protos::pbzero::VmInstruction::Decoder& instruction) {
+ if (instruction.has_select()) {
+ auto status = ParseSelect(instruction);
+ PROTOVM_RETURN(status, "select");
+ }
- struct Empty {};
+ if (instruction.has_reg_load()) {
+ auto status = ParseRegLoad(instruction);
+ PROTOVM_RETURN_IF_NOT_OK(status, "reg_load");
+ } else if (instruction.has_del()) {
+ PROTOVM_ASSIGN_OR_RETURN(bool is_root, cursors_.dst.IsRoot());
+ if (cursors_.innermost_saved_dst != nullptr &&
+ cursors_.dst == *cursors_.innermost_saved_dst && !is_root) {
+ // Illegal operation
+ // For each "select" operation we effectively save a snapshot of the
+ // cursors on the stack, so that they can be restored when a frame is
+ // exited. This "del" operation is attempting to delete a "dst" cursor
+ // that is currently aliased in the parent stack frame. This would result
+ // in a dangling pointer when the current frame is exited and the aliased
+ // "dst" is restored.
+ PROTOVM_ABORT(
+ "del would invalidate a cursor saved by an enclosing select");
+ }
+ auto status = executor_->Delete(&cursors_.dst);
+ PROTOVM_RETURN_IF_NOT_OK(status, "del");
+ } else if (instruction.has_merge()) {
+ auto status = ParseMerge(instruction);
+ PROTOVM_RETURN_IF_NOT_OK(status, "merge");
+ } else if (instruction.has_set()) {
+ auto status = executor_->Set(&cursors_);
+ PROTOVM_RETURN_IF_NOT_OK(status, "set");
+ } else {
+ PROTOVM_ABORT("Unsupported instruction");
+ }
- struct MappedRepeatedField {
- IntrusiveMap key_to_node;
- };
+ return ParseInstructions(instruction.nested_instructions());
+}
- struct IndexedRepeatedField {
- IntrusiveMap index_to_node;
- };
+StatusOr<void> Parser::ParseMerge(
+ const protos::pbzero::VmInstruction::Decoder& instruction) {
+ protos::pbzero::VmOpMerge::Decoder merge(instruction.merge());
+ uint32_t flags = Executor::MergeFlags::kNone;
+ if (merge.skip_submessages())
+ flags |= Executor::MergeFlags::kSkipSubmessages;
+ if (merge.del_if_src_empty())
+ flags |= Executor::MergeFlags::kDelIfSrcEmpty;
+ auto status = executor_->Merge(&cursors_, flags);
+ PROTOVM_RETURN_IF_NOT_OK(status);
+ return status;
+}
- struct Message {
- IntrusiveMap field_id_to_node;
- };
+StatusOr<void> Parser::ParseRegLoad(
+ const protos::pbzero::VmInstruction::Decoder& instruction) {
+ auto saved_selected = cursors_.selected;
- template <class T>
- T* GetIf() {
- return std::get_if<T>(&value);
+ protos::pbzero::VmOpRegLoad::Decoder reg_load(instruction.reg_load());
+ cursors_.selected = !reg_load.has_cursor()
+ ? CursorEnum::VM_CURSOR_SRC
+ : static_cast<CursorEnum>(reg_load.cursor());
+ auto status = executor_->WriteRegister(
+ cursors_, static_cast<uint8_t>(reg_load.dst_register()));
+
+ cursors_.selected = saved_selected;
+
+ PROTOVM_RETURN_IF_NOT_OK(status);
+
+ return status;
+}
+
+StatusOr<void> Parser::ParseSelect(
+ const protos::pbzero::VmInstruction::Decoder& instruction) {
+ auto saved_cursors = cursors_;
+ cursors_.innermost_saved_dst = &saved_cursors.dst;
+
+ protos::pbzero::VmOpSelect::Decoder select(instruction.select());
+ cursors_.selected = !select.has_cursor()
+ ? CursorEnum::VM_CURSOR_SRC
+ : static_cast<CursorEnum>(select.cursor());
+ cursors_.create_if_not_exist = select.create_if_not_exist();
+
+ if (cursors_.selected == CursorEnum::VM_CURSOR_SRC &&
+ cursors_.create_if_not_exist) {
+ PROTOVM_ABORT(
+ "incompatible params: src cursor (read only) + create_if_not_exist");
}
- template <class T>
- const T* GetIf() const {
- return std::get_if<T>(&value);
+ auto status = ParseSelectRec(instruction, select.relative_path());
+ cursors_ = saved_cursors;
+
+ return status;
+}
+
+StatusOr<void> Parser::ParseSelectRec(
+ const protos::pbzero::VmInstruction::Decoder& instruction,
+ protozero::RepeatedFieldIterator<protozero::ConstBytes> it_path_component) {
+ protos::pbzero::VmOpSelect::Decoder select(instruction.select());
+
+ bool has_entered_all_path_components = !it_path_component;
+ if (has_entered_all_path_components) {
+ return ParseInstructions(instruction.nested_instructions());
}
- const char* GetTypeName() const;
+ auto curr_component =
+ protos::pbzero::VmOpSelect::PathComponent::Decoder(*it_path_component);
+ ++it_path_component;
- std::variant<Bytes,
- Empty,
- IndexedRepeatedField,
- MappedRepeatedField,
- Message,
- Scalar>
- value;
+ std::optional<protos::pbzero::VmOpSelect::PathComponent::Decoder>
+ next_component =
+ it_path_component
+ ? std::make_optional(
+ protos::pbzero::VmOpSelect::PathComponent::Decoder(
+ *it_path_component))
+ : std::nullopt;
- // Flag needed to track the merge state of repeated fields
- // (see implementation of Merge operation in RW proto)
- bool has_been_merged = false;
-};
+ if (!curr_component.has_field_id()) {
+ PROTOVM_ABORT("Invalid path. Expected path component with field_id.");
+ }
+
+ // iterate repeated field
+ if (curr_component.is_repeated()) {
+ if (cursors_.selected == CursorEnum::VM_CURSOR_SRC) {
+ auto status_or_it = executor_->IterateRepeatedField(
+ &cursors_.src, curr_component.field_id());
+ PROTOVM_RETURN_IF_NOT_OK(status_or_it, "iterate repeated field (id = %d)",
+ static_cast<int>(curr_component.field_id()));
+ int index = 0;
+ for (auto it = *status_or_it; it; ++it) {
+ cursors_.src = *it;
+ auto status = ParseSelectRec(instruction, it_path_component);
+ PROTOVM_RETURN_IF_NOT_OK(status, "repeated field (id = %d, index = %d)",
+ static_cast<int>(curr_component.field_id()),
+ index);
+ ++index;
+ }
+ } else if (cursors_.selected == CursorEnum::VM_CURSOR_DST) {
+ auto status_or_it = executor_->IterateRepeatedField(
+ &cursors_.dst, curr_component.field_id());
+ PROTOVM_RETURN_IF_NOT_OK(status_or_it, "iterate repeated field (id = %d)",
+ static_cast<int>(curr_component.field_id()));
+ int index = 0;
+ for (auto it = *status_or_it; it; ++it) {
+ cursors_.dst = it.GetCursor();
+ auto status = ParseSelectRec(instruction, it_path_component);
+ PROTOVM_RETURN_IF_NOT_OK(status, "repeated field (id = %d, index = %d)",
+ static_cast<int>(curr_component.field_id()),
+ index);
+ ++index;
+ }
+ } else {
+ PROTOVM_ABORT(
+ "Iteration over selected cursor (%d) is not supported. Should be "
+ "either SRC or DST cursor.",
+ static_cast<int>(cursors_.selected));
+ }
+ return StatusOr<void>::Ok();
+ }
+
+ // enter indexed repeated field
+ if (next_component && next_component->has_array_index()) {
+ ++it_path_component;
+ auto status_enter = executor_->EnterRepeatedFieldAt(
+ &cursors_, curr_component.field_id(), next_component->array_index());
+ PROTOVM_RETURN_IF_NOT_OK(status_enter, "enter indexed repeated field");
+ auto status_select = ParseSelectRec(instruction, it_path_component);
+ PROTOVM_RETURN(status_select, "repeated field (id = %d, index = %d)",
+ static_cast<int>(curr_component.field_id()),
+ static_cast<int>(next_component->array_index()));
+ }
+
+ // enter mapped repeated field
+ if (next_component && next_component->has_map_key_field_id()) {
+ ++it_path_component;
+ if (!next_component->has_register_to_match()) {
+ PROTOVM_ABORT(
+ "enter mapped repeated field: expected field 'register_to_match'");
+ }
+ auto reg_id = static_cast<uint8_t>(next_component->register_to_match());
+ auto key = executor_->ReadRegister(reg_id);
+ PROTOVM_RETURN_IF_NOT_OK(key, "enter mapped repeated field");
+ auto status_enter = executor_->EnterRepeatedFieldByKey(
+ &cursors_, curr_component.field_id(),
+ next_component->map_key_field_id(), static_cast<uint32_t>(*key));
+ PROTOVM_RETURN_IF_NOT_OK(status_enter, "enter mapped repeated field");
+ auto status_select = ParseSelectRec(instruction, it_path_component);
+ PROTOVM_RETURN(status_select, "mapped repeated field (id = %d, key = %d)",
+ static_cast<int>(curr_component.field_id()),
+ static_cast<int>(*key));
+ }
+
+ // enter field
+ auto status = executor_->EnterField(&cursors_, curr_component.field_id());
+ PROTOVM_RETURN_IF_NOT_OK(status, "enter field (id = %d)",
+ static_cast<int>(curr_component.field_id()));
+
+ return ParseSelectRec(instruction, it_path_component);
+}
} // namespace protovm
} // namespace perfetto
-
-#endif // SRC_PROTOVM_NODE_H_
-// gen_amalgamated begin header: src/protovm/slab_allocator.h
-// gen_amalgamated begin header: include/perfetto/ext/base/flat_hash_map.h
-// gen_amalgamated begin header: include/perfetto/ext/base/flat_hash_map_v1.h
-// gen_amalgamated begin header: include/perfetto/ext/base/murmur_hash.h
-// gen_amalgamated begin header: include/perfetto/ext/base/hash.h
+// gen_amalgamated begin source: src/protovm/ro_cursor.cc
/*
- * Copyright (C) 2019 The Android Open Source Project
+ * Copyright (C) 2025 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.
@@ -53115,468 +58376,282 @@ struct Node {
* limitations under the License.
*/
-#ifndef INCLUDE_PERFETTO_EXT_BASE_HASH_H_
-#define INCLUDE_PERFETTO_EXT_BASE_HASH_H_
+// gen_amalgamated expanded: #include "src/protovm/ro_cursor.h"
-#include <cstddef>
-#include <cstdint>
-#include <memory>
-#include <optional>
-#include <tuple>
-#include <utility>
+// gen_amalgamated expanded: #include "perfetto/base/logging.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/proto_utils.h"
-namespace perfetto::base {
+namespace perfetto {
+namespace protovm {
-// ============================================================================
-// Absl-style hash customization point
-// ============================================================================
-//
-// To make a type hashable with Perfetto hash functions, define a friend
-// function template:
-//
-// template <typename H>
-// friend H PerfettoHashValue(H h, const MyType& value) {
-// return H::Combine(std::move(h), value.field1, value.field2);
-// }
-//
-// This function will be found via ADL (Argument Dependent Lookup) when hashing
-// your type. No forward declaration is needed - ADL finds it in your type's
-// namespace.
+RoCursor::RepeatedFieldIterator::RepeatedFieldIterator()
+ : decoder_{protozero::ConstBytes{}}, field_id_{0}, field_{Advance()} {
+ PERFETTO_DCHECK(!field_.valid());
+}
-// ============================================================================
-// Built-in PerfettoHashValue implementations for common standard library
-// types. These allow standard library types to work seamlessly with the
-// absl-style hash API without requiring users to define their own
-// implementations.
-// ============================================================================
+RoCursor::RepeatedFieldIterator::RepeatedFieldIterator(
+ protozero::ProtoDecoder decoder,
+ uint32_t field_id)
+ : decoder_(decoder), field_id_(field_id), field_{Advance()} {}
-// Hash function for std::optional - hashes the value if present, or a sentinel
-// if not.
-template <typename H, typename T>
-H PerfettoHashValue(H h, const std::optional<T>& value) {
- if (value.has_value()) {
- return H::Combine(H::Combine(std::move(h), true), *value);
- }
- return H::Combine(std::move(h), false, 0);
+RoCursor::RepeatedFieldIterator& RoCursor::RepeatedFieldIterator::operator++() {
+ field_ = Advance();
+ return *this;
}
-// Hash function for std::pair - combines hashes of both elements.
-template <typename H, typename T1, typename T2>
-H PerfettoHashValue(H h, const std::pair<T1, T2>& value) {
- return H::Combine(std::move(h), value.first, value.second);
+RoCursor RoCursor::RepeatedFieldIterator::operator*() {
+ return RoCursor(field_);
}
-// Hash function for std::tuple - combines hashes of all elements.
-template <typename H, typename... Ts>
-H PerfettoHashValue(H h, const std::tuple<Ts...>& value) {
- return std::apply(
- [&h](const auto&... elements) {
- return H::Combine(std::move(h), elements...);
- },
- value);
+RoCursor::RepeatedFieldIterator::operator bool() const {
+ return field_.valid();
}
-// Hash function for pointers - hashes the pointer value as an integer.
-template <typename H, typename T>
-H PerfettoHashValue(H h, const std::unique_ptr<T>& ptr) {
- return H::Combine(std::move(h), ptr.get());
-}
-template <typename H, typename T>
-H PerfettoHashValue(H h, const std::shared_ptr<T>& ptr) {
- return H::Combine(std::move(h), ptr.get());
+protozero::Field RoCursor::RepeatedFieldIterator::Advance() {
+ auto field = decoder_.ReadField();
+ while (field) {
+ if (field.id() == field_id_) {
+ break;
+ }
+ field = decoder_.ReadField();
+ }
+ return field;
}
-// This is for using already-hashed key into std::unordered_map and avoid the
-// cost of re-hashing. Example:
-// unordered_map<uint64_t, Value, AlreadyHashed> my_map.
-template <typename T>
-struct AlreadyHashed {
- size_t operator()(const T& x) const { return static_cast<size_t>(x); }
-};
+RoCursor::RoCursor() = default;
-} // namespace perfetto::base
+RoCursor::RoCursor(protozero::ConstBytes data) : data_{data} {}
-#endif // INCLUDE_PERFETTO_EXT_BASE_HASH_H_
-/*
- * 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.
- */
+RoCursor::RoCursor(protozero::Field data) : data_{data} {}
-#ifndef INCLUDE_PERFETTO_EXT_BASE_MURMUR_HASH_H_
-#define INCLUDE_PERFETTO_EXT_BASE_MURMUR_HASH_H_
+StatusOr<void> RoCursor::EnterField(uint32_t field_id) {
+ auto status_or_data = GetLengthDelimitedData();
+ PROTOVM_RETURN_IF_NOT_OK(status_or_data);
-#include <cstddef>
-#include <cstdint>
-#include <cstring>
-#include <limits>
-#include <string>
-#include <string_view>
-#include <type_traits>
-#include <utility>
+ protozero::ProtoDecoder decoder(*status_or_data);
-// gen_amalgamated expanded: #include "perfetto/ext/base/hash.h"
-// gen_amalgamated expanded: #include "perfetto/ext/base/string_view.h"
-// gen_amalgamated expanded: #include "perfetto/public/compiler.h"
+ for (auto field = decoder.ReadField(); field.valid();
+ field = decoder.ReadField()) {
+ if (field.id() == field_id) {
+ data_ = field;
+ return StatusOr<void>::Ok();
+ }
+ }
-// We need <cmath> only for std::isnan here. But cmath is a quite heavy
-// header AND is not frequently used, so its include cost is generally
-// NOT amortized. OTOH this header is very frequently used.
-// The code below avoids pulling cmath in many translation units, reducing
-// compilation time. Under the hoods std::isnan uses __builtin_isnan if
-// available.
-#if PERFETTO_HAS_BUILTIN(__builtin_isnan)
-#define PERFETTO_IS_NAN(x) __builtin_isnan(x)
-#else
-#include <cmath>
-#define PERFETTO_IS_NAN(x) std::isnan(x)
-#endif
+ return StatusOr<void>::Error();
+}
-// This file provides an implementation of the 64-bit MurmurHash2 algorithm,
-// also known as MurmurHash64A. This algorithm, created by Austin Appleby, is a
-// fast, non-cryptographic hash function with excellent distribution properties,
-// making it ideal for use in hash tables.
-//
-// The file also includes related hashing utilities:
-// - A standalone `fmix64` finalizer from MurmurHash3, used for hashing
-// individual numeric types.
-// - A hash combiner for creating a single hash from a sequence of values.
-//
-// NOTE: This implementation is NOT cryptographically secure. It must not be
-// used for security-sensitive applications like password storage or digital
-// signatures, as it is not designed to be resistant to malicious attacks.
+StatusOr<void> RoCursor::EnterRepeatedFieldAt(uint32_t field_id,
+ uint32_t index) {
+ auto status_or_data = GetLengthDelimitedData();
+ PROTOVM_RETURN_IF_NOT_OK(status_or_data);
-namespace perfetto::base {
+ protozero::ProtoDecoder decoder(*status_or_data);
-namespace murmur_internal {
+ uint32_t current_index = 0;
-// Finalizes an intermediate hash value using the `fmix64` routine from
-// MurmurHash3.
-//
-// This function's purpose is to thoroughly mix the bits of the hash state to
-// ensure the final result is well-distributed, which is critical for avoiding
-// collisions in hash tables.
-//
-// Args:
-// h: The intermediate hash value to be finalized.
-//
-// Returns:
-// The final, well-mixed 64-bit hash value.
-inline uint64_t MurmurHashMix(uint64_t h) {
- h ^= h >> 33;
- h *= 0xff51afd7ed558ccdULL;
- h ^= h >> 33;
- h *= 0xc4ceb9fe1a85ec53ULL;
- h ^= h >> 33;
- return h;
-}
+ for (auto field = decoder.ReadField(); field.valid();
+ field = decoder.ReadField()) {
+ if (field.id() != field_id) {
+ continue;
+ }
-// Computes a 64-bit hash for a block of memory using the MurmurHash64A
-// algorithm.
-//
-// The process involves four main steps:
-// 1. Initialization: The hash state is seeded with a value derived from the
-// input length.
-// 2. Main Loop: Data is processed in 8-byte chunks, with each chunk being
-// mixed into the hash state.
-// 3. Tail Processing: The final 1-7 bytes of data are handled.
-// 4. Finalization: The hash state is passed through a final mixing sequence to
-// ensure good bit distribution.
-//
-// Args:
-// input: A pointer to the data to be hashed.
-// len: The length of the data in bytes.
-//
-// Returns:
-// The 64-bit MurmurHash64A hash of the input data.
-inline uint64_t MurmurHashBytes(const void* input, size_t len) {
- // This implementation follows the canonical MurmurHash64A algorithm.
- // The constants `kMulConstant` (m) and the shift value `47` (r) are from
- // the original specification.
- // The seed is inspired by the one used in DuckDB.
- static constexpr uint64_t kSeed = 0xe17a1465U;
- static constexpr uint64_t kMulConstant = 0xc6a4a7935bd1e995;
- static constexpr int kShift = 47;
+ if (current_index == index) {
+ data_ = field.as_bytes();
+ return StatusOr<void>::Ok();
+ }
- uint64_t h = kSeed ^ (len * kMulConstant);
- const auto* data = static_cast<const uint8_t*>(input);
- const size_t num_blocks = len / 8;
+ ++current_index;
+ }
- // Process 8-byte (64-bit) chunks
- for (size_t i = 0; i < num_blocks; ++i) {
- uint64_t k;
- memcpy(&k, data, sizeof(k));
- data += sizeof(k); // Advance the pointer by 8 bytes
+ return StatusOr<void>::Error();
+}
- k *= kMulConstant;
- k ^= k >> kShift;
- k *= kMulConstant;
+StatusOr<RoCursor::RepeatedFieldIterator> RoCursor::IterateRepeatedField(
+ uint32_t field_id) const {
+ auto status_or_data = GetLengthDelimitedData();
+ PROTOVM_RETURN_IF_NOT_OK(status_or_data);
+ protozero::ProtoDecoder decoder(*status_or_data);
+ return RepeatedFieldIterator(decoder, field_id);
+}
- h ^= k;
- h *= kMulConstant;
+bool RoCursor::IsScalar() const {
+ auto* field = std::get_if<protozero::Field>(&data_);
+ if (!field) {
+ return false;
}
- // Process the remaining 1 to 7 bytes
- // The 'byte_ptr' now points to the beginning of the tail.
- switch (len & 7) {
- case 7:
- h ^= static_cast<uint64_t>(data[6]) << 48;
- [[fallthrough]];
- case 6:
- h ^= static_cast<uint64_t>(data[5]) << 40;
- [[fallthrough]];
- case 5:
- h ^= static_cast<uint64_t>(data[4]) << 32;
- [[fallthrough]];
- case 4:
- h ^= static_cast<uint64_t>(data[3]) << 24;
- [[fallthrough]];
- case 3:
- h ^= static_cast<uint64_t>(data[2]) << 16;
- [[fallthrough]];
- case 2:
- h ^= static_cast<uint64_t>(data[1]) << 8;
- [[fallthrough]];
- case 1:
- h ^= static_cast<uint64_t>(data[0]);
- h *= kMulConstant;
- }
+ return field->type() == protozero::proto_utils::ProtoWireType::kVarInt ||
+ field->type() == protozero::proto_utils::ProtoWireType::kFixed32 ||
+ field->type() == protozero::proto_utils::ProtoWireType::kFixed64;
+}
- // Final mixing stage
- h ^= h >> kShift;
- h *= kMulConstant;
- h ^= h >> kShift;
+bool RoCursor::IsBytes() const {
+ if (std::holds_alternative<protozero::ConstBytes>(data_)) {
+ return true;
+ }
- return h;
+ auto& field = std::get<protozero::Field>(data_);
+ return field.type() ==
+ protozero::proto_utils::ProtoWireType::kLengthDelimited;
}
-template <typename Float, typename Int>
-Int NormalizeFloatToInt(Float value) {
- static_assert(std::is_floating_point_v<Float>);
- static_assert(std::is_integral_v<Int>);
-
- // Normalize floating point representations which can vary.
- if (PERFETTO_UNLIKELY(value == 0.0)) {
- // Turn negative zero into positive zero
- value = 0.0;
- } else if (PERFETTO_UNLIKELY(PERFETTO_IS_NAN(value))) {
- // Turn arbtirary NaN representations to a consistent NaN repr.
- value = std::numeric_limits<Float>::quiet_NaN();
+StatusOr<Scalar> RoCursor::GetScalar() const {
+ if (!IsScalar()) {
+ PROTOVM_ABORT("Attempted to access length-delimited field as a scalar");
}
- Int res;
- static_assert(sizeof(Float) == sizeof(Int));
- memcpy(&res, &value, sizeof(Float));
- return res;
+
+ auto& field = std::get<protozero::Field>(data_);
+ return Scalar{field.type(), field.as_uint64()};
}
-// Computes a 64-bit hash for a single built-in value without any combination.
-// This is the core primitive used by both MurmurHashValue and
-// MurmurHashCombiner::CombineOne for built-in types.
-//
-// NOTE: This function intentionally has no else branch for non-builtin types,
-// which will cause a compile error if called with an unsupported type. Callers
-// should check if the type is supported before calling this function.
-template <typename T>
-auto MurmurHashBuiltinValue(const T& value) {
- if constexpr (std::is_enum_v<T>) {
- return murmur_internal::MurmurHashMix(
- static_cast<uint64_t>(static_cast<std::underlying_type_t<T>>(value)));
- } else if constexpr (std::is_integral_v<T>) {
- return murmur_internal::MurmurHashMix(static_cast<uint64_t>(value));
- } else if constexpr (std::is_same_v<T, double>) {
- return murmur_internal::MurmurHashMix(
- murmur_internal::NormalizeFloatToInt<double, uint64_t>(value));
- } else if constexpr (std::is_same_v<T, float>) {
- return murmur_internal::MurmurHashMix(
- murmur_internal::NormalizeFloatToInt<float, uint32_t>(value));
- } else if constexpr (std::is_same_v<T, std::string> ||
- std::is_same_v<T, std::string_view> ||
- std::is_same_v<T, base::StringView>) {
- return murmur_internal::MurmurHashBytes(value.data(), value.size());
- } else if constexpr (std::is_same_v<T, const char*>) {
- std::string_view view(value);
- return murmur_internal::MurmurHashBytes(view.data(), view.size());
- } else if constexpr (std::is_pointer_v<T>) {
- return murmur_internal::MurmurHashMix(
- static_cast<uint64_t>(reinterpret_cast<uintptr_t>(value)));
- } else {
- struct InvalidBuiltin {};
- return InvalidBuiltin{};
+StatusOr<protozero::ConstBytes> RoCursor::GetBytes() const {
+ if (std::holds_alternative<protozero::ConstBytes>(data_)) {
+ return std::get<protozero::ConstBytes>(data_);
}
-}
-// Helper to check if a type has a built-in MurmurHash implementation.
-template <typename T>
-constexpr bool HasMurmurHashBuiltinValue() {
- return std::is_same_v<decltype(MurmurHashBuiltinValue(std::declval<T>())),
- uint64_t>;
-}
+ auto& field = std::get<protozero::Field>(data_);
+ if (field.type() != protozero::proto_utils::ProtoWireType::kLengthDelimited) {
+ PROTOVM_ABORT(
+ "Attempted to access field as length-delimited but actual wire "
+ "type is "
+ "%u",
+ static_cast<uint32_t>(field.type()));
+ }
-// Helper to check if two types are integeral and U is convertible to T.
-template <typename T, typename U>
-constexpr bool IsConvertibleIntegral() {
- return std::is_integral_v<T> && std::is_integral_v<U> &&
- std::is_convertible_v<U, T>;
+ return field.as_bytes();
}
-// Helper to check if a type is string-like (i.e. string, c-string or string
-// views).
-template <typename T>
-constexpr bool IsStringLike() {
- return std::is_same_v<T, std::string> ||
- std::is_same_v<T, std::string_view> ||
- std::is_same_v<T, base::StringView> || std::is_same_v<T, const char*>;
-}
+StatusOr<protozero::ConstBytes> RoCursor::GetLengthDelimitedData() const {
+ if (std::holds_alternative<protozero::Field>(data_)) {
+ auto& field = std::get<protozero::Field>(data_);
+ if (field.type() !=
+ protozero::proto_utils::ProtoWireType::kLengthDelimited) {
+ PROTOVM_ABORT(
+ "Attempted to access field as length-delimited, but actual "
+ "wire type is %u",
+ static_cast<uint32_t>(field.type()));
+ }
+ return field.as_bytes();
+ }
-// Helper to check if heterogeneous lookup is allowed between T and U.
-// Only allows it for convertible integral types and string-like types.
-template <typename T, typename U>
-constexpr bool AllowsHeterogeneousLookup() {
- return IsConvertibleIntegral<T, U>() ||
- (IsStringLike<T>() && IsStringLike<U>());
+ return std::get<protozero::ConstBytes>(data_);
}
-// Helper to detect pointers in Combine(...).
-// Hashing pointers directly is prohibited as it often indicates a misuse
-// (e.g., passing ptr and len instead of a single std::string_view).
-template <typename... Args>
-constexpr bool HasPointerV = (std::is_pointer_v<Args> || ...);
+} // namespace protovm
+} // namespace perfetto
+// gen_amalgamated begin source: src/protovm/rw_proto.cc
+/*
+ * Copyright (C) 2025 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.
+ */
-} // namespace murmur_internal
+// gen_amalgamated expanded: #include "src/protovm/rw_proto.h"
-// ============================================================================
-// MurmurHashCombiner - the core hasher state object
-// ============================================================================
-//
-// A helper class to create a 64-bit MurmurHash from a series of
-// structured fields.
-//
-// This class supports both the absl-style hasher API and a direct
-// member Combine() method.
-//
-// Absl-style API (for custom types with PerfettoHashValue):
-// template <typename H>
-// friend H PerfettoHashValue(H h, const MyType& value) {
-// return H::Combine(std::move(h), value.field1, value.field2);
-// }
-//
-// Direct API (for simple hash combining):
-// MurmurHashCombiner combiner;
-// combiner.Combine(field1, field2, ...);
-// return combiner.digest();
-//
-// IMPORTANT: This is NOT a true streaming hash. It is an order-dependent
-// combiner. It does not guarantee that hashing two concatenated chunks of data
-// will produce the same result as hashing them separately in sequence.
-class MurmurHashCombiner {
- public:
- MurmurHashCombiner() = default;
+// gen_amalgamated expanded: #include "perfetto/protozero/message.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/proto_utils.h"
- // Static Combine - returns a new hasher with the combined state.
- // This is used by the absl-style PerfettoHashValue API.
- template <typename... Args>
- static MurmurHashCombiner Combine(MurmurHashCombiner h, const Args&... args) {
- h.Combine(args...);
- return h;
- }
+namespace perfetto {
+namespace protovm {
- // Member Combine - combines values into this hasher's state.
- // This is a convenient API for directly combining multiple values.
- // The combination is order-dependent.
- template <typename... Args>
- void Combine(const Args&... args) {
- static_assert(!murmur_internal::HasPointerV<Args...>,
- "MurmurHashCombiner::Combine() does not support pointers. "
- "If you want to hash the contents of a memory range, use a "
- "single hashable object (e.g., std::string_view). If you "
- "want to hash a pointer address, cast it to uintptr_t.");
- // Uses a C++17 fold expression with CombineOne for each argument.
- (CombineOne(args), ...);
- }
+RwProto::RwProto(Allocator* allocator)
+ : allocator_{allocator}, root_{Node::Empty{}} {}
- // Returns the digest (i.e. current state of the combiner).
- uint64_t digest() const { return hash_; }
+RwProto::~RwProto() {
+ allocator_->DeleteReferencedData(&root_);
+}
- private:
- // Combines a single value into the hasher state.
- template <typename T>
- void CombineOne(const T& value) {
- if constexpr (murmur_internal::HasMurmurHashBuiltinValue<T>()) {
- Update(murmur_internal::MurmurHashBuiltinValue(value));
- } else {
- // For custom types, use ADL to find the PerfettoHashValue function.
- // This will cause a compile error with a clear message if the function
- // is not defined.
- hash_ = PerfettoHashValue(std::move(*this), value).digest();
- }
+RwProto::Cursor RwProto::GetRoot() {
+ return Cursor{&root_, allocator_};
+}
+
+void RwProto::Serialize(protozero::Message* proto) const {
+ if (root_.GetIf<Node::Empty>()) {
+ return;
}
- // Low-level update with a pre-computed hash value. This uses a fast,
- // order-dependent combination step inspired by the `hash_combine` function
- // in the Boost C++ libraries.
- void Update(uint64_t piece_hash) {
- hash_ ^= piece_hash + 0x9e3779b9 + (hash_ << 6) + (hash_ >> 2);
+ if (auto* bytes = root_.GetIf<Node::Bytes>()) {
+ proto->AppendRawProtoBytes(bytes->data.get(), bytes->size);
+ return;
}
- static constexpr uint64_t kSeed = 0xe17a1465U;
- uint64_t hash_ = kSeed;
-};
+ auto* message = root_.GetIf<Node::Message>();
+ PERFETTO_DCHECK(message);
-// Simple wrapper function around MurmurHashCombiner to improve clarity in
-// callsites to not have to instantiate the class, call Combine() then digest().
-template <typename... Args>
-uint64_t MurmurHashCombine(const Args&... value) {
- return MurmurHashCombiner::Combine(MurmurHashCombiner{}, value...).digest();
+ for (auto it = message->field_id_to_node.begin(); it; ++it) {
+ auto field_id = static_cast<uint32_t>(it->key);
+ SerializeField(field_id, *it->value, proto);
+ }
}
-// Simple wrapper function to compute a hash value for a single value.
-// This is the primitive hash operation that MurmurHash<T> delegates to.
-//
-// For built-in types (integers, floats, strings), this uses a fast path that
-// avoids the overhead of the MurmurHashCombiner. For custom types, it delegates
-// to MurmurHashCombiner which will use ADL to find the PerfettoHashValue.
-template <typename T>
-uint64_t MurmurHashValue(const T& value) {
- if constexpr (murmur_internal::HasMurmurHashBuiltinValue<T>()) {
- return murmur_internal::MurmurHashBuiltinValue(value);
- } else {
- return MurmurHashCombine(value);
+void RwProto::SerializeField(uint32_t field_id,
+ const Node& node,
+ protozero::Message* proto) const {
+ if (node.GetIf<Node::Empty>()) {
+ return;
+ }
+
+ if (auto* bytes = node.GetIf<Node::Bytes>()) {
+ proto->AppendBytes(field_id, bytes->data.get(), bytes->size);
+ return;
}
-}
-// std::hash<T> drop-in class which uses MurmurHashValue as the primitive.
-// All specializations consistently delegate to MurmurHashValue.
-template <typename T>
-struct MurmurHash {
- using is_transparent = void;
+ if (auto* scalar = node.GetIf<Scalar>()) {
+ if (scalar->wire_type == protozero::proto_utils::ProtoWireType::kFixed32) {
+ proto->AppendFixed(field_id, static_cast<uint32_t>(scalar->value));
+ return;
+ }
- uint64_t operator()(const T& value) const { return MurmurHashValue(value); }
+ if (scalar->wire_type == protozero::proto_utils::ProtoWireType::kFixed64) {
+ proto->AppendFixed(field_id, static_cast<uint64_t>(scalar->value));
+ return;
+ }
- // Heterogeneous lookup support. Only allowed for types where it makes sense
- // (e.g. string-like types and convertible integral types).
- template <typename U>
- auto operator()(const U& value) const
- -> std::enable_if_t<murmur_internal::AllowsHeterogeneousLookup<T, U>(),
- uint64_t> {
- return MurmurHashValue(value);
+ proto->AppendVarInt(field_id, scalar->value);
+ return;
}
-};
-} // namespace perfetto::base
+ if (auto* message = node.GetIf<Node::Message>()) {
+ auto* message_proto =
+ proto->BeginNestedMessage<protozero::Message>(field_id);
-#endif // INCLUDE_PERFETTO_EXT_BASE_MURMUR_HASH_H_
+ for (auto it = message->field_id_to_node.begin(); it; ++it) {
+ auto message_field_id = static_cast<uint32_t>(it->key);
+ SerializeField(message_field_id, *it->value, message_proto);
+ }
+ }
+
+ if (node.GetIf<Node::IndexedRepeatedField>() ||
+ node.GetIf<Node::MappedRepeatedField>()) {
+ const IntrusiveMap* map;
+ if (auto* indexed = node.GetIf<Node::IndexedRepeatedField>()) {
+ map = &indexed->index_to_node;
+ } else {
+ map = &node.GetIf<Node::MappedRepeatedField>()->key_to_node;
+ }
+
+ for (auto it = map->begin(); it; ++it) {
+ SerializeField(field_id, *it->value, proto);
+ }
+ }
+}
+
+} // namespace protovm
+} // namespace perfetto
+// gen_amalgamated begin source: src/protovm/rw_proto_cursor.cc
/*
- * Copyright (C) 2021 The Android Open Source Project
+ * Copyright (C) 2025 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.
@@ -53591,1117 +58666,853 @@ struct MurmurHash {
* limitations under the License.
*/
-#ifndef INCLUDE_PERFETTO_EXT_BASE_FLAT_HASH_MAP_V1_H_
-#define INCLUDE_PERFETTO_EXT_BASE_FLAT_HASH_MAP_V1_H_
+// gen_amalgamated expanded: #include "src/protovm/rw_proto_cursor.h"
-// gen_amalgamated expanded: #include "perfetto/base/logging.h"
-// gen_amalgamated expanded: #include "perfetto/ext/base/murmur_hash.h"
-// gen_amalgamated expanded: #include "perfetto/ext/base/utils.h"
-// gen_amalgamated expanded: #include "perfetto/public/compiler.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/proto_decoder.h"
+// gen_amalgamated expanded: #include "src/protovm/error_handling.h"
-#include <algorithm>
-#include <cstddef>
-#include <cstdint>
-#include <cstring>
-#include <limits>
-#include <memory>
-#include <type_traits>
-#include <utility>
+namespace perfetto {
+namespace protovm {
-namespace perfetto::base {
+RwProtoCursor::RepeatedFieldIterator::RepeatedFieldIterator()
+ : allocator_{nullptr}, it_{} {}
-// An open-addressing hashmap implementation.
-// Pointers are not stable, neither for keys nor values.
-// Has similar performances of a RobinHood hash (without the complications)
-// and 2x an unordered map.
-// Doc: http://go/perfetto-hashtables .
-//
-// When used to implement a string pool in TraceProcessor, the performance
-// characteristics obtained by replaying the set of strings seeen in a 4GB trace
-// (226M strings, 1M unique) are the following (see flat_hash_map_benchmark.cc):
-// This(Linear+AppendOnly) 879,383,676 ns 258.013M insertions/s
-// This(LinearProbe): 909,206,047 ns 249.546M insertions/s
-// This(QuadraticProbe): 1,083,844,388 ns 209.363M insertions/s
-// std::unordered_map: 6,203,351,870 ns 36.5811M insertions/s
-// tsl::robin_map: 931,403,397 ns 243.622M insertions/s
-// absl::flat_hash_map: 998,013,459 ns 227.379M insertions/s
-// FollyF14FastMap: 1,181,480,602 ns 192.074M insertions/s
-//
-// The structs below define the probing algorithm used to probe slots upon a
-// collision. They are guaranteed to visit all slots as our table size is always
-// a power of two (see https://en.wikipedia.org/wiki/Quadratic_probing).
+RwProtoCursor::RepeatedFieldIterator::RepeatedFieldIterator(
+ Allocator* allocator,
+ IntrusiveMap::Iterator it)
+ : allocator_{allocator}, it_{it} {}
-// Linear probing can be faster if the hashing is well distributed and the load
-// is not high. For TraceProcessor's StringPool this is the fastest. It can
-// degenerate badly if the hashing doesn't spread (e.g., if using directly pids
-// as keys, with a no-op hashing function).
-struct LinearProbe {
- static inline size_t Calc(size_t key_hash, size_t step, size_t capacity) {
- return (key_hash + step) & (capacity - 1); // Linear probe
- }
-};
+RwProtoCursor::RepeatedFieldIterator&
+RwProtoCursor::RepeatedFieldIterator::RepeatedFieldIterator::operator++() {
+ ++it_;
+ return *this;
+}
-// Generates the sequence: 0, 3, 10, 21, 36, 55, ...
-// Can be a bit (~5%) slower than LinearProbe because it's less cache hot, but
-// avoids degenerating badly if the hash function is bad and causes clusters.
-// A good default choice unless benchmarks prove otherwise.
-struct QuadraticProbe {
- static inline size_t Calc(size_t key_hash, size_t step, size_t capacity) {
- return (key_hash + 2 * step * step + step) & (capacity - 1);
- }
-};
+RwProtoCursor RwProtoCursor::RepeatedFieldIterator::GetCursor() {
+ return RwProtoCursor{it_->value.get(), allocator_};
+}
-// Tends to perform in the middle between linear and quadratic.
-// It's a bit more cache-effective than the QuadraticProbe but can create more
-// clustering if the hash function doesn't spread well.
-// Generates the sequence: 0, 1, 3, 6, 10, 15, 21, ...
-struct QuadraticHalfProbe {
- static inline size_t Calc(size_t key_hash, size_t step, size_t capacity) {
- return (key_hash + (step * step + step) / 2) & (capacity - 1);
- }
-};
+RwProtoCursor::RepeatedFieldIterator::operator bool() const {
+ return static_cast<bool>(it_);
+}
-// Non-templated base class to hold helpers for FlatHashMap.
-struct FlatHashMapV1Base {
- public:
- // Helper to detect if a hasher has is_transparent defined.
- template <typename, typename = void>
- struct HasIsTransparent : std::false_type {};
+RwProtoCursor::RwProtoCursor() = default;
- template <typename H>
- struct HasIsTransparent<H, std::void_t<typename H::is_transparent>>
- : std::true_type {};
+RwProtoCursor::RwProtoCursor(Node* node, Allocator* allocator)
+ : node_{node}, allocator_{allocator} {}
- // Helper to check if a lookup key type K is allowed.
- // Returns true if:
- // 1. K can be implicitly converted to Key, OR
- // 2. Hasher has is_transparent AND Hasher is invocable with K AND Key and K
- // are equality comparable
- template <typename K, typename Key, typename Hasher>
- static constexpr bool IsLookupKeyAllowed() {
- if constexpr (HasIsTransparent<Hasher>::value) {
- return std::is_invocable_v<Hasher, const K&> &&
- std::is_same_v<decltype(std::declval<const Key&>() ==
- std::declval<const K&>()),
- bool>;
- } else if constexpr (std::is_convertible_v<K, Key>) {
- return true;
- } else {
- return false;
- }
- }
-};
+bool RwProtoCursor::operator==(const RwProtoCursor& other) const {
+ return node_ == other.node_;
+}
+bool RwProtoCursor::operator!=(const RwProtoCursor& other) const {
+ return !(*this == other);
+}
-template <typename Key,
- typename Value,
- typename Hasher = base::MurmurHash<Key>,
- typename Probe = QuadraticProbe,
- bool AppendOnly = false>
-class FlatHashMapV1 : protected FlatHashMapV1Base {
- public:
- class Iterator {
- public:
- explicit Iterator(const FlatHashMapV1* map) : map_(map) {
- FindNextNonFree();
- }
- ~Iterator() = default;
- Iterator(const Iterator&) = default;
- Iterator& operator=(const Iterator&) = default;
- Iterator(Iterator&&) noexcept = default;
- Iterator& operator=(Iterator&&) noexcept = default;
+StatusOr<bool> RwProtoCursor::IsRoot() const {
+ PROTOVM_RETURN_IF_NOT_OK(CheckIsValid());
+ return parent_link_.node == nullptr;
+}
- Key& key() { return map_->keys_[idx_]; }
- Value& value() { return map_->values_[idx_]; }
- const Key& key() const { return map_->keys_[idx_]; }
- const Value& value() const { return map_->values_[idx_]; }
+StatusOr<bool> RwProtoCursor::HasField(uint32_t field_id) {
+ PROTOVM_RETURN_IF_NOT_OK(CheckIsValid());
- explicit operator bool() const { return idx_ != kEnd; }
- Iterator& operator++() {
- PERFETTO_DCHECK(idx_ < map_->capacity_);
- ++idx_;
- FindNextNonFree();
- return *this;
- }
+ // Eagerly decompose bytes because the field being tested will be entered
+ // later anyways. See Executor::EnterField().
+ auto status = ConvertToMessageIfNeeded(node_);
+ PROTOVM_RETURN_IF_NOT_OK(status);
+ auto* message = node_->GetIf<Node::Message>();
+ bool found = static_cast<bool>(message->field_id_to_node.Find(field_id));
+ return found;
+}
- private:
- static constexpr size_t kEnd = std::numeric_limits<size_t>::max();
+StatusOr<void> RwProtoCursor::EnterField(uint32_t field_id) {
+ PROTOVM_RETURN_IF_NOT_OK(CheckIsValid());
- void FindNextNonFree() {
- const auto& tags = map_->tags_;
- for (; idx_ < map_->capacity_; idx_++) {
- if (tags[idx_] != kFreeSlot && (AppendOnly || tags[idx_] != kTombstone))
- return;
- }
- idx_ = kEnd;
- }
+ auto status_or_it = FindOrCreateMessageField(node_, field_id);
+ PROTOVM_RETURN_IF_NOT_OK(status_or_it);
+ auto it = *status_or_it;
- const FlatHashMapV1* map_ = nullptr;
- size_t idx_ = 0;
- }; // Iterator
- static constexpr int kDefaultLoadLimitPct = 75;
- explicit FlatHashMapV1(size_t initial_capacity = 0,
- int load_limit_pct = kDefaultLoadLimitPct)
- : load_limit_percent_(load_limit_pct) {
- if (initial_capacity > 0)
- Reset(initial_capacity, true);
+ if (it->value->GetIf<Node::IndexedRepeatedField>()) {
+ PROTOVM_ABORT(
+ "Attempted to enter field (id=%u) as a simple field but it is an "
+ "indexed repeated field",
+ field_id);
}
- // We are calling Clear() so that the destructors for the inserted entries are
- // called (unless they are trivial, in which case it will be a no-op).
- ~FlatHashMapV1() { Clear(); }
+ if (it->value->GetIf<Node::MappedRepeatedField>()) {
+ PROTOVM_ABORT(
+ "Attempted to enter field (id=%u) as a simple field but it is a "
+ "mapped repeated field",
+ field_id);
+ }
- FlatHashMapV1(FlatHashMapV1&& other) noexcept {
- tags_ = std::move(other.tags_);
- keys_ = std::move(other.keys_);
- values_ = std::move(other.values_);
- capacity_ = other.capacity_;
- size_ = other.size_;
- tombstones_ = other.tombstones_;
- max_probe_length_ = other.max_probe_length_;
- load_limit_ = other.load_limit_;
- load_limit_percent_ = other.load_limit_percent_;
+ parent_link_ = {node_, &node_->GetIf<Node::Message>()->field_id_to_node,
+ std::addressof(*it)};
+ node_ = it->value.get();
+ return StatusOr<void>::Ok();
+}
- new (&other) FlatHashMapV1();
- }
+StatusOr<void> RwProtoCursor::EnterRepeatedFieldAt(uint32_t field_id,
+ uint32_t index) {
+ PROTOVM_RETURN_IF_NOT_OK(CheckIsValid());
- FlatHashMapV1& operator=(FlatHashMapV1&& other) noexcept {
- this->~FlatHashMapV1();
- new (this) FlatHashMapV1(std::move(other));
- return *this;
- }
+ auto status_or_message_field = FindOrCreateMessageField(node_, field_id);
+ PROTOVM_RETURN_IF_NOT_OK(status_or_message_field);
+ auto message_field = *status_or_message_field;
- FlatHashMapV1(const FlatHashMapV1&) = delete;
- FlatHashMapV1& operator=(const FlatHashMapV1&) = delete;
+ auto status =
+ ConvertToIndexedRepeatedFieldIfNeeded(message_field->value.get());
+ PROTOVM_RETURN_IF_NOT_OK(status);
- std::pair<Value*, bool> Insert(Key key, Value value) {
- const size_t key_hash = Hasher{}(key);
- const uint8_t tag = HashToTag(key_hash);
- static constexpr size_t kSlotNotFound = std::numeric_limits<size_t>::max();
+ auto status_or_repeated_field =
+ FindOrCreateIndexedRepeatedField(message_field->value.get(), index);
+ PROTOVM_RETURN_IF_NOT_OK(status_or_repeated_field);
- // This for loop does in reality at most two attempts:
- // The first iteration either:
- // - Early-returns, because the key exists already,
- // - Finds an insertion slot and proceeds because the load is < limit.
- // The second iteration is only hit in the unlikely case of this insertion
- // bringing the table beyond the target |load_limit_| (or the edge case
- // of the HT being full, if |load_limit_pct_| = 100).
- // We cannot simply pre-grow the table before insertion, because we must
- // guarantee that calling Insert() with a key that already exists doesn't
- // invalidate iterators.
- size_t insertion_slot;
- size_t probe_len;
- for (;;) {
- PERFETTO_DCHECK((capacity_ & (capacity_ - 1)) == 0); // Must be a pow2.
- insertion_slot = kSlotNotFound;
- // Start the iteration at the desired slot (key_hash % capacity_)
- // searching either for a free slot or a tombstone. In the worst case we
- // might end up scanning the whole array of slots. The Probe functions are
- // guaranteed to visit all the slots within |capacity_| steps. If we find
- // a free slot, we can stop the search immediately (a free slot acts as an
- // "end of chain for entries having the same hash". If we find a
- // tombstones (a deleted slot) we remember its position, but have to keep
- // searching until a free slot to make sure we don't insert a duplicate
- // key.
- for (probe_len = 0; probe_len < capacity_;) {
- const size_t idx = Probe::Calc(key_hash, probe_len, capacity_);
- PERFETTO_DCHECK(idx < capacity_);
- const uint8_t tag_idx = tags_[idx];
- ++probe_len;
- if (tag_idx == kFreeSlot) {
- // Rationale for "insertion_slot == kSlotNotFound": if we encountered
- // a tombstone while iterating we should reuse that rather than
- // taking another slot.
- if (AppendOnly || insertion_slot == kSlotNotFound)
- insertion_slot = idx;
- break;
- }
- // We should never encounter tombstones in AppendOnly mode.
- PERFETTO_DCHECK(!(tag_idx == kTombstone && AppendOnly));
- if (!AppendOnly && tag_idx == kTombstone) {
- insertion_slot = idx;
- continue;
- }
- if (tag_idx == tag && keys_[idx] == key) {
- // The key is already in the map.
- return std::make_pair(&values_[idx], false);
- }
- } // for (idx)
+ parent_link_ = {
+ message_field->value.get(),
+ &message_field->value->GetIf<Node::IndexedRepeatedField>()->index_to_node,
+ std::addressof(**status_or_repeated_field)};
+ node_ = (*status_or_repeated_field)->value.get();
- // If we got to this point the key does not exist (otherwise we would have
- // hit the return above) and we are going to insert a new entry.
- // Before doing so, ensure we stay under the target load limit.
- if (PERFETTO_UNLIKELY(size_ >= load_limit_)) {
- MaybeGrowAndRehash(/*grow=*/true);
- continue;
- }
- // If there are too many tombstones, it's worth doing a rehash to
- // clean them up. This is to avoid the case where we have a table full
- // of tombstones which would cause lookups to be very slow.
- bool is_many_tombstones = tombstones_ > size_ && size_ > 128;
- bool is_tombstones_plus_size_too_high = tombstones_ + size_ > load_limit_;
- if (PERFETTO_UNLIKELY(is_many_tombstones ||
- is_tombstones_plus_size_too_high)) {
- MaybeGrowAndRehash(/*grow=*/false);
- continue;
- }
- PERFETTO_DCHECK(insertion_slot != kSlotNotFound);
- break;
- } // for (attempt)
+ return StatusOr<void>::Ok();
+}
- PERFETTO_CHECK(insertion_slot < capacity_);
+StatusOr<RwProtoCursor::RepeatedFieldIterator>
+RwProtoCursor::IterateRepeatedField(uint32_t field_id) {
+ PROTOVM_RETURN_IF_NOT_OK(CheckIsValid());
- // We found a free slot (or a tombstone). Proceed with the insertion.
- if (tags_[insertion_slot] == kTombstone) {
- PERFETTO_DCHECK(tombstones_ > 0);
- tombstones_--;
- }
- Value* value_idx = &values_[insertion_slot];
- new (&keys_[insertion_slot]) Key(std::move(key));
- new (value_idx) Value(std::move(value));
- tags_[insertion_slot] = tag;
- PERFETTO_DCHECK(probe_len > 0 && probe_len <= capacity_);
- max_probe_length_ = std::max(max_probe_length_, probe_len);
- size_++;
+ auto status_convertion_to_message = ConvertToMessageIfNeeded(node_);
+ PROTOVM_RETURN_IF_NOT_OK(status_convertion_to_message);
- return std::make_pair(value_idx, true);
- }
+ auto* message = node_->GetIf<Node::Message>();
+ auto it = message->field_id_to_node.Find(field_id);
- template <typename K = Key>
- Value* Find(const K& key) const {
- const size_t idx = FindInternal(key);
- if (idx == kNotFound)
- return nullptr;
- return &values_[idx];
+ if (!it) {
+ return RepeatedFieldIterator{};
}
- template <typename K = Key>
- bool Erase(const K& key) {
- if (AppendOnly)
- PERFETTO_FATAL("Erase() not supported because AppendOnly=true");
- size_t idx = FindInternal(key);
- if (idx == kNotFound)
- return false;
- EraseInternal(idx);
- return true;
- }
+ auto* field = it->value.get();
+ auto status_convertion_to_repeated_field =
+ ConvertToIndexedRepeatedFieldIfNeeded(field);
+ PROTOVM_RETURN_IF_NOT_OK(status_convertion_to_repeated_field);
- void Clear() {
- // Avoid trivial heap operations on zero-capacity std::move()-d objects.
- if (PERFETTO_UNLIKELY(capacity_ == 0))
- return;
+ return RepeatedFieldIterator{
+ allocator_,
+ field->GetIf<Node::IndexedRepeatedField>()->index_to_node.begin()};
+}
- for (size_t i = 0; i < capacity_; ++i) {
- const uint8_t tag = tags_[i];
- if (tag != kFreeSlot && (AppendOnly || tag != kTombstone)) {
- keys_[i].~Key();
- values_[i].~Value();
- }
- }
- Reset(capacity_, false);
- }
+StatusOr<void> RwProtoCursor::EnterRepeatedFieldByKey(uint32_t field_id,
+ uint32_t map_key_field_id,
+ uint64_t key) {
+ PROTOVM_RETURN_IF_NOT_OK(CheckIsValid());
- Value& operator[](Key key) {
- auto it_and_inserted = Insert(std::move(key), Value{});
- return *it_and_inserted.first;
- }
+ auto status_or_message_field = FindOrCreateMessageField(node_, field_id);
+ PROTOVM_RETURN_IF_NOT_OK(status_or_message_field);
+ auto message_field = *status_or_message_field;
- Iterator GetIterator() { return Iterator(this); }
- const Iterator GetIterator() const { return Iterator(this); }
+ auto status_conversion = ConvertToMappedRepeatedFieldIfNeeded(
+ message_field->value.get(), map_key_field_id);
+ PROTOVM_RETURN_IF_NOT_OK(status_conversion);
- size_t size() const { return size_; }
- size_t capacity() const { return capacity_; }
+ auto status_or_repeated_field =
+ FindOrCreateMappedRepeatedField(message_field->value.get(), key);
+ PROTOVM_RETURN_IF_NOT_OK(status_or_repeated_field);
- // "protected" here is only for the flat_hash_map_benchmark.cc. Everything
- // below is by all means private.
- protected:
- enum ReservedTags : uint8_t { kFreeSlot = 0, kTombstone = 1 };
- static constexpr size_t kNotFound = std::numeric_limits<size_t>::max();
+ parent_link_ = {
+ message_field->value.get(),
+ &message_field->value->GetIf<Node::MappedRepeatedField>()->key_to_node,
+ std::addressof(**status_or_repeated_field)};
+ node_ = (*status_or_repeated_field)->value.get();
- template <typename K = Key>
- size_t FindInternal(const K& key) const {
- static_assert(
- IsLookupKeyAllowed<K, Key, Hasher>(),
- "Heterogeneous lookup requires Hasher to define is_transparent and "
- "support hashing the lookup key type. For same-type lookup, Key and K "
- "must match exactly.");
- const size_t key_hash = Hasher{}(key);
- const uint8_t tag = HashToTag(key_hash);
- PERFETTO_DCHECK((capacity_ & (capacity_ - 1)) == 0); // Must be a pow2.
- PERFETTO_DCHECK(max_probe_length_ <= capacity_);
- for (size_t i = 0; i < max_probe_length_; ++i) {
- const size_t idx = Probe::Calc(key_hash, i, capacity_);
- const uint8_t tag_idx = tags_[idx];
+ return StatusOr<void>::Ok();
+}
- if (tag_idx == kFreeSlot)
- return kNotFound;
- // HashToTag() never returns kTombstone, so the tag-check below cannot
- // possibly match. Also we just want to skip tombstones.
- if (tag_idx == tag && keys_[idx] == key) {
- PERFETTO_DCHECK(tag_idx > kTombstone);
- return idx;
- }
- } // for (idx)
- return kNotFound;
+StatusOr<Scalar> RwProtoCursor::GetScalar() const {
+ PROTOVM_RETURN_IF_NOT_OK(CheckIsValid());
+
+ auto* scalar = node_->GetIf<Scalar>();
+ if (!scalar) {
+ PROTOVM_ABORT("Attempted \"get scalar\" operation but node has type %s",
+ node_->GetTypeName());
}
+ return *scalar;
+}
- void EraseInternal(size_t idx) {
- PERFETTO_DCHECK(tags_[idx] > kTombstone);
- PERFETTO_DCHECK(size_ > 0);
- tags_[idx] = kTombstone;
- keys_[idx].~Key();
- values_[idx].~Value();
- size_--;
- tombstones_++;
- PERFETTO_DCHECK(size_ + tombstones_ <= capacity_);
+StatusOr<void> RwProtoCursor::SetBytes(protozero::ConstBytes data) {
+ PROTOVM_RETURN_IF_NOT_OK(CheckIsValid());
+
+ if (bool is_compatible = node_->GetIf<Node::Empty>() ||
+ node_->GetIf<Node::Bytes>() ||
+ node_->GetIf<Node::Message>();
+ !is_compatible) {
+ PROTOVM_ABORT("Attempted \"set bytes\" operation but node has type %s",
+ node_->GetTypeName());
}
- PERFETTO_NO_INLINE void MaybeGrowAndRehash(bool grow) {
- PERFETTO_DCHECK(size_ <= capacity_);
- const size_t old_capacity = capacity_;
+ auto status_or_bytes = allocator_->AllocateAndCopyBytes(data);
+ PROTOVM_RETURN_IF_NOT_OK(status_or_bytes);
- // Grow quickly up to 1MB, then chill.
- const size_t old_size_bytes = old_capacity * (sizeof(Key) + sizeof(Value));
- const size_t grow_factor = old_size_bytes < (1024u * 1024u) ? 8 : 2;
- const size_t new_capacity =
- grow ? std::max(old_capacity * grow_factor, size_t(1024))
- : old_capacity;
+ allocator_->DeleteReferencedData(node_);
+ node_->value = Node::Bytes{std::move(*status_or_bytes)};
- auto old_tags(std::move(tags_));
- auto old_keys(std::move(keys_));
- auto old_values(std::move(values_));
- size_t old_size = size_;
+ return StatusOr<void>::Ok();
+}
- // This must be a CHECK (i.e. not just a DCHECK) to prevent UAF attacks on
- // 32-bit archs that try to double the size of the table until wrapping.
- PERFETTO_CHECK(new_capacity >= old_capacity);
- Reset(new_capacity, true);
+StatusOr<void> RwProtoCursor::SetScalar(Scalar scalar) {
+ PROTOVM_RETURN_IF_NOT_OK(CheckIsValid());
- size_t new_size = 0; // Recompute the size.
- for (size_t i = 0; i < old_capacity; ++i) {
- const uint8_t old_tag = old_tags[i];
- if (old_tag != kFreeSlot && old_tag != kTombstone) {
- Insert(std::move(old_keys[i]), std::move(old_values[i]));
- old_keys[i].~Key(); // Destroy the old objects.
- old_values[i].~Value();
- new_size++;
- }
- }
- PERFETTO_DCHECK(new_size == old_size);
- PERFETTO_DCHECK(tombstones_ == 0);
- size_ = new_size;
+ if (bool is_compatible =
+ node_->GetIf<Node::Empty>() || node_->GetIf<Scalar>();
+ !is_compatible) {
+ PROTOVM_ABORT("Attempted \"set scalar\" operation but node has type %s",
+ node_->GetTypeName());
}
- // Doesn't call destructors. Use Clear() for that.
- PERFETTO_NO_INLINE void Reset(size_t n, bool reallocate) {
- PERFETTO_DCHECK((n & (n - 1)) == 0); // Must be a pow2.
-
- capacity_ = n;
- max_probe_length_ = 0;
- size_ = 0;
- tombstones_ = 0;
- load_limit_ = n * static_cast<size_t>(load_limit_percent_) / 100;
- load_limit_ = std::min(load_limit_, n);
+ node_->value = scalar;
+ return StatusOr<void>::Ok();
+}
- if (reallocate) {
- tags_.reset(new uint8_t[n]);
- keys_ = AlignedAllocTyped<Key[]>(n); // Deliberately not 0-initialized.
- values_ =
- AlignedAllocTyped<Value[]>(n); // Deliberately not 0-initialized.
- }
+StatusOr<void> RwProtoCursor::Merge(protozero::ConstBytes data,
+ uint32_t flags) {
+ PROTOVM_RETURN_IF_NOT_OK(CheckIsValid());
- // Only clear the tags if not nullptr.
- if (tags_) {
- memset(&tags_[0], 0, n); // Clear all tags.
- }
+ if (bool is_compatible = node_->GetIf<Node::Empty>() ||
+ node_->GetIf<Node::Message>() ||
+ node_->GetIf<Node::Bytes>();
+ !is_compatible) {
+ PROTOVM_ABORT("Attempted MERGE operation but node has type %s",
+ node_->GetTypeName());
}
- static inline uint8_t HashToTag(size_t full_hash) {
- uint8_t tag = full_hash >> (sizeof(full_hash) * 8 - 8);
- // Ensure the hash is always >= 2. We use 0, 1 for kFreeSlot and kTombstone.
- tag += (tag <= kTombstone) << 1;
- PERFETTO_DCHECK(tag > kTombstone);
- return tag;
+ if (data.size == 0) {
+ return StatusOr<void>::Ok();
}
- size_t capacity_ = 0;
- size_t size_ = 0;
- size_t tombstones_ = 0;
- size_t max_probe_length_ = 0;
- size_t load_limit_ = 0; // Updated every time |capacity_| changes.
- int load_limit_percent_ =
- kDefaultLoadLimitPct; // Load factor limit in % of |capacity_|.
+ auto status_convert_to_message = ConvertToMessageIfNeeded(node_);
+ PROTOVM_RETURN_IF_NOT_OK(status_convert_to_message);
+ auto* message = node_->GetIf<Node::Message>();
- // These arrays have always the |capacity_| elements.
- // Note: AlignedUniquePtr just allocates memory, doesn't invoke any ctor/dtor.
- std::unique_ptr<uint8_t[]> tags_;
- AlignedUniquePtr<Key[]> keys_;
- AlignedUniquePtr<Value[]> values_;
-};
+ protozero::ProtoDecoder decoder(data);
-} // namespace perfetto::base
+ for (auto field = decoder.ReadField(); field.valid();
+ field = decoder.ReadField()) {
+ auto it = message->field_id_to_node.Find(field.id());
-#endif // INCLUDE_PERFETTO_EXT_BASE_FLAT_HASH_MAP_V1_H_
-/*
- * Copyright (C) 2025 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.
- */
+ bool del_if_src_empty = (flags & kDelIfSrcEmpty) != 0;
+ if (it && del_if_src_empty &&
+ field.type() ==
+ protozero::proto_utils::ProtoWireType::kLengthDelimited &&
+ field.size() == 0) {
+ // Implements remove submessage semantics: empty src field means delete
+ // the dst field
+ message->field_id_to_node.Remove(*it);
+ allocator_->Delete(&*it);
+ continue;
+ }
-#ifndef INCLUDE_PERFETTO_EXT_BASE_FLAT_HASH_MAP_H_
-#define INCLUDE_PERFETTO_EXT_BASE_FLAT_HASH_MAP_H_
+ bool skip_submessages = (flags & kSkipSubmessages) != 0;
+ if (skip_submessages && it && it->value->GetIf<Node::Message>()) {
+ // Implements deep merge semantics: skip this message that was already
+ // merged by a previous operation
+ continue;
+ }
-// gen_amalgamated expanded: #include "perfetto/base/build_config.h"
-// gen_amalgamated expanded: #include "perfetto/base/logging.h"
-// gen_amalgamated expanded: #include "perfetto/ext/base/bits.h"
-// gen_amalgamated expanded: #include "perfetto/ext/base/flat_hash_map_v1.h"
-// gen_amalgamated expanded: #include "perfetto/ext/base/murmur_hash.h"
-// gen_amalgamated expanded: #include "perfetto/ext/base/string_view.h"
-// gen_amalgamated expanded: #include "perfetto/ext/base/utils.h"
-// gen_amalgamated expanded: #include "perfetto/public/compiler.h"
+ auto status_or_map_value = CreateNodeFromField(field);
+ PROTOVM_RETURN_IF_NOT_OK(status_or_map_value);
-#include <algorithm>
-#include <cstddef>
-#include <cstdint>
-#include <cstring>
-#include <functional>
-#include <limits>
-#include <memory>
-#include <string>
-#include <string_view>
-#include <type_traits>
-#include <utility>
+ if (!it) {
+ auto status_or_it = MapInsert(&message->field_id_to_node, field.id(),
+ std::move(*status_or_map_value));
+ PROTOVM_RETURN_IF_NOT_OK(status_or_it);
+ (*status_or_it)->value->has_been_merged = true;
+ continue;
+ }
-#if PERFETTO_BUILDFLAG(PERFETTO_X64_CPU_OPT)
-#include <immintrin.h>
-#endif
+ if (it->value->GetIf<Node::MappedRepeatedField>()) {
+ PROTOVM_ABORT(
+ "Merge operation of mapped repeated field is not supported (field id "
+ "= %u)",
+ field.id());
+ }
-namespace perfetto::base {
+ // Promote field as repeated if needed:
+ // If this is the second time that the same field ID is being merged, then
+ // they are a repeated fields and they should live within an
+ // IndexedRepeatedField node.
+ if (it->value->has_been_merged) {
+ auto status_convert_to_indexed =
+ ConvertToIndexedRepeatedFieldIfNeeded(it->value.get());
+ PROTOVM_RETURN_IF_NOT_OK(status_convert_to_indexed);
+ }
-// A Swiss Table-style open-addressing hashmap implementation.
-// Inspired by absl::flat_hash_map, this uses a metadata array of control bytes
-// to enable fast SIMD-accelerated probing.
-//
-// Key design choices:
-// - Control bytes: Each slot has a 1-byte tag (7-bit H2 hash or special marker)
-// stored in a separate array, enabling fast group-based matching.
-// - SIMD acceleration: On x64, uses SSE instructions to match 16 control bytes
-// in parallel. Falls back to SWAR (SIMD Within A Register) on other platforms
-// matching 8 bytes at a time.
-// - Triangular probing: Uses the sequence 0, 16, 48, 96, ... (like Absl) to
-// probe groups of slots, ensuring good cache behavior.
-// - Pointers are NOT stable: Neither keys nor values have stable addresses
-// across insertions that trigger rehashing.
-//
-// See also: FlatHashMapV1 in flat_hash_map_v1.h for the older implementation
-// using traditional open-addressing with configurable probing strategies.
+ if (auto* indexed_fields = it->value->GetIf<Node::IndexedRepeatedField>()) {
+ // Implements merge semantics for repeated fields: all existing fields are
+ // removed and replaced with the newly received fields.
+ if (!it->value->has_been_merged) {
+ // Optimization opportunity: reuse the existing nodes to avoid N
+ // allocation-deallocation pairs, where N is the number of newly
+ // received repeated fields.
+ allocator_->DeleteReferencedData(it->value.get());
+ it->value->has_been_merged = true;
+ }
+ MapInsert(&indexed_fields->index_to_node,
+ indexed_fields->index_to_node.Size(),
+ std::move(*status_or_map_value));
+ continue;
+ }
-// Non-templated base class to hold helpers for FlatHashMapV2.
-namespace flat_hash_map_v2_internal {
+ // Optimization oppurtunity: reuse the existing node to avoid one
+ // allocation-deallocation pair
+ allocator_->Delete(it->value.release());
+ it->value = std::move(*status_or_map_value);
+ it->value->has_been_merged = true;
+ }
-// Helper to detect if a hasher has is_transparent defined.
-template <typename, typename = void>
-struct HasIsTransparent : std::false_type {};
+ // Reset the merge flags
+ for (auto& field : message->field_id_to_node) {
+ field.value->has_been_merged = false;
+ }
-template <typename H>
-struct HasIsTransparent<H, std::void_t<typename H::is_transparent>>
- : std::true_type {};
+ return StatusOr<void>::Ok();
+}
-// Equality comparator trait.
-template <typename T>
-struct HashEq : public std::equal_to<T> {};
+StatusOr<void> RwProtoCursor::Delete() {
+ PROTOVM_RETURN_IF_NOT_OK(CheckIsValid());
-// Specialization for std::string to compare via std::string_view.
-//
-// This exists because after benchmarking, it turns out libc++ has an
-// "optimization" for std::string equality that does something byte by
-// byte comparision for short strings but this is slower than just memcmp.
-//
-// This helps close the gap to absl::flat_hash_map for string keys.
-template <>
-struct HashEq<std::string> {
- bool operator()(const std::string& a, const std::string& b) const {
- return std::string_view(a) == std::string_view(b);
- }
- bool operator()(const std::string& a, const std::string_view& b) const {
- return std::string_view(a) == b;
- }
- bool operator()(const std::string& a, base::StringView b) const {
- return base::StringView(a) == b;
+ PROTOVM_ASSIGN_OR_RETURN(bool is_root, IsRoot());
+ if (is_root) {
+ node_->value = Node::Empty{};
+ return StatusOr<void>::Ok();
}
-};
-// Specialization for double to prevent spurious -Wfloat-equal warnings.
-//
-// Trace processor legitimately has a need to compare with exact equality
-template <>
-struct HashEq<double> {
- bool operator()(double a, double b) const { return std::equal_to<>()(a, b); }
-};
+ PERFETTO_DCHECK(parent_link_.map);
+ PERFETTO_DCHECK(parent_link_.map_node);
-// Helper to check if a lookup key type K is allowed.
-// Returns true if:
-// 1. K can be implicitly converted to Key, OR
-// 2. Hasher has is_transparent AND Hasher is invocable with K AND Key and K
-// are equality comparable
-template <typename K, typename Key, typename Hasher>
-static constexpr bool IsLookupKeyAllowed() {
- if constexpr (HasIsTransparent<Hasher>::value) {
- return std::is_invocable_v<Hasher, const K&> &&
- std::is_invocable_v<std::equal_to<>, const Key&, const K&>;
- } else if constexpr (std::is_convertible_v<K, Key>) {
- return true;
- } else {
- return false;
- }
+ parent_link_.map->Remove(*parent_link_.map_node);
+ allocator_->Delete(parent_link_.map_node);
+
+ // Delete operation invalidates cursor
+ node_ = nullptr;
+ parent_link_ = {};
+
+ return StatusOr<void>::Ok();
}
-// Swiss Table control byte encoding:
-// - Empty: 0x80 (10000000) - MSB set, easy to detect with sign bit
-// - Deleted: 0xFE (11111110) - MSB set
-// - Full: 0x00-0x7F - MSB clear, stores 7-bit H2 hash
-static constexpr uint8_t kFreeSlot = 0x80; // Empty slot
-static constexpr uint8_t kTombstone = 0xFE; // Deleted slot
+StatusOr<void> RwProtoCursor::ConvertToMessageIfNeeded(Node* node) {
+ if (node->GetIf<Node::Message>()) {
+ return StatusOr<void>::Ok();
+ }
-// The default load limit percent before growing the table.
-static constexpr int kDefaultLoadLimitPct = 75;
+ if (node->GetIf<Node::Empty>()) {
+ node->value = Node::Message{};
+ return StatusOr<void>::Ok();
+ }
-} // namespace flat_hash_map_v2_internal
+ auto* bytes = node->GetIf<Node::Bytes>();
+ if (!bytes) {
+ PROTOVM_ABORT("Attempted conversion to message but node has type %s",
+ node->GetTypeName());
+ }
-template <typename Key,
- typename Value,
- typename Hasher = base::MurmurHash<Key>,
- typename Eq = flat_hash_map_v2_internal::HashEq<Key>>
-class FlatHashMapV2 {
- private:
- // Import constants from internal namespace.
- static constexpr uint8_t kFreeSlot = flat_hash_map_v2_internal::kFreeSlot;
- static constexpr uint8_t kTombstone = flat_hash_map_v2_internal::kTombstone;
- static constexpr int kDefaultLoadLimitPct =
- flat_hash_map_v2_internal::kDefaultLoadLimitPct;
+ Node::Message message;
- // Slot structure holds both key and value
- struct Slot {
- Key key;
- Value value;
- };
+ protozero::ProtoDecoder decoder(protozero::ConstBytes{
+ static_cast<const uint8_t*>(bytes->data.get()), bytes->size});
- public:
- class Iterator {
- public:
- explicit Iterator(const uint8_t* ctrl, const uint8_t* ctrl_end, Slot* slot)
- : ctrl_(ctrl), ctrl_end_(ctrl_end), slot_(slot) {
- FindNextNonFree();
+ for (auto field = decoder.ReadField(); field.valid();
+ field = decoder.ReadField()) {
+ auto status_or_map_value = CreateNodeFromField(field);
+ if (!status_or_map_value.IsOk()) {
+ allocator_->DeleteReferencedData(&message);
+ PROTOVM_RETURN(status_or_map_value);
}
- ~Iterator() = default;
- Iterator(const Iterator&) = default;
- Iterator& operator=(const Iterator&) = default;
- Iterator(Iterator&&) noexcept = default;
- Iterator& operator=(Iterator&&) noexcept = default;
- const Key& key() { return slot_->key; }
- Value& value() { return slot_->value; }
- const Key& key() const { return slot_->key; }
- const Value& value() const { return slot_->value; }
+ auto it = message.field_id_to_node.Find(field.id());
- explicit operator bool() const { return ctrl_ != ctrl_end_; }
- Iterator& operator++() {
- PERFETTO_DCHECK(ctrl_ != ctrl_end_);
- ++ctrl_;
- ++slot_;
- FindNextNonFree();
- return *this;
+ // First occurrence of this field id. Just insert a new field into the
+ // map.
+ if (!it) {
+ auto status_or_it = MapInsert(&message.field_id_to_node, field.id(),
+ std::move(*status_or_map_value));
+ if (!status_or_it.IsOk()) {
+ allocator_->DeleteReferencedData(&message);
+ PROTOVM_RETURN(status_or_it, "Insert message field (id = %u)",
+ field.id());
+ }
+ continue;
}
- private:
- void FindNextNonFree() {
- for (; ctrl_ != ctrl_end_; ++ctrl_, ++slot_) {
- const uint8_t cur_ctrl = *ctrl_;
- if (cur_ctrl != kFreeSlot && cur_ctrl != kTombstone)
- return;
- }
+ // Nth occurrence of this field id:
+ // 1. Make sure we have an IndexedRepeatedField node
+ // 2. Append into the IndexedRepeatedField's map
+ auto status_conversion =
+ ConvertToIndexedRepeatedFieldIfNeeded(it->value.get());
+ if (!status_conversion.IsOk()) {
+ allocator_->DeleteReferencedData(&message);
+ allocator_->Delete(status_or_map_value->release());
+ PROTOVM_RETURN(status_conversion);
}
- const uint8_t* ctrl_ = nullptr;
- const uint8_t* ctrl_end_ = nullptr;
- Slot* slot_ = nullptr;
- }; // Iterator
- explicit FlatHashMapV2(size_t initial_capacity = 0,
- int load_limit_pct = kDefaultLoadLimitPct)
- : load_limit_percent_(load_limit_pct) {
- if (initial_capacity > 0) {
- Reset(initial_capacity, true);
+ auto& index_to_node =
+ it->value->GetIf<Node::IndexedRepeatedField>()->index_to_node;
+ auto status_or_it = MapInsert(&index_to_node, index_to_node.Size(),
+ std::move(*status_or_map_value));
+ if (!status_or_it.IsOk()) {
+ allocator_->DeleteReferencedData(&message);
+ PROTOVM_RETURN(status_or_it,
+ "Insert repeated field (id = %u, index = %d)", field.id(),
+ static_cast<int>(index_to_node.Size()));
}
}
- // We are calling Clear() so that the destructors for the inserted entries are
- // called (unless they are trivial, in which case it will be a no-op).
- ~FlatHashMapV2() { Clear(); }
+ allocator_->DeleteReferencedData(node);
+ node->value = message;
- FlatHashMapV2(FlatHashMapV2&& other) noexcept
- : storage_(std::move(other.storage_)),
- capacity_(other.capacity_),
- size_(other.size_),
- growth_info_(other.growth_info_),
- load_limit_percent_(other.load_limit_percent_),
- ctrl_(other.ctrl_),
- slots_(other.slots_) {
- new (&other) FlatHashMapV2();
+ return StatusOr<void>::Ok();
+}
+
+StatusOr<OwnedPtr<Node>> RwProtoCursor::CreateNodeFromField(
+ protozero::Field field) {
+ if (field.type() == protozero::proto_utils::ProtoWireType::kLengthDelimited) {
+ auto status_or_bytes = allocator_->AllocateAndCopyBytes(field.as_bytes());
+ PROTOVM_RETURN_IF_NOT_OK(status_or_bytes);
+ auto status_or_node =
+ allocator_->CreateNode<Node::Bytes>(std::move(*status_or_bytes));
+ if (!status_or_node.IsOk()) {
+ allocator_->DeleteReferencedData(&status_or_bytes.value());
+ PROTOVM_RETURN(status_or_node);
+ }
+
+ return std::move(*status_or_node);
}
- FlatHashMapV2& operator=(FlatHashMapV2&& other) noexcept {
- this->~FlatHashMapV2();
- new (this) FlatHashMapV2(std::move(other));
- return *this;
+ auto status_or_node =
+ allocator_->CreateNode<Scalar>(field.type(), field.as_uint64());
+ if (!status_or_node.IsOk()) {
+ PROTOVM_RETURN(status_or_node);
+ }
+
+ return std::move(*status_or_node);
+}
+
+StatusOr<void> RwProtoCursor::ConvertToMappedRepeatedFieldIfNeeded(
+ Node* node,
+ uint32_t map_key_field_id) {
+ if (node->GetIf<Node::MappedRepeatedField>()) {
+ return StatusOr<void>::Ok();
+ }
+
+ if (node->GetIf<Node::Empty>()) {
+ node->value = Node::MappedRepeatedField{};
+ return StatusOr<void>::Ok();
+ }
+
+ // If the current node contains a message (either raw bytes or a decomposed
+ // Node::Message), convert it into a Node::MappedRepeatedField.
+ //
+ // The process is:
+ // 1. Extract the key (identified by 'map_key_field_id') from the message data
+ // within the current 'node'.
+ // 2. Allocate a new node. The original message content from the current node
+ // is moved into this new node.
+ // 3. Repurpose the current node, replacing it with an empty
+ // Node::MappedRepeatedField
+ // (intrusive tree that stores message fields ordered by key).
+ // 4. Insert the new node (containing Node::Message) into the repurposed
+ // current node (Node::MappedRepeatedField) using the key extracted in step 1.
+ if (node->GetIf<Node::Bytes>() || node->GetIf<Node::Message>()) {
+ auto status_or_key = ReadScalarField(*node, map_key_field_id);
+ PROTOVM_RETURN_IF_NOT_OK(status_or_key);
+
+ auto status_or_map_value = allocator_->CreateNode<Node::Empty>();
+ PROTOVM_RETURN_IF_NOT_OK(status_or_map_value);
+
+ auto map_value = std::move(*status_or_map_value);
+ map_value->value = std::move(node->value);
+ node->value = Node::MappedRepeatedField{};
+
+ auto status_or_it =
+ MapInsert(&node->GetIf<Node::MappedRepeatedField>()->key_to_node,
+ *status_or_key, std::move(map_value));
+ PROTOVM_RETURN(status_or_it);
}
- FlatHashMapV2(const FlatHashMapV2&) = delete;
- FlatHashMapV2& operator=(const FlatHashMapV2&) = delete;
+ // If the current node is a Node::IndexedRepeatedField (intrusive tree with
+ // message fields ordered by index), this block converts it into a
+ // Node::MappedRepeatedField (intrusive tree with message fields ordered by
+ // key).
+ //
+ // The process is:
+ // 1. Initialize an empty Node::MappedRepeatedField
+ // 2. For each field in the current node (Node::IndexedRepeatedField):
+ // 2.1. Extract the key (identified by 'map_key_field_id'). Note that the
+ // iterated fields must be messages.
+ // 2.2. Remove the field from the current node
+ // (Node::IndexedRepeatedField).
+ // 2.3. Insert the field into the Node::MappedRepeatedField using the key
+ // extracted in step 2.1.
+ // 3. Assign the Node::MappedRepeatedField to the current node, i.e. repurpose
+ // current node from Node::IndexedRepeatedField to
+ // Node::MappedRepeatedField)
+ if (auto* indexed = node->GetIf<Node::IndexedRepeatedField>()) {
+ Node::MappedRepeatedField mapped_repeated_field;
+
+ for (auto it = indexed->index_to_node.begin(); it;) {
+ auto& map_entry = *it;
+ auto& value_node = *it->value;
+
+ it = indexed->index_to_node.Remove(it);
- template <typename K = Key>
- PERFETTO_ALWAYS_INLINE Value* Find(const K& key) const {
- size_t key_hash = Hasher{}(key);
- uint8_t h2 = H2(key_hash);
- FindResult res = FindSlotIgnoringTombstones<false>(key, key_hash, h2);
- if (PERFETTO_UNLIKELY(res.needs_insert)) {
- return nullptr;
- }
- return &slots_[res.idx].value;
- }
+ auto status_or_key = ReadScalarField(value_node, map_key_field_id);
+ PROTOVM_RETURN_IF_NOT_OK(status_or_key);
- template <typename K = Key>
- bool Erase(const K& key) {
- size_t key_hash = Hasher{}(key);
- uint8_t h2 = H2(key_hash);
- FindResult res = FindSlotIgnoringTombstones<false>(key, key_hash, h2);
- if (PERFETTO_UNLIKELY(res.needs_insert)) {
- return false;
+ map_entry.key = *status_or_key;
+ mapped_repeated_field.key_to_node.Insert(map_entry);
}
- PERFETTO_DCHECK(size_ > 0);
- SetCtrl(res.idx, kTombstone);
- slots_[res.idx].key.~Key();
- slots_[res.idx].value.~Value();
- size_--;
- growth_info_.has_tombstones = 1;
- return true;
- }
- PERFETTO_ALWAYS_INLINE std::pair<Value*, bool> Insert(Key key, Value value) {
- size_t key_hash = Hasher{}(key);
- uint8_t h2 = H2(key_hash);
- FindResult res = FindSlotIgnoringTombstones<true>(key, key_hash, h2);
- if (PERFETTO_UNLIKELY(!res.needs_insert)) {
- return {&slots_[res.idx].value, false};
- }
- if (PERFETTO_UNLIKELY(growth_info_.growth_left == 0)) {
- GrowAndRehash();
- // After rehash, table has no tombstones. Find an empty slot directly
- // instead of recursing (which would prevent inlining).
- res.idx = FindFirstEmptyOrTombstone(key_hash);
- }
- PERFETTO_DCHECK(res.idx != kNotFound);
- size_t insert_idx = res.idx;
- bool is_freeslot = true;
- if (PERFETTO_UNLIKELY(growth_info_.has_tombstones)) {
- insert_idx = FindFirstEmptyOrTombstone(key_hash);
- is_freeslot = ctrl_[insert_idx] != kTombstone;
- }
- new (&slots_[insert_idx].key) Key(std::move(key));
- new (&slots_[insert_idx].value) Value(std::move(value));
- SetCtrl(insert_idx, h2);
- size_++;
- if (is_freeslot) {
- growth_info_.growth_left--;
- }
- return {&slots_[insert_idx].value, true};
+ node->value = mapped_repeated_field;
+
+ return StatusOr<void>::Ok();
}
- Value& operator[](Key key) {
- auto it_and_inserted = Insert(std::move(key), Value{});
- return *it_and_inserted.first;
+ PROTOVM_ABORT(
+ "Attempted to access field as MappedRepeatedField but node has type "
+ "%s",
+ node->GetTypeName());
+}
+
+StatusOr<void> RwProtoCursor::ConvertToIndexedRepeatedFieldIfNeeded(
+ Node* node) {
+ if (node->GetIf<Node::IndexedRepeatedField>()) {
+ return StatusOr<void>::Ok();
}
- void Clear() {
- // Avoid trivial heap operations on zero-capacity std::move()-d objects.
- if (PERFETTO_UNLIKELY(capacity_ == 0)) {
- return;
- }
- for (size_t i = 0; i < capacity_; ++i) {
- const uint8_t tag = ctrl_[i];
- if (tag == kFreeSlot || tag == kTombstone) {
- continue;
- }
- slots_[i].key.~Key();
- slots_[i].value.~Value();
- }
- Reset(capacity_, false);
+ if (node->GetIf<Node::MappedRepeatedField>()) {
+ PROTOVM_ABORT(
+ "Attempted \"convert to indexed repeated field\" operation but "
+ "node has type %s",
+ node->GetTypeName());
}
- Iterator GetIterator() { return Iterator(ctrl_, ctrl_ + capacity_, slots_); }
- Iterator GetIterator() const {
- return Iterator(ctrl_, ctrl_ + capacity_, slots_);
+ if (node->GetIf<Node::Empty>()) {
+ node->value = Node::IndexedRepeatedField{};
+ return StatusOr<void>::Ok();
}
- size_t size() const { return size_; }
- size_t capacity() const { return capacity_; }
+ auto status_or_map_value = allocator_->CreateNode<Node::Empty>();
+ PROTOVM_RETURN_IF_NOT_OK(status_or_map_value);
- private:
- // Result struct for FindOrPrepareInsert - avoids bit manipulation overhead
- struct FindResult {
- uint64_t idx : 63;
- uint64_t needs_insert : 1;
- };
+ auto map_value = std::move(*status_or_map_value);
+ map_value->value = std::move(node->value);
+ node->value = Node::IndexedRepeatedField{};
- // Tracks growth capacity and whether any deletions have occurred.
- // Using bitfields like absl's GrowthInfo to avoid manual bit manipulation.
- struct GrowthInfo {
- uint64_t growth_left : 63;
- uint64_t has_tombstones : 1;
- };
+ auto status_or_it =
+ MapInsert(&node->GetIf<Node::IndexedRepeatedField>()->index_to_node, 0,
+ std::move(map_value));
+ PROTOVM_RETURN(status_or_it);
+}
- // Not found sentinel (must fit in 63-bit FindResult.idx)
- static constexpr size_t kNotFound = std::numeric_limits<size_t>::max() >> 1;
+StatusOr<IntrusiveMap::Iterator> RwProtoCursor::FindOrCreateMessageField(
+ Node* node,
+ uint32_t field_id) {
+ auto status = ConvertToMessageIfNeeded(node);
+ PROTOVM_RETURN_IF_NOT_OK(status);
- // Abstraction over a group of control bytes that enables batch operations.
- // On x64, uses SSE to match 16 control bytes in parallel.
- // On other platforms, uses SWAR (SIMD Within A Register) for 8 bytes.
- //
- // Match() returns an iterator over slots whose control byte matches h2.
- // MatchEmpty() returns an iterator over empty slots (kFreeSlot).
- // MatchEmptyOrDeleted() returns an iterator over empty or deleted slots.
-#if PERFETTO_BUILDFLAG(PERFETTO_X64_CPU_OPT)
- struct Group {
- public:
- // Group size 16 for x64 SSE
- static constexpr size_t kSize = 16;
-
- // Iterates over set bits in a match mask. Each set bit indicates a slot
- // in the group that matched the search criteria. Call Next() to get the
- // index of each matching slot.
- struct Iterator {
- public:
- PERFETTO_ALWAYS_INLINE explicit Iterator(uint16_t mask) : mask_(mask) {}
- PERFETTO_ALWAYS_INLINE explicit operator bool() const { return mask_; }
-
- PERFETTO_ALWAYS_INLINE size_t Next() {
- auto idx = static_cast<size_t>(CountTrailZeros(mask_));
- mask_ &= static_cast<uint16_t>(mask_ - 1);
- return idx;
- }
+ auto* message = node->GetIf<Node::Message>();
+ auto it = message->field_id_to_node.Find(field_id);
+ if (it) {
+ return it;
+ }
- private:
- uint16_t mask_;
- };
+ auto status_or_map_value = allocator_->CreateNode<Node::Empty>();
+ PROTOVM_RETURN_IF_NOT_OK(status_or_map_value);
- PERFETTO_ALWAYS_INLINE explicit Group(const uint8_t* pos) {
- ctrl_ = _mm_loadu_si128(reinterpret_cast<const __m128i*>(pos));
- }
+ auto status_or_it = MapInsert(&message->field_id_to_node, field_id,
+ std::move(*status_or_map_value));
+ PROTOVM_RETURN(status_or_it);
+}
- PERFETTO_ALWAYS_INLINE Iterator Match(uint8_t h2) const {
- auto match = _mm_cmpeq_epi8(ctrl_, _mm_set1_epi8(static_cast<char>(h2)));
- return Iterator(static_cast<uint16_t>(_mm_movemask_epi8(match)));
- }
+StatusOr<IntrusiveMap::Iterator>
+RwProtoCursor::FindOrCreateIndexedRepeatedField(Node* node, uint32_t index) {
+ auto& index_to_node =
+ node->GetIf<Node::IndexedRepeatedField>()->index_to_node;
- PERFETTO_ALWAYS_INLINE Iterator MatchEmpty() const {
- return Iterator(static_cast<uint16_t>(
- _mm_movemask_epi8(_mm_sign_epi8(ctrl_, ctrl_))));
- }
+ auto it = index_to_node.Find(index);
+ if (it) {
+ return it;
+ }
- PERFETTO_ALWAYS_INLINE Iterator MatchEmptyOrDeleted() const {
- return Iterator(static_cast<uint16_t>(_mm_movemask_epi8(ctrl_)));
- }
+ bool requires_creation_and_is_not_simple_append =
+ index > index_to_node.Size();
+ if (requires_creation_and_is_not_simple_append) {
+ PROTOVM_ABORT(
+ "Attempted to insert repeated field at arbitrary position (only "
+ "append operation is supported)");
+ }
- private:
- __m128i ctrl_;
- };
-#else
- // SWAR fallback: processes 8 control bytes at a time using 64-bit arithmetic.
- struct Group {
- public:
- // Group size 8 for ARM and other platforms
- static constexpr size_t kSize = 8;
-
- // Iterates over set bits in a sparse 64-bit mask. Each set MSB indicates
- // a matching byte in the group. Call Next() to get the index of each
- // matching slot.
- struct Iterator {
- public:
- PERFETTO_ALWAYS_INLINE explicit Iterator(uint64_t mask) : mask_(mask) {}
- PERFETTO_ALWAYS_INLINE explicit operator bool() const { return mask_; }
- PERFETTO_ALWAYS_INLINE size_t Next() {
- // Count zeros and divide by 8 (shift 3)
- // 0x80 (Byte 0) -> CTZ 7 -> 7>>3 = 0
- // 0x8000 (Byte 1) -> CTZ 15 -> 15>>3 = 1
- size_t idx = static_cast<size_t>(CountTrailZeros(mask_) >> 3);
- mask_ &= mask_ - 1; // Clear lowest set bit
- return idx;
- }
+ auto status_or_map_value = allocator_->CreateNode<Node::Empty>();
+ PROTOVM_RETURN_IF_NOT_OK(status_or_map_value);
- private:
- uint64_t mask_;
- };
+ return MapInsert(&node->GetIf<Node::IndexedRepeatedField>()->index_to_node,
+ index, std::move(*status_or_map_value));
+}
- PERFETTO_ALWAYS_INLINE explicit Group(const uint8_t* pos) {
- memcpy(&ctrl_, pos, sizeof(ctrl_));
- }
+StatusOr<IntrusiveMap::Iterator> RwProtoCursor::FindOrCreateMappedRepeatedField(
+ Node* node,
+ uint64_t key) {
+ auto it = node->GetIf<Node::MappedRepeatedField>()->key_to_node.Find(key);
- PERFETTO_ALWAYS_INLINE Iterator Match(uint8_t h2) const {
- uint64_t x = ctrl_ ^ (kLsbs * h2);
- return Iterator((x - kLsbs) & ~x & kMsbs);
- }
+ if (it) {
+ return it;
+ }
- PERFETTO_ALWAYS_INLINE Iterator MatchEmpty() const {
- // 0x80 check (Empty)
- return Iterator((ctrl_ & ~(ctrl_ << 6)) & kMsbs);
- }
+ auto status_or_map_value = allocator_->CreateNode<Node::Empty>();
+ PROTOVM_RETURN_IF_NOT_OK(status_or_map_value);
- PERFETTO_ALWAYS_INLINE Iterator MatchEmptyOrDeleted() const {
- // 0x80 or 0xFE check (Empty or Deleted)
- return Iterator((ctrl_ & ~(ctrl_ << 7)) & kMsbs);
- }
+ return MapInsert(&node->GetIf<Node::MappedRepeatedField>()->key_to_node, key,
+ std::move(*status_or_map_value));
+}
- private:
- static constexpr uint64_t kLsbs = 0x0101010101010101ULL;
- static constexpr uint64_t kMsbs = 0x8080808080808080ULL;
+StatusOr<IntrusiveMap::Iterator> RwProtoCursor::MapInsert(
+ IntrusiveMap* map,
+ uint64_t key,
+ OwnedPtr<Node> map_value) {
+ auto status_or_map_node =
+ allocator_->CreateMapNode(key, std::move(map_value));
+ PROTOVM_RETURN_IF_NOT_OK(status_or_map_node, "Failed to allocate node");
- uint64_t ctrl_;
- };
-#endif
+ auto [it, inserted] = map->Insert(*status_or_map_node->get());
+ if (!inserted) {
+ allocator_->Delete(status_or_map_node->release());
+ PROTOVM_ABORT(
+ "Failed to insert intrusive map entry (key = %d). Duplicated key?",
+ static_cast<int>(key));
+ }
- // The number of cloned control bytes after the main control byte array.
- static constexpr size_t kNumClones = Group::kSize - 1;
+ status_or_map_node->release();
+ return it;
+}
- // Searches for a key in the table. This function IGNORES tombstones during
- // the search - it only stops at empty slots (kFreeSlot) or matching keys.
- //
- // Why ignore tombstones? In Swiss Tables, tombstones mark deleted entries but
- // must be skipped during lookup because the key we're searching for may have
- // been inserted AFTER the tombstone was created (i.e., the key's probe
- // sequence may have skipped over that tombstone). Only an empty slot
- // definitively proves the key doesn't exist.
- //
- // Returns FindResult with idx and whether the key needs to be inserted:
- // - If key is found: {idx, false} where idx is the slot containing the key.
- // - If key not found and ForInsert=true: {empty_idx, true} where empty_idx
- // is the index of the first EMPTY slot encountered.
- // - If key not found and ForInsert=false: {kNotFound, true}.
- //
- // IMPORTANT for insertion (ForInsert=true): The returned empty_idx is NOT
- // necessarily the best slot to insert into! There may be an earlier tombstone
- // in the probe sequence that should be reused to avoid wasting slots. When
- // has_tombstones is set, the caller must make a SECOND pass by calling
- // FindFirstEmptyOrTombstone() to find the actual insertion slot.
- template <bool ForInsert, typename K = Key>
- PERFETTO_ALWAYS_INLINE FindResult
- FindSlotIgnoringTombstones(const K& key, size_t key_hash, uint8_t h2) const {
- static_assert(
- flat_hash_map_v2_internal::IsLookupKeyAllowed<K, Key, Hasher>(),
- "Heterogeneous lookup requires Hasher to define is_transparent and "
- "support hashing the lookup key type. For same-type lookup, Key and K "
- "must match exactly.");
+StatusOr<uint64_t> RwProtoCursor::ReadScalarField(const Node& node,
+ uint32_t field_id) {
+ if (auto* bytes = node.GetIf<Node::Bytes>()) {
+ protozero::ProtoDecoder decoder(protozero::ConstBytes{
+ static_cast<const uint8_t*>(bytes->data.get()), bytes->size});
- if (PERFETTO_UNLIKELY(ctrl_ == nullptr)) {
- return {kNotFound, true};
+ auto field = decoder.ReadField();
+ while (field.valid() && field.id() != field_id) {
+ field = decoder.ReadField();
}
- const size_t cap_mask = capacity_ - 1;
- size_t offset = H1(key_hash) & cap_mask;
- size_t probe_size = 0;
- const uint8_t* ctrl = ctrl_;
-
- // Prefetch control bytes (like Absl's prefetch_heap_block).
- // Use locality hint 3 (high temporal locality) for better L1 cache usage.
- __builtin_prefetch(ctrl_ + offset, 0, 3);
-
- while (true) {
- // Prefetch slots at current probe offset (like Absl).
- __builtin_prefetch(slots_ + offset, 0, 3);
-
- Group group(ctrl + offset);
-
- // Match H2 tags in this group.
- for (auto it = group.Match(h2); PERFETTO_LIKELY(it);) {
- // Must mask because offset + it.Next() can exceed capacity when
- // group straddles the table boundary (using cloned control bytes).
- size_t idx = (offset + it.Next()) & cap_mask;
- if (PERFETTO_LIKELY(Eq{}(slots_[idx].key, key))) {
- return {idx, false}; // Found
- }
- }
+ if (!field.valid()) {
+ PROTOVM_ABORT(
+ "Attempted to read scalar field (id=%u) but it is not present",
+ field_id);
+ }
- // Check for empty slot (NOT tombstones). If we find an empty slot, the
- // key cannot exist in the table (empty slots terminate probe chains).
- if (auto it = group.MatchEmpty(); PERFETTO_LIKELY(it)) {
- if constexpr (ForInsert) {
- size_t empty_idx = (offset + it.Next()) & cap_mask;
- return {empty_idx, true}; // Not found - empty slot for insertion
- } else {
- return {kNotFound, true}; // Not found - no need to compute slot
- }
- }
+ if (field.type() ==
+ protozero::proto_utils::ProtoWireType::kLengthDelimited) {
+ PROTOVM_ABORT("Attempted to length-delimited field (id=%u) as scalar",
+ field_id);
+ }
- // Triangular probing (like Absl): 0, 16, 48, 96, ...
- probe_size += Group::kSize;
- offset = (offset + probe_size) & cap_mask;
+ return field.as_uint64();
+ }
- // Should never happen with load limit.
- PERFETTO_DCHECK(probe_size <= capacity_);
+ if (auto* message = node.GetIf<Node::Message>()) {
+ auto it = message->field_id_to_node.Find(field_id);
+ if (!it) {
+ PROTOVM_ABORT(
+ "Attempted to read scalar field (id=%u) but it is not present",
+ field_id);
}
- }
- // Find first empty OR tombstone slot for insertion.
- // Called when has_tombstones is set to find an earlier tombstone that can
- // be reused instead of taking a new empty slot.
- size_t FindFirstEmptyOrTombstone(size_t key_hash) const {
- const size_t cap_mask = capacity_ - 1;
- size_t offset = H1(key_hash) & cap_mask;
- size_t probe_size = 0;
- while (true) {
- Group group(ctrl_ + offset);
- if (auto it = group.MatchEmptyOrDeleted(); PERFETTO_LIKELY(it)) {
- return (offset + it.Next()) & cap_mask;
- }
- probe_size += Group::kSize;
- offset = (offset + probe_size) & cap_mask;
+ auto* scalar = it->value->GetIf<Scalar>();
+ if (!scalar) {
+ PROTOVM_ABORT(
+ "Attempted to read scalar field (id=%u) from node with type %s",
+ field_id, it->value->GetTypeName());
}
+
+ return scalar->value;
}
- PERFETTO_NO_INLINE void GrowAndRehash() {
- // Grow factor must be a power of 2 because probing uses bitwise AND
- // for modulo arithmetic (capacity must remain a power of 2).
- static constexpr size_t kGrowFactor = 2;
- static_assert((kGrowFactor & (kGrowFactor - 1)) == 0,
- "kGrowFactor must be a power of 2");
+ PROTOVM_ABORT(
+ "Attempted to read scalar field (id=%u) but parent node has type %s",
+ field_id, node.GetTypeName());
+}
- PERFETTO_DCHECK(size_ <= capacity_);
+StatusOr<void> RwProtoCursor::CheckIsValid() const {
+ if (!node_) {
+ PROTOVM_ABORT("Attempted to access invalid cursor");
+ }
+ return StatusOr<void>::Ok();
+}
- size_t old_capacity = capacity_;
- size_t old_size = size_;
- uint8_t* old_ctrl = ctrl_;
- Slot* old_slots = slots_;
- std::unique_ptr<uint8_t[]> old_storage(std::move(storage_));
+} // namespace protovm
+} // namespace perfetto
+// gen_amalgamated begin source: src/protovm/vm.cc
+// gen_amalgamated begin header: src/protovm/vm.h
+/*
+ * Copyright (C) 2025 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.
+ */
- // This must be a CHECK (i.e. not just a DCHECK) to prevent UAF attacks on
- // 32-bit archs that try to double the size of the table until wrapping.
- size_t new_capacity = old_capacity * kGrowFactor;
- PERFETTO_CHECK(new_capacity >= old_capacity);
- Reset(new_capacity, true);
+#ifndef SRC_PROTOVM_VM_H_
+#define SRC_PROTOVM_VM_H_
- size_t new_size = 0;
- for (size_t i = 0; i < old_capacity; ++i) {
- if (uint8_t t = old_ctrl[i]; t == kFreeSlot || t == kTombstone) {
- continue;
- }
- Insert(std::move(old_slots[i].key), std::move(old_slots[i].value));
- old_slots[i].key.~Key(); // Destroy the old objects.
- old_slots[i].value.~Value();
- new_size++;
- }
- PERFETTO_DCHECK(new_size == old_size);
- size_ = new_size;
- }
+#include <memory>
- // Doesn't call destructors. Use Clear() for that.
- PERFETTO_NO_INLINE void Reset(size_t n, bool reallocate) {
- // Must be a pow2.
- PERFETTO_CHECK((n & (n - 1)) == 0);
+// gen_amalgamated expanded: #include "perfetto/protozero/field.h"
- // Always ensure at least 128 capacity to avoid too frequent growths.
- capacity_ = std::max<size_t>(n, 128u);
- size_ = 0;
- growth_info_.growth_left =
- (capacity_ * static_cast<size_t>(load_limit_percent_)) / 100;
- growth_info_.has_tombstones = 0;
+// gen_amalgamated expanded: #include "src/protovm/error_handling.h"
+// gen_amalgamated expanded: #include "src/protovm/executor.h"
+// gen_amalgamated expanded: #include "src/protovm/parser.h"
- if (reallocate) {
- // See memory layout comment above |storage_|.
- size_t slots_offset =
- base::AlignUp(capacity_ + kNumClones, alignof(Slot));
- storage_.reset(new uint8_t[slots_offset + (capacity_ * sizeof(Slot))]);
- ctrl_ = storage_.get();
- slots_ = reinterpret_cast<Slot*>(storage_.get() + slots_offset);
- }
- if (ctrl_) {
- // Initialize all control bytes (including clones) to empty (kFreeSlot)
- memset(ctrl_, kFreeSlot, capacity_ + kNumClones);
- }
- }
+namespace perfetto {
+namespace protovm {
- // Swiss Table hash splitting (matching absl):
- // H1 = upper bits for bucket index
- // H2 = lower 7 bits for tag
- // This ensures H1 and H2 are independent, avoiding tag collisions within
- // buckets. The seed XOR prevents clustering when hash values have patterns
- // (e.g., sequential keys)
- static constexpr size_t H1(size_t hash) { return (hash >> 7); }
- static constexpr uint8_t H2(size_t hash) { return hash & 0x7F; }
+// A VM that executes programs defined by data sources at registration time.
+// Used by traced to apply patches (packets overwritten in the ring buffer) to
+// an incremental state packet, thus allowing efficient incremental tracing of
+// Layers/Windows/Views without requiring periodic invalidation and achieve
+// perfect interning.
+//
+// Overview of the VM's architecture and interactions:
+//
+//
+// ***********
+// * *
+// * Program *
+// * *
+// ***********
+// │
+// │
+// │
+// ┌───┴──┐ ┌────────┐
+// │ │ │ │
+// │Parser├────────────┤Executor│
+// │ │ │ │
+// └──────┘ └─┬────┬─┘
+// │ │
+// ┌─────┘ └─────┐
+// │ │
+// │ │
+// ┌───┴────┐ ┌───┴────┐
+// │ │ │ │
+// │RoCursor│ │RwProto │
+// │ │ │::Cursor│
+// └────┬───┘ │ │
+// │ └───┬────┘
+// │ │
+// │ │
+// │ │
+// ********* ***************
+// * * * *
+// * Patch * * Incremental *
+// * * * state *
+// ********* * *
+// ***************
+//
+// ┌─┐
+// │ │ VM's component
+// └─┘
+//
+// ***
+// * * Data
+// ***
+//
+//
+// Parser: Understands the instructions semantic and controls the program flow.
+// It delegates to the Executor operations like navigating through the
+// patch and incremental state data, reading values, and manipulating
+// fields.
+//
+//
+// Executor: Thin glue layer that mainly forwards data back and forth between
+// the Parser and cursors. Mainly useful for testing, as it can
+// be easily mocked and allows to test the Parser in isolation.
+//
+//
+// RoCursor: Provides read-only access to the incoming data (the patch) to be
+// applied. It allows to traverse the proto message structure of the
+// patch, iterating over fields and extracting field values.
+//
+//
+// RwProto::Cursor: Provides read-write access to the incremental state. It
+// allows traversing the proto message structure of the
+// incremental state, as well as deleting/inserting/merging
+// fields.
+class Vm {
+ public:
+ Vm(protozero::ConstBytes program,
+ size_t memory_limit_bytes,
+ protozero::ConstBytes initial_incremental_state = {nullptr, 0});
+ StatusOr<void> ApplyPatch(protozero::ConstBytes packet);
+ void SerializeIncrementalState(protozero::Message*) const;
+ std::string SerializeProgram() const;
+ std::unique_ptr<Vm> CloneReadOnly() const;
+ uint64_t GetMemoryUsageBytes() const;
- // Set control byte and update clone if needed
- PERFETTO_ALWAYS_INLINE void SetCtrl(size_t i, uint8_t h) {
- ctrl_[i] = h;
- // Update clone if this is one of the first kNumClones entries
- if (PERFETTO_UNLIKELY(i < kNumClones)) {
- ctrl_[capacity_ + i] = h;
+ private:
+ struct ReadWriteState {
+ ReadWriteState(std::string& program,
+ size_t memory_limit_bytes,
+ protozero::ConstBytes initial_incremental_state)
+ : executor{},
+ parser{protozero::ConstBytes{
+ reinterpret_cast<const uint8_t*>(program.data()),
+ program.size()},
+ &executor},
+ allocator{memory_limit_bytes},
+ incremental_state{&allocator} {
+ if (initial_incremental_state.data) {
+ incremental_state.GetRoot().SetBytes(initial_incremental_state);
+ }
}
- }
- // Owns the actual memory with the following layout:
- //
- // [Control bytes]
- // |capacity_| bytes for control bytes.
- // kNumClones (15 or 7) bytes for control byte clones (*).
- // No alignment required (accessed at arbitrary byte offsets).
- //
- // [Padding for Slot alignment]
- //
- // [Slots]
- // capacity_ * sizeof(Slot): contains key-value pairs.
- // Must be aligned to alignof(Slot).
- //
- // (*) Control byte clones: The first kNumClones control bytes are duplicated
- // at the end of the control array. This allows SIMD operations to read a full
- // group (16 or 8 bytes) starting from any position without bounds checking,
- // even near the end of the array.
- std::unique_ptr<uint8_t[]> storage_;
+ Executor executor;
+ Parser parser;
+ Allocator allocator;
+ RwProto incremental_state;
+ };
- size_t capacity_ = 0;
- size_t size_ = 0;
+ struct ReadOnlyState {
+ explicit ReadOnlyState(std::string incremental_state)
+ : serialized_incremental_state(std::move(incremental_state)) {}
- // Slots remaining + has_deleted flag
- GrowthInfo growth_info_{0, 0};
+ std::string serialized_incremental_state;
+ };
- // Load factor limit in % of |capacity_|.
- int load_limit_percent_ = kDefaultLoadLimitPct;
+ // Constructor used to produce read-only copies of the ProtoVm.
+ // Private to avoid unintended copies. It should be used only for
+ // CloneReadOnly().
+ Vm(const Vm&);
- // Cached pointers for fast access (like absl::flat_hash_map)
- // These are updated whenever storage is allocated/reallocated.
- uint8_t* ctrl_ = nullptr; // Points to control bytes
- Slot* slots_ = nullptr; // Points to slot array
-};
+ // Constructor used only for cloning
+ explicit Vm(std::string incremental_state);
-// Alias FlatHashMap to FlatHashMapV1 for backward compatibility.
-//
-// TODO(lalitm): Once FlatHashMapV2 is fully tested and verified, switch this
-// to FlatHashMapV2.
-template <typename Key,
- typename Value,
- typename Hasher = MurmurHash<Key>,
- typename Probe = QuadraticProbe,
- bool AppendOnly = false>
-using FlatHashMap = FlatHashMapV1<Key, Value, Hasher, Probe, AppendOnly>;
+ std::string SerializeIncrementalStateAsString() const;
-} // namespace perfetto::base
+ std::string owned_program_;
+ std::variant<ReadWriteState, ReadOnlyState> state_;
+};
-#endif // INCLUDE_PERFETTO_EXT_BASE_FLAT_HASH_MAP_H_
+} // namespace protovm
+} // namespace perfetto
+
+#endif // SRC_PROTOVM_VM_H_
/*
* Copyright (C) 2025 The Android Open Source Project
*
@@ -54718,280 +59529,81 @@ using FlatHashMap = FlatHashMapV1<Key, Value, Hasher, Probe, AppendOnly>;
* limitations under the License.
*/
-#ifndef SRC_PROTOVM_SLAB_ALLOCATOR_H_
-#define SRC_PROTOVM_SLAB_ALLOCATOR_H_
-
-#include <cstdlib>
-#include <new>
-
-// gen_amalgamated expanded: #include "perfetto/base/logging.h"
-// gen_amalgamated expanded: #include "perfetto/ext/base/flat_hash_map.h"
-// gen_amalgamated expanded: #include "perfetto/ext/base/intrusive_list.h"
-// gen_amalgamated expanded: #include "perfetto/ext/base/paged_memory.h"
+// gen_amalgamated expanded: #include "src/protovm/vm.h"
-// An efficient allocator for elements with fixed size and alignment
-// requirements.
-//
-// Design doc: go/perfetto-protovm-implementation
-//
-// Key features:
-//
-// - Slab allocation: Instead of requesting memory for each individual element,
-// this allocator pre-allocates large memory chunks (slabs). Each slab is
-// designed to hold multiple elements.
-//
-// - Element free list: A free list tracks available elements within each
-// individual slab, allowing for O(1) access time during allocation.
-//
-// - Slab intrusive lists: Slabs are managed within one of two intrusive lists.
-// The "non-full slabs" list and the "full slabs" list. This organization
-// allows "non-full" slabs (those with available space for new allocations) to
-// be accessed in O(1) time.
-//
-// - Block-to-Slab hash map: A hash map links 4KB-aligned memory blocks to their
-// corresponding slab. This enables O(1) mapping of an element back to its
-// slab during deallocation.
-//
-// Allocation process:
-// 1. If there is no free slab
-// 1.1 Allocate a new slab, add it to the “non-full slabs” list, populate the
-// block-to-slab map
-// 2. Pick any slab from the “non-full slabs” list
-// 3. Allocate the element
-// 4. If needed, move the slab to the “full slabs” list
-//
-// Deallocation process:
-// 1. Find slab from the block-to-slab map
-// 2. Free element
-// 3. If needed, move to the “non-full slabs” list
-// 4. If needed, deallocate the slab.
+// gen_amalgamated expanded: #include "perfetto/protozero/field.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/scattered_heap_buffer.h"
+// gen_amalgamated expanded: #include "src/protovm/error_handling.h"
+// gen_amalgamated expanded: #include "src/protovm/ro_cursor.h"
+// gen_amalgamated expanded: #include "src/protovm/rw_proto.h"
namespace perfetto {
namespace protovm {
-namespace internal {
-static constexpr size_t k4KiloBytes = static_cast<size_t>(4096);
-}
-
-template <size_t ElementSize, size_t ElementAlign, size_t Blocks4KB>
-class Slab {
- public:
- struct IntrusiveListTraits {
- static constexpr size_t node_offset() {
- return offsetof(Slab, intrusive_list_node_);
- }
- };
-
- Slab() : paged_memory_(base::PagedMemory::Allocate(ElementSize * kCapacity)) {
- PERFETTO_CHECK(paged_memory_.IsValid());
-
- // Expect allocated memory to be always 4KB-aligned
- PERFETTO_CHECK(reinterpret_cast<uintptr_t>(paged_memory_.Get()) %
- internal::k4KiloBytes ==
- 0);
-
- ConstructSlots();
- InitializeSlotsFreeList();
- }
-
- ~Slab() { DestroySlots(); }
-
- void* Allocate() {
- PERFETTO_DCHECK(next_free_slot_);
- auto* slot = next_free_slot_;
- next_free_slot_ = next_free_slot_->next;
- ++size_;
- return slot;
- }
-
- void Free(void* p) {
- auto* slot = static_cast<Slot*>(p);
- PERFETTO_DCHECK(slot >= slots() && slot < slots() + kCapacity);
- slot->next = next_free_slot_;
- next_free_slot_ = slot;
- --size_;
- }
-
- bool IsFull() const { return size_ == kCapacity; }
-
- bool IsEmpty() const { return size_ == 0; }
-
- const void* GetBeginAddress() const {
- return const_cast<Slab*>(this)->slots();
- }
-
- const void* GetEndAddress() const {
- return const_cast<Slab*>(this)->slots() + kCapacity;
- }
-
- private:
- static constexpr size_t kCapacity =
- Blocks4KB * (internal::k4KiloBytes / ElementSize);
-
- static_assert(kCapacity >= 128,
- "The configured number of 4KB blocks per slab seems too small, "
- "resulting in a low slab capacity. Slab allocation is "
- "expensive (involves syscalls), so a high elements-to-slab "
- "ratio is desirable to amortize the cost.");
-
- static_assert(ElementAlign <= internal::k4KiloBytes,
- "SlabAllocator currently supports alignment <= 4KB");
-
- union Slot {
- Slot* next;
- alignas(ElementAlign) unsigned char element[ElementSize];
- };
-
- void InitializeSlotsFreeList() {
- next_free_slot_ = &slots()[0];
-
- for (size_t i = 0; i + 1 < kCapacity; ++i) {
- auto& slot = slots()[i];
- auto& next_slot = slots()[i + 1];
- slot.next = &next_slot;
- }
-
- auto& last_slot = slots()[kCapacity - 1];
- last_slot.next = nullptr;
- }
-
- void ConstructSlots() {
- auto* slot = slots();
- for (size_t i = 0; i < kCapacity; ++i) {
- new (&slot[i]) Slot();
- }
- }
-
- void DestroySlots() {
- auto* slot = slots();
- for (size_t i = 0; i < kCapacity; ++i) {
- slot[i].~Slot();
- }
- }
-
- Slot* slots() {
- return std::launder(reinterpret_cast<Slot*>(paged_memory_.Get()));
- }
-
- Slot* next_free_slot_{nullptr};
- size_t size_{0};
- base::IntrusiveListNode intrusive_list_node_;
- base::PagedMemory paged_memory_;
-};
-
-template <size_t ElementSize, size_t ElementAlign, size_t Blocks4KBPerSlab = 16>
-class SlabAllocator {
- public:
- ~SlabAllocator() {
- DeleteSlabs(slabs_non_full_);
- DeleteSlabs(slabs_full_);
- }
-
- void* Allocate() {
- // Create new slab if needed
- if (slabs_non_full_.empty()) {
- auto* slab = new SlabType();
- slabs_non_full_.PushFront(*slab);
- ++slabs_non_full_size_;
- InsertHashMapEntries(*slab);
- }
-
- // Allocate using any non-full slab
- auto& slab = slabs_non_full_.front();
- auto* allocated = slab.Allocate();
- PERFETTO_CHECK(allocated);
+Vm::Vm(protozero::ConstBytes program,
+ size_t memory_limit_bytes,
+ protozero::ConstBytes initial_incremental_state)
+ : owned_program_(program.ToStdString()),
+ state_(std::in_place_type_t<ReadWriteState>{},
+ owned_program_,
+ memory_limit_bytes,
+ initial_incremental_state) {}
- // Move to "full slabs" list if needed
- if (slab.IsFull()) {
- slabs_non_full_.Erase(slab);
- --slabs_non_full_size_;
- slabs_full_.PushFront(slab);
- }
+Vm::Vm(const Vm& other)
+ : owned_program_(other.SerializeProgram()),
+ state_(std::in_place_type_t<ReadOnlyState>{},
+ other.SerializeIncrementalStateAsString()) {}
- return allocated;
+StatusOr<void> Vm::ApplyPatch(protozero::ConstBytes packet) {
+ ReadWriteState* rw_state = std::get_if<ReadWriteState>(&state_);
+ if (!rw_state) {
+ return StatusOr<void>::Abort();
}
+ auto src = RoCursor(packet);
+ auto dst = rw_state->incremental_state.GetRoot();
+ return rw_state->parser.Run(src, dst);
+}
- void Free(void* p) {
- auto& slab = FindSlabInHashMap(p);
-
- // Move to "non-full slabs" list if needed
- if (slab.IsFull()) {
- slabs_full_.Erase(slab);
- slabs_non_full_.PushFront(slab);
- ++slabs_non_full_size_;
- }
-
- slab.Free(p);
-
- // Deallocate the slab if it becomes empty and it's not the sole non-full
- // slab.
- //
- // The "is not the sole non-full slab" condition avoids thrashing scenarios
- // where a slab is repeatedly allocated and deallocated. For example:
- // 1. Allocate element x -> a new slab is allocated.
- // 2. Free element x -> slab becomes empty and is deallocated.
- // 3. Allocate element y -> a new slab is allocated again.
- // 4. And so on...
- if (slab.IsEmpty() && slabs_non_full_size_ > 1) {
- EraseHashMapEntries(slab);
- slabs_non_full_.Erase(slab);
- --slabs_non_full_size_;
- delete &slab;
- }
+void Vm::SerializeIncrementalState(protozero::Message* proto) const {
+ if (const ReadOnlyState* state = std::get_if<ReadOnlyState>(&state_); state) {
+ proto->AppendRawProtoBytes(state->serialized_incremental_state.data(),
+ state->serialized_incremental_state.size());
+ return;
}
- private:
- using SlabType = Slab<ElementSize, ElementAlign, Blocks4KBPerSlab>;
- using SlabList =
- base::IntrusiveList<SlabType, typename SlabType::IntrusiveListTraits>;
+ const ReadWriteState* state = std::get_if<ReadWriteState>(&state_);
+ state->incremental_state.Serialize(proto);
+}
- void InsertHashMapEntries(SlabType& slab) {
- for (auto p = reinterpret_cast<uintptr_t>(slab.GetBeginAddress());
- p < reinterpret_cast<uintptr_t>(slab.GetEndAddress());
- p += internal::k4KiloBytes) {
- PERFETTO_DCHECK(p % internal::k4KiloBytes == 0);
- block_4KB_aligned_to_slab_.Insert(p, &slab);
- }
- }
+std::string Vm::SerializeIncrementalStateAsString() const {
+ protozero::HeapBuffered<protozero::Message> proto;
+ SerializeIncrementalState(proto.get());
+ return proto.SerializeAsString();
+}
- void EraseHashMapEntries(const SlabType& slab) {
- for (auto p = reinterpret_cast<uintptr_t>(slab.GetBeginAddress());
- p < reinterpret_cast<uintptr_t>(slab.GetEndAddress());
- p += internal::k4KiloBytes) {
- PERFETTO_DCHECK(p % internal::k4KiloBytes == 0);
- block_4KB_aligned_to_slab_.Erase(p);
- }
- }
+std::string Vm::SerializeProgram() const {
+ return owned_program_;
+}
- SlabType& FindSlabInHashMap(const void* ptr) {
- auto ptr_4KB_aligned = reinterpret_cast<uintptr_t>(ptr) &
- ~(static_cast<uintptr_t>(internal::k4KiloBytes) - 1);
- SlabType** slab = block_4KB_aligned_to_slab_.Find(ptr_4KB_aligned);
- PERFETTO_CHECK(slab);
- PERFETTO_CHECK(*slab);
- return **slab;
- }
+std::unique_ptr<Vm> Vm::CloneReadOnly() const {
+ return std::unique_ptr<Vm>(new Vm(*this));
+}
- void DeleteSlabs(SlabList& slabs) {
- while (!slabs.empty()) {
- auto& slab = slabs.front();
- slabs.PopFront();
- delete &slab;
- }
+uint64_t Vm::GetMemoryUsageBytes() const {
+ if (const ReadOnlyState* state = std::get_if<ReadOnlyState>(&state_); state) {
+ return owned_program_.size() + state->serialized_incremental_state.size();
}
- base::FlatHashMap<uintptr_t, SlabType*> block_4KB_aligned_to_slab_;
- SlabList slabs_full_;
- SlabList slabs_non_full_;
- size_t slabs_non_full_size_{0};
-};
+ const ReadWriteState* state = std::get_if<ReadWriteState>(&state_);
+ return owned_program_.size() + state->allocator.GetMemoryUsageBytes();
+}
} // namespace protovm
} // namespace perfetto
-
-#endif // SRC_PROTOVM_SLAB_ALLOCATOR_H_
+// gen_amalgamated begin source: src/protozero/filtering/filter_bytecode_parser.cc
+// gen_amalgamated begin header: src/protozero/filtering/filter_bytecode_parser.h
/*
- * Copyright (C) 2025 The Android Open Source Project
+ * Copyright (C) 2021 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.
@@ -55006,85 +59618,166 @@ class SlabAllocator {
* limitations under the License.
*/
-#ifndef SRC_PROTOVM_ALLOCATOR_H_
-#define SRC_PROTOVM_ALLOCATOR_H_
-
-#include <algorithm>
-#include <cstdlib>
+#ifndef SRC_PROTOZERO_FILTERING_FILTER_BYTECODE_PARSER_H_
+#define SRC_PROTOZERO_FILTERING_FILTER_BYTECODE_PARSER_H_
-// gen_amalgamated expanded: #include "perfetto/protozero/field.h"
+#include <stddef.h>
+#include <stdint.h>
-// gen_amalgamated expanded: #include "src/protovm/error_handling.h"
-// gen_amalgamated expanded: #include "src/protovm/node.h"
-// gen_amalgamated expanded: #include "src/protovm/slab_allocator.h"
+#include <vector>
-namespace perfetto {
-namespace protovm {
+namespace protozero {
-// A centralized allocator to manage all the memory requests from RwProto. It
-// enforces a strict memory usage limit, thus allowing fine-grained control of
-// the overall proto VM's memory footprint.
-class Allocator {
+// Loads the proto-encoded bytecode in memory and allows fast lookups for tuples
+// (msg_index, field_id) to tell if a given field should be allowed or not and,
+// in the case of nested fields, what is the next message index to recurse into.
+// This class does two things:
+// 1. Expands the array of varint from the proto into a vector<uint32_t>. This
+// is to avoid performing varint decoding on every lookup, at the cost of
+// some extra memory (2KB-4KB). Note that the expanded vector is not just a
+// 1:1 copy of the proto one (more below). This is to avoid O(Fields) linear
+// lookup complexity.
+// 2. Creates an index of offsets to remember the start word for each message.
+// This is so we can jump to O(1) to the N-th message when recursing into a
+// nested fields, without having to scan and find the (N-1)-th END_OF_MESSAGE
+// marker.
+// Overall lookups are O(1) for field ids < 128 (kDirectlyIndexLimit) and O(N),
+// with N being the number of allowed field ranges for other fields.
+// See comments around |word_| below for the structure of the word vector.
+class FilterBytecodeParser {
public:
- static constexpr size_t kNodeSize = std::max(sizeof(Node), sizeof(MapNode));
- static constexpr size_t kNodeAlign =
- std::max(alignof(Node), alignof(MapNode));
+ static constexpr uint32_t kSimpleField = 0x7fffffff;
+ static constexpr uint32_t kFilterStringField = 0x7ffffffe;
+ // FilterStringFieldWithType uses a range: 0x7fff0000 to 0x7ffffffd.
+ // The semantic type is encoded in the lower 16 bits.
+ static constexpr uint32_t kFilterStringFieldWithType = 0x7fff0000;
+ static constexpr uint32_t kFilterStringFieldWithTypeMask = 0x7fff0000;
+ static constexpr uint32_t kSemanticTypeMask = 0xffff;
- explicit Allocator(size_t memory_limit_bytes);
+ // Result of a Query() operation
+ struct QueryResult {
+ bool allowed; // Whether the field is allowed at all or no.
- template <class T, class... Args>
- StatusOr<OwnedPtr<Node>> CreateNode(Args&&... args) {
- auto p = Allocate();
- PROTOVM_RETURN_IF_NOT_OK(p);
+ // If |allowed|==true && nested_msg_field() == true, this tells the message
+ // index of the nested field that should be used when recursing in the
+ // parser.
+ uint32_t nested_msg_index;
- // 1. Construct node's inner value T passing args (struct aggregate
- // initialization)
- // 2. Construct node passing T (struct aggregate initialization)
- new (*p) Node{T{std::forward<Args>(args)...}};
+ // The semantic type of the field (only meaningful when
+ // filter_string_field() returns true). A value of 0 means unspecified.
+ uint32_t semantic_type;
- return OwnedPtr<Node>(static_cast<Node*>(*p));
- }
+ // If |allowed|==true, specifies if the field is of a simple type (varint,
+ // fixed32/64, string or byte).
+ bool simple_field() const { return nested_msg_index == kSimpleField; }
- StatusOr<OwnedPtr<MapNode>> CreateMapNode(uint64_t key, OwnedPtr<Node> value);
+ // If |allowed|==true, specifies if this field is a string field that needs
+ // to be filtered.
+ bool filter_string_field() const {
+ // Range: [kFilterStringFieldWithType, kFilterStringField] i.e.
+ // [0x7fff0000, 0x7ffffffe]. This excludes kSimpleField (0x7fffffff).
+ return nested_msg_index >= kFilterStringFieldWithType &&
+ nested_msg_index <= kFilterStringField;
+ }
- StatusOr<Node::Bytes> AllocateAndCopyBytes(protozero::ConstBytes data);
+ // If |allowed|==true, specifies if the field is a nested field that needs
+ // recursion. The caller is expected to use |nested_msg_index| for the next
+ // Query() calls.
+ bool nested_msg_field() const {
+ static_assert(kFilterStringFieldWithType < kFilterStringField,
+ "kFilterStringFieldWithType < kFilterStringField");
+ static_assert(kFilterStringField < kSimpleField,
+ "kFilterStringField < kSimpleField");
+ return nested_msg_index < kFilterStringFieldWithType;
+ }
+ };
- // Deeply delete a node and all the referenced data. E.g. if the node holds a
- // Node::Message, recursively delete the message fields and finally delete the
- // node.
- void Delete(Node* node);
- void Delete(MapNode* node);
+ // Loads a filter. The filter data consists of a sequence of varints which
+ // contains the filter opcodes and a final checksum.
+ // If a filter is already loaded, it is replaced.
+ //
+ // Optionally accepts an overlay (pass nullptr/0 if not needed). The overlay
+ // can add new fields or upgrade existing fields (e.g., to FilterString).
+ // The overlay uses the same opcode format as the base bytecode, but with an
+ // explicit message index prefix:
+ // [msg_index, (field_id << 3) | opcode, argument] ... [checksum]
+ // Entry sizes depend on the opcode (same as base bytecode).
+ // Entries must be sorted by (msg_index, field_id). The base bytecode and
+ // overlay are merged during loading, maintaining sorted field order.
+ // See /rfcs/0011-subset-string-filter-rules.md for design details.
+ bool Load(const void* filter_data,
+ size_t len,
+ const void* overlay_data = nullptr,
+ size_t overlay_len = 0);
- // Deeply delete a node's referenced data, but do not delete the node itself.
- // E.g. if the node holds a Node::Message, recursively delete the message
- // fields.
- void DeleteReferencedData(Node* node);
+ // Checks wheter a given field is allowed or not.
+ // msg_index = 0 is the index of the root message, where all queries should
+ // start from (typically perfetto.protos.Trace).
+ QueryResult Query(uint32_t msg_index, uint32_t field_id) const;
- // Recursively delete a message's fields, but do not delete the message
- // itself.
- void DeleteReferencedData(Node::Message* message);
+ void Reset();
+ void set_suppress_logs_for_fuzzer(bool x) { suppress_logs_for_fuzzer_ = x; }
- // Delete the blob referenced by the Bytes struct, but do not delete the Bytes
- // struct itself.
- void DeleteReferencedData(Node::Bytes* bytes);
+ private:
+ static constexpr uint32_t kDirectlyIndexLimit = 128;
+ static constexpr uint32_t kAllowed = 1u << 31u;
- size_t GetMemoryUsageBytes() const { return used_memory_bytes_; }
+ bool LoadInternal(const uint8_t* filter_data,
+ size_t len,
+ const uint8_t* overlay_data,
+ size_t overlay_len);
+
+ // The state of all fields for all messages is stored in one contiguous array.
+ // This is to avoid memory fragmentation and allocator overhead.
+ // We expect a high number of messages (hundreds), but each message is small.
+ // For each message we store two sets of uint32:
+ // 1. A set of "directly indexed" fields, for field ids < 128.
+ // 2. The remainder is a set of ranges.
+ // So each message descriptor consists of a sequence of words as follows:
+ //
+ // [0] -> how many directly indexed fields are stored next (up to 128)
+ //
+ // [1..N] -> One word per field id (See "field state" below).
+ //
+ // [N + 1] -> Start of field id range 1
+ // [N + 2] -> End of field id range 1 (exclusive, STL-style).
+ // [N + 3] -> Field state for fields in range 1 (below)
+ //
+ // [N + 4] -> Start of field id range 2
+ // [N + 5] -> End of field id range 2 (exclusive, STL-style).
+ // [N + 6] -> Field state for fields in range 2 (below)
+
+ // The "field state" word is as follows:
+ // Bit 31: 1 if the field is allowed, 0 if disallowed.
+ // Only directly indexed fields can be 0 (it doesn't make sense to add
+ // a range and then say "btw it's NOT allowed".. don't add it then.
+ // 0 is only used for filling gaps in the directly indexed bucket.
+ // Bits [30..0] (only when MSB == allowed):
+ // 0x7fffffff: The field is "simple" (varint, fixed32/64, string, bytes) and
+ // can be directly passed through in output. No recursion is needed.
+ // 0x7ffffffe: The field is string field which needs to be filtered.
+ // 0x7fff0000-0x7ffffffd: The field is a string field with a semantic type.
+ // The lower 16 bits encode the semantic type.
+ // [0, 0x7ffeffff]: The field is a nested submessage. The value is the index
+ // that must be passed as first argument to the next Query() calls.
+ // Note that the message index is purely a monotonic counter in the
+ std::vector<uint32_t> words_;
- private:
- void DeallocateBytes(OwnedPtr<void> p, size_t size);
- StatusOr<void*> Allocate();
+ // One entry for each message index stored in the filter plus a sentinel at
+ // the end. Maps each message index to the offset in |words_| where the
+ // Nth message start.
+ // message_offset_.size() - 2 == the max message id that can be parsed.
+ std::vector<uint32_t> message_offset_;
- size_t memory_limit_bytes_{0};
- size_t used_memory_bytes_{0};
- SlabAllocator<kNodeSize, kNodeAlign> slab_allocator_;
+ bool suppress_logs_for_fuzzer_ = false;
};
-} // namespace protovm
-} // namespace perfetto
+} // namespace protozero
-#endif // SRC_PROTOVM_ALLOCATOR_H_
+#endif // SRC_PROTOZERO_FILTERING_FILTER_BYTECODE_PARSER_H_
+// gen_amalgamated begin header: src/protozero/filtering/filter_bytecode_common.h
/*
- * Copyright (C) 2025 The Android Open Source Project
+ * Copyright (C) 2021 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.
@@ -55099,121 +59792,52 @@ class Allocator {
* limitations under the License.
*/
-// gen_amalgamated expanded: #include "src/protovm/allocator.h"
-
-namespace perfetto {
-namespace protovm {
-
-Allocator::Allocator(size_t memory_limit_bytes)
- : memory_limit_bytes_{memory_limit_bytes}, used_memory_bytes_{0} {}
-
-StatusOr<OwnedPtr<MapNode>> Allocator::CreateMapNode(uint64_t key,
- OwnedPtr<Node> value) {
- PERFETTO_DCHECK(value);
- auto p = Allocate();
- if (!p.IsOk()) {
- Delete(value.release());
- PROTOVM_RETURN(p);
- }
- new (*p) MapNode{key, std::move(value)};
- return OwnedPtr<MapNode>(static_cast<MapNode*>(*p));
-}
-
-StatusOr<Node::Bytes> Allocator::AllocateAndCopyBytes(
- protozero::ConstBytes data) {
- if (used_memory_bytes_ + data.size > memory_limit_bytes_) {
- PROTOVM_ABORT(
- "Failed to allocate %zu bytes. Memory limit: %zu bytes. Used: %zu "
- "bytes.)",
- data.size, memory_limit_bytes_, used_memory_bytes_);
- }
+#ifndef SRC_PROTOZERO_FILTERING_FILTER_BYTECODE_COMMON_H_
+#define SRC_PROTOZERO_FILTERING_FILTER_BYTECODE_COMMON_H_
- if (data.size == 0) {
- return Node::Bytes{nullptr, 0};
- }
+#include <stdint.h>
- auto copy = OwnedPtr<void>{malloc(data.size)};
- if (!copy) {
- PROTOVM_ABORT("Failed to malloc %zu bytes", data.size);
- }
- used_memory_bytes_ += data.size;
- memcpy(copy.get(), data.data, data.size);
+namespace protozero {
- return Node::Bytes{std::move(copy), data.size};
-}
+enum FilterOpcode : uint32_t {
+ // The immediate value is 0 in this case.
+ kFilterOpcode_EndOfMessage = 0,
-void Allocator::Delete(Node* node) {
- DeleteReferencedData(node);
- node->~Node();
- slab_allocator_.Free(node);
- used_memory_bytes_ -= kNodeSize;
-}
+ // The immediate value is the id of the allowed field.
+ kFilterOpcode_SimpleField = 1,
-void Allocator::Delete(MapNode* node) {
- Delete(node->value.release());
- node->~MapNode();
- slab_allocator_.Free(node);
- used_memory_bytes_ -= kNodeSize;
-}
+ // The immediate value is the start of the range. The next word (without
+ // any shifting) is the length of the range.
+ kFilterOpcode_SimpleFieldRange = 2,
-void Allocator::DeleteReferencedData(Node* node) {
- if (auto* message = node->GetIf<Node::Message>()) {
- DeleteReferencedData(message);
- } else if (auto* indexed_fields = node->GetIf<Node::IndexedRepeatedField>()) {
- for (auto it = indexed_fields->index_to_node.begin(); it;) {
- auto& map_node = *it;
- it = indexed_fields->index_to_node.Remove(it);
- Delete(&map_node);
- }
- } else if (auto* mapped_fields = node->GetIf<Node::MappedRepeatedField>()) {
- for (auto it = mapped_fields->key_to_node.begin(); it;) {
- auto& map_node = *it;
- it = mapped_fields->key_to_node.Remove(it);
- Delete(&map_node);
- }
- } else if (auto* bytes = node->GetIf<Node::Bytes>()) {
- DeleteReferencedData(bytes);
- }
-}
+ // The immediate value is the id of the allowed field. The next word
+ // (without any shifting) is the index of the filter that should be used to
+ // recurse into the nested message.
+ kFilterOpcode_NestedField = 3,
-void Allocator::DeleteReferencedData(Node::Message* message) {
- for (auto it = message->field_id_to_node.begin(); it;) {
- auto& map_node = *it;
- it = message->field_id_to_node.Remove(it);
- Delete(&map_node);
- }
-}
+ // The immediate value is the id of the allowed field. The behaviour of this
+ // opcode is the same as kFilterOpcode_SimpleField, with the further semantic
+ // that the field is a string and needs to be processed using the string
+ // filtering rules.
+ kFilterOpcode_FilterString = 4,
-void Allocator::DeleteReferencedData(Node::Bytes* bytes) {
- DeallocateBytes(std::move(bytes->data), bytes->size);
-}
+ // The immediate value is the id of the allowed field. The next word (without
+ // any shifting) is the semantic type of the string field. The behaviour is
+ // similar to kFilterOpcode_FilterString, but carries semantic type info so
+ // that the string filter can apply type-specific rules.
+ kFilterOpcode_FilterStringWithType = 5,
+};
-void Allocator::DeallocateBytes(OwnedPtr<void> p, size_t size) {
- free(p.release());
- used_memory_bytes_ -= size;
-}
+// Constants for extracting opcode and field_id from bytecode words.
+// Bytecode words are encoded as: (field_id << kOpcodeShift) | opcode
+constexpr uint32_t kOpcodeMask = 0x7u;
+constexpr uint32_t kOpcodeShift = 3;
-StatusOr<void*> Allocator::Allocate() {
- if (used_memory_bytes_ + kNodeSize > memory_limit_bytes_) {
- PROTOVM_ABORT(
- "Failed to allocate element (%zu bytes). Memory limit: %zu [bytes]. "
- "Used: %zu "
- "[bytes].)",
- kNodeSize, memory_limit_bytes_, used_memory_bytes_);
- }
- auto* p = slab_allocator_.Allocate();
- if (!p) {
- PROTOVM_ABORT("Failed to allocate node");
- }
- used_memory_bytes_ += kNodeSize;
- return p;
-}
+} // namespace protozero
-} // namespace protovm
-} // namespace perfetto
-// gen_amalgamated begin source: src/protovm/error_handling.cc
+#endif // SRC_PROTOZERO_FILTERING_FILTER_BYTECODE_COMMON_H_
/*
- * Copyright (C) 2025 The Android Open Source Project
+ * Copyright (C) 2021 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.
@@ -55228,280 +59852,464 @@ StatusOr<void*> Allocator::Allocate() {
* limitations under the License.
*/
-// gen_amalgamated expanded: #include "src/protovm/error_handling.h"
-
-namespace perfetto {
-namespace protovm {
+// gen_amalgamated expanded: #include "src/protozero/filtering/filter_bytecode_parser.h"
-void LogStacktraceMessage(Stacktrace& stacktrace,
- const char* file_name,
- int file_line,
- const char* fmt,
- ...) {
- const char* const fmt_file_info = "%s:%d ";
- auto size_file_info =
- std::snprintf(nullptr, 0, fmt_file_info, file_name, file_line);
+#include <algorithm>
+#include <cstddef>
+#include <cstdint>
+#include <limits>
+#include <vector>
- va_list args;
- va_start(args, fmt);
- auto size_message = std::vsnprintf(nullptr, 0, fmt, args);
- va_end(args);
+// gen_amalgamated expanded: #include "perfetto/base/endian.h"
+// gen_amalgamated expanded: #include "perfetto/base/logging.h"
+// gen_amalgamated expanded: #include "perfetto/ext/base/fnv_hash.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/proto_decoder.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/proto_utils.h"
+// gen_amalgamated expanded: #include "perfetto/public/compiler.h"
+// gen_amalgamated expanded: #include "src/protozero/filtering/filter_bytecode_common.h"
- auto s = std::string(
- static_cast<std::size_t>(size_file_info + size_message + 1), '.');
+namespace protozero {
- std::snprintf(s.data(), static_cast<size_t>(size_file_info) + 1,
- fmt_file_info, file_name, file_line);
+namespace {
- va_start(args, fmt);
- std::vsnprintf(s.data() + size_file_info,
- static_cast<size_t>(size_message) + 1, fmt, args);
- va_end(args);
+// Parses varint-encoded bytecode and verifies checksum.
+// Returns true on success, with the checksum removed from |words|.
+bool ParseAndVerifyChecksum(const uint8_t* data,
+ size_t len,
+ std::vector<uint32_t>* words,
+ bool suppress_logs) {
+ if (len == 0) {
+ return false;
+ }
+ words->reserve(len); // An overestimation, but avoids reallocations.
- s.pop_back(); // null-terminating char
+ // Parse varints while computing checksum in a single pass.
+ // The last word is the checksum itself and should not be hashed.
+ perfetto::base::FnvHasher hasher;
+ uint32_t actual_csum = 0;
- stacktrace.push_back(std::move(s));
+ using BytecodeDecoder =
+ PackedRepeatedFieldIterator<proto_utils::ProtoWireType::kVarInt,
+ uint32_t>;
+ bool has_checksum = false;
+ bool packed_parse_err = false;
+ for (BytecodeDecoder it(data, len, &packed_parse_err); it;) {
+ uint32_t word = *it++;
+ if (bool is_last_word = !it; is_last_word) {
+ actual_csum = word;
+ has_checksum = true;
+ break;
+ }
+ words->emplace_back(word);
+ hasher.Update(perfetto::base::HostToLE(word));
+ }
+ if (packed_parse_err || !has_checksum) {
+ words->clear();
+ return false;
+ }
+ auto expected_csum = static_cast<uint32_t>(hasher.digest());
+ if (expected_csum != actual_csum) {
+ if (!suppress_logs) {
+ PERFETTO_ELOG("Filter bytecode checksum failed. Expected: %x, actual: %x",
+ expected_csum, actual_csum);
+ }
+ words->clear();
+ return false;
+ }
+ return true;
}
-void LogStacktraceMessage(Stacktrace& stacktrace,
- const char* file_name,
- int file_line) {
- const char* const fmt = "%s:%d <no message>";
- auto size_message = std::snprintf(nullptr, 0, fmt, file_name, file_line);
- auto s = std::string(static_cast<size_t>(size_message) + 1, '.');
- std::snprintf(s.data(), static_cast<size_t>(size_message) + 1, fmt, file_name,
- file_line);
-
- s.pop_back(); // null-terminating char
+struct OverlayEntry {
+ uint32_t msg_index;
+ uint32_t field_id;
+ uint32_t message_id;
+};
- stacktrace.push_back(std::move(s));
+// Returns the message_id for an overlay entry based on opcode and argument.
+// Returns 0 if the opcode is invalid.
+uint32_t GetMessageIdForOverlay(uint32_t opcode, uint32_t argument) {
+ switch (opcode) {
+ case kFilterOpcode_SimpleField:
+ return FilterBytecodeParser::kSimpleField;
+ case kFilterOpcode_FilterString:
+ return FilterBytecodeParser::kFilterStringField;
+ case kFilterOpcode_FilterStringWithType:
+ // For FilterStringWithType, incorporate semantic type into message_id.
+ return FilterBytecodeParser::kFilterStringFieldWithType |
+ (argument & FilterBytecodeParser::kSemanticTypeMask);
+ default:
+ return 0; // Invalid opcode
+ }
}
-} // namespace protovm
-} // namespace perfetto
-// gen_amalgamated begin source: src/protovm/executor.cc
-// gen_amalgamated begin header: src/protovm/executor.h
-// gen_amalgamated begin header: src/protovm/ro_cursor.h
-/*
- * Copyright (C) 2025 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 SRC_PROTOVM_RO_CURSOR_H_
-#define SRC_PROTOVM_RO_CURSOR_H_
+} // namespace
-#include <cstdint>
-#include <variant>
+void FilterBytecodeParser::Reset() {
+ bool suppress = suppress_logs_for_fuzzer_;
+ *this = FilterBytecodeParser();
+ suppress_logs_for_fuzzer_ = suppress;
+}
-// gen_amalgamated expanded: #include "perfetto/protozero/field.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/proto_decoder.h"
+bool FilterBytecodeParser::Load(const void* filter_data,
+ size_t len,
+ const void* overlay_data,
+ size_t overlay_len) {
+ Reset();
+ bool res =
+ LoadInternal(static_cast<const uint8_t*>(filter_data), len,
+ static_cast<const uint8_t*>(overlay_data), overlay_len);
+ // If load fails, don't leave the parser in a half broken state.
+ if (!res)
+ Reset();
+ return res;
+}
-// gen_amalgamated expanded: #include "src/protovm/error_handling.h"
-// gen_amalgamated expanded: #include "src/protovm/scalar.h"
+bool FilterBytecodeParser::LoadInternal(const uint8_t* filter_data,
+ size_t len,
+ const uint8_t* overlay_data,
+ size_t overlay_len) {
+ // First unpack the varints into a plain uint32 vector, so it's easy to
+ // iterate through them and look ahead.
+ std::vector<uint32_t> words;
+ if (!ParseAndVerifyChecksum(filter_data, len, &words,
+ suppress_logs_for_fuzzer_))
+ return false;
-namespace perfetto {
-namespace protovm {
+ // Parse the overlay (if provided).
+ std::vector<OverlayEntry> overlay;
+ if (overlay_data && overlay_len > 0) {
+ std::vector<uint32_t> overlay_words;
+ if (!ParseAndVerifyChecksum(overlay_data, overlay_len, &overlay_words,
+ suppress_logs_for_fuzzer_)) {
+ return false;
+ }
-class RoCursor {
- public:
- class RepeatedFieldIterator {
- public:
- RepeatedFieldIterator();
- explicit RepeatedFieldIterator(protozero::ProtoDecoder decoder,
- uint32_t field_id);
- RepeatedFieldIterator& operator++();
- RoCursor operator*();
- explicit operator bool() const;
+ // Each entry is exactly 3 words: [msg_index, field_word, argument]
+ // where field_id = field_word >> 3. The argument is 0 when not needed.
+ if (overlay_words.size() % 3 != 0) {
+ PERFETTO_DLOG("overlay error: size %zu not multiple of 3",
+ overlay_words.size());
+ return false;
+ }
- private:
- protozero::Field Advance();
+ for (size_t i = 0; i < overlay_words.size(); i += 3) {
+ overlay.emplace_back();
- protozero::ProtoDecoder decoder_;
- uint32_t field_id_;
- protozero::Field field_;
- };
+ uint32_t opcode = overlay_words[i + 1] & kOpcodeMask;
+ uint32_t message_id =
+ GetMessageIdForOverlay(opcode, overlay_words[i + 2]);
+ if (message_id == 0) {
+ PERFETTO_DLOG("overlay error: invalid opcode %u at index %zu", opcode,
+ i + 1);
+ return false;
+ }
- RoCursor();
- explicit RoCursor(protozero::ConstBytes data);
- explicit RoCursor(protozero::Field data);
- StatusOr<void> EnterField(uint32_t field_id);
- StatusOr<void> EnterRepeatedFieldAt(uint32_t field_id, uint32_t index);
- StatusOr<RepeatedFieldIterator> IterateRepeatedField(uint32_t field_id) const;
- bool IsScalar() const;
- bool IsBytes() const;
- StatusOr<Scalar> GetScalar() const;
- StatusOr<protozero::ConstBytes> GetBytes() const;
+ OverlayEntry& entry = overlay.back();
+ entry.msg_index = overlay_words[i];
+ entry.field_id = overlay_words[i + 1] >> kOpcodeShift;
+ entry.message_id = message_id;
- private:
- StatusOr<protozero::ConstBytes> GetLengthDelimitedData() const;
+ if (overlay.size() == 1) {
+ continue;
+ }
+ // Validate that overlay entries are sorted by (msg_index, field_id).
+ const OverlayEntry& prev_entry = overlay[overlay.size() - 2];
+ if (entry.msg_index < prev_entry.msg_index ||
+ (entry.msg_index == prev_entry.msg_index &&
+ entry.field_id <= prev_entry.field_id)) {
+ PERFETTO_DLOG(
+ "overlay error: entries not sorted at index %zu (msg %u, "
+ "field %u) after (msg %u, field %u)",
+ i, entry.msg_index, entry.field_id, prev_entry.msg_index,
+ prev_entry.field_id);
+ return false;
+ }
+ }
+ }
- std::variant<protozero::ConstBytes, protozero::Field> data_;
-};
+ // Temporary storage for each message. Cleared on every END_OF_MESSAGE.
+ std::vector<uint32_t> direct_indexed_fields;
+ std::vector<uint32_t> ranges;
+ uint32_t max_msg_index = 0;
+ uint32_t current_msg_index = 0;
+ size_t overlay_idx = 0;
-} // namespace protovm
-} // namespace perfetto
+ auto add_directly_indexed_field = [&](uint32_t field_id, uint32_t msg_id) {
+ PERFETTO_DCHECK(field_id > 0 && field_id < kDirectlyIndexLimit);
+ direct_indexed_fields.resize(std::max(direct_indexed_fields.size(),
+ static_cast<size_t>(field_id) + 1));
+ direct_indexed_fields[field_id] = kAllowed | msg_id;
+ };
-#endif // SRC_PROTOVM_RO_CURSOR_H_
-// gen_amalgamated begin header: src/protovm/rw_proto.h
-// gen_amalgamated begin header: src/protovm/rw_proto_cursor.h
-/*
- * Copyright (C) 2025 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.
- */
+ auto add_range = [&](uint32_t id_start, uint32_t id_end, uint32_t msg_id) {
+ PERFETTO_DCHECK(id_end > id_start);
+ PERFETTO_DCHECK(id_start >= kDirectlyIndexLimit);
+ ranges.emplace_back(id_start);
+ ranges.emplace_back(id_end);
+ ranges.emplace_back(kAllowed | msg_id);
+ };
-#ifndef SRC_PROTOVM_RW_PROTO_CURSOR_H_
-#define SRC_PROTOVM_RW_PROTO_CURSOR_H_
+ // Merges overlay entries into the current message being built.
+ //
+ // This function processes overlay entries for the current message up to (and
+ // including) the given |field_id|. Since both base bytecode and overlay are
+ // sorted by (msg_index, field_id), we can use a two-pointer merge approach:
+ // - Entries with field_id < the given field_id are ADDed as new fields
+ // - An entry with field_id == the given field_id is an UPGRADE (returned)
+ // - Entries with field_id > the given field_id are left for later
+ //
+ // Pass std::numeric_limits<uint32_t>::max() as field_id to drain all
+ // remaining entries for the current message (called at EndOfMessage).
+ //
+ // Returns:
+ // - The msg_id to use if there's an exact match (upgrade case)
+ // - 0 if no match (use the base bytecode's msg_id)
+ // - std::numeric_limits<uint32_t>::max() on error
+ constexpr uint32_t kOverlayError = std::numeric_limits<uint32_t>::max();
+ auto process_overlay = [&](uint32_t field_id) -> uint32_t {
+ while (overlay_idx < overlay.size()) {
+ const OverlayEntry& entry = overlay[overlay_idx];
-// gen_amalgamated expanded: #include "perfetto/protozero/field.h"
+ // Stop if this entry is for a later message or a later field.
+ if (entry.msg_index > current_msg_index ||
+ (entry.msg_index == current_msg_index && entry.field_id > field_id)) {
+ break;
+ }
-// gen_amalgamated expanded: #include "src/protovm/allocator.h"
-// gen_amalgamated expanded: #include "src/protovm/error_handling.h"
-// gen_amalgamated expanded: #include "src/protovm/node.h"
+ // Message indexes are dense and we verified above that we are sorted
+ // so this must be for the current message.
+ PERFETTO_DCHECK(entry.msg_index == current_msg_index);
-namespace perfetto {
-namespace protovm {
+ // Exact match - this is an upgrade. Return the msg_id for the caller.
+ if (entry.field_id == field_id) {
+ ++overlay_idx;
+ return entry.message_id;
+ }
-class RwProtoCursor {
- public:
- enum MergeFlags : uint32_t {
- kNone = 0,
- kSkipSubmessages = 1 << 0,
- kDelIfSrcEmpty = 1 << 1,
+ // entry_field < field_id: This is a new field to ADD.
+ if (entry.field_id < kDirectlyIndexLimit) {
+ add_directly_indexed_field(entry.field_id, entry.message_id);
+ } else {
+ add_range(entry.field_id, entry.field_id + 1, entry.message_id);
+ }
+ ++overlay_idx;
+ }
+ // No match found.
+ return 0;
};
- class RepeatedFieldIterator {
- public:
- RepeatedFieldIterator();
- RepeatedFieldIterator(Allocator* allocator, IntrusiveMap::Iterator it);
- RepeatedFieldIterator& operator++();
- RwProtoCursor GetCursor();
- explicit operator bool() const;
+ bool is_eom = true;
+ for (size_t i = 0; i < words.size(); ++i) {
+ const uint32_t word = words[i];
+ const bool has_next_word = i < words.size() - 1;
+ const uint32_t opcode = word & kOpcodeMask;
+ const uint32_t field_id = word >> kOpcodeShift;
- private:
- Allocator* allocator_{nullptr};
- IntrusiveMap::Iterator it_;
- };
+ is_eom = opcode == kFilterOpcode_EndOfMessage;
+ if (field_id == 0 && opcode != kFilterOpcode_EndOfMessage) {
+ PERFETTO_DLOG("bytecode error @ word %zu, invalid field id (0)", i);
+ return false;
+ }
- RwProtoCursor();
- explicit RwProtoCursor(Node* node, Allocator* allocator);
+ if (opcode == kFilterOpcode_SimpleField ||
+ opcode == kFilterOpcode_NestedField ||
+ opcode == kFilterOpcode_FilterString ||
+ opcode == kFilterOpcode_FilterStringWithType) {
+ // Field words are organized as follow:
+ // MSB: 1 if allowed, 0 if not allowed.
+ // Remaining bits:
+ // Message index in the case of nested (non-simple) messages.
+ // 0x7fff0000-0x7ffffffe for string fields with semantic type.
+ // 0x7ffffffe in the case of string fields which need filtering.
+ // 0x7fffffff in the case of simple fields.
+ uint32_t msg_id;
+ if (opcode == kFilterOpcode_SimpleField) {
+ msg_id = kSimpleField;
+ } else if (opcode == kFilterOpcode_FilterString) {
+ msg_id = kFilterStringField;
+ } else if (opcode == kFilterOpcode_FilterStringWithType) {
+ // The next word in the bytecode contains the semantic type.
+ if (!has_next_word) {
+ PERFETTO_DLOG(
+ "bytecode error @ word %zu: unterminated filter string with type",
+ i);
+ return false;
+ }
+ uint32_t semantic_type = words[++i];
+ msg_id =
+ kFilterStringFieldWithType | (semantic_type & kSemanticTypeMask);
+ } else { // FILTER_OPCODE_NESTED_FIELD
+ // The next word in the bytecode contains the message index.
+ if (!has_next_word) {
+ PERFETTO_DLOG("bytecode error @ word %zu: unterminated nested field",
+ i);
+ return false;
+ }
+ msg_id = words[++i];
+ max_msg_index = std::max(max_msg_index, msg_id);
+ }
- bool operator==(const RwProtoCursor& other) const;
- bool operator!=(const RwProtoCursor& other) const;
+ // Process overlay: add any fields that come before this one, and check
+ // if this field should be upgraded.
+ uint32_t overlay_msg_id = process_overlay(field_id);
+ if (overlay_msg_id == kOverlayError) {
+ return false;
+ }
+ if (overlay_msg_id != 0) {
+ msg_id = overlay_msg_id;
+ }
- StatusOr<bool> IsRoot() const;
- StatusOr<bool> HasField(uint32_t field_id);
- StatusOr<void> EnterField(uint32_t field_id);
- StatusOr<void> EnterRepeatedFieldAt(uint32_t field_id, uint32_t index);
- StatusOr<RepeatedFieldIterator> IterateRepeatedField(uint32_t field_id);
+ if (field_id < kDirectlyIndexLimit) {
+ add_directly_indexed_field(field_id, msg_id);
+ } else {
+ // In the case of a large field id (rare) we waste an extra word and
+ // represent it as a range. Doesn't make sense to introduce extra
+ // complexity to deal with rare cases like this.
+ add_range(field_id, field_id + 1, msg_id);
+ }
+ } else if (opcode == kFilterOpcode_SimpleFieldRange) {
+ if (!has_next_word) {
+ PERFETTO_DLOG("bytecode error @ word %zu: unterminated range", i);
+ return false;
+ }
+ const uint32_t range_len = words[++i];
+ const uint32_t range_end = field_id + range_len; // STL-style, excl.
+ uint32_t id = field_id;
- // Enters a specific repeated field, treating it as a map of key-value pairs.
- //
- // The function operates on the principle that the repeated field (identified
- // by <field_id>) can be viewed as a collection of key-value pairs, where:
- // - Each message element within the repetition is a "value".
- // - A specific subfield within each message element (identified by
- // <map_key_field_id>) serves as the unique key for that element.
- //
- // The function performs a lookup using the provided <key> and, if a match
- // is found, moves the cursor into the corresponding repeated field.
- //
- // Example:
- //
- // // Message currently pointer by the cursor
- // message CurrentMessage {
- // repeated KeyValuePair entries = <field_id>;
- // }
- //
- // message KeyValuePair {
- // uint32 key = <map_key_field_id>;
- // string value_x = ...;
- // string value_y = ...;
- // }
- //
- // In this example <field_id> points to CurrentMessage.entries,
- // <map_key_field_id> points to KeyValuePair.key, and <key> = 10. So the
- // function attempts to find and enter the KeyValuePair message where
- // key == 10.
- StatusOr<void> EnterRepeatedFieldByKey(uint32_t field_id,
- uint32_t map_key_field_id,
- uint64_t key);
+ // Here's the subtle complexity: at the bytecode level, we don't know
+ // anything about the kDirectlyIndexLimit. It is legit to define a range
+ // that spans across the direct-indexing threshold (e.g. 126-132). In that
+ // case we want to add all the elements < the indexing to the O(1) bucket
+ // and add only the remaining range as a non-indexed range.
+ for (; id < range_end && id < kDirectlyIndexLimit; ++id)
+ add_directly_indexed_field(id, kAllowed | kSimpleField);
+ PERFETTO_DCHECK(id >= kDirectlyIndexLimit || id == range_end);
+ if (id < range_end)
+ add_range(id, range_end, kSimpleField);
+ } else if (opcode == kFilterOpcode_EndOfMessage) {
+ // Drain any remaining overlay entries for this message.
+ if (process_overlay(std::numeric_limits<uint32_t>::max()) ==
+ kOverlayError) {
+ return false;
+ }
- StatusOr<Scalar> GetScalar() const;
- StatusOr<void> SetBytes(protozero::ConstBytes data);
- StatusOr<void> SetScalar(Scalar scalar);
+ // Verify that the ranges are non-overlapping. Assumes that the ranges
+ // are sorted (they are, because the bytecode is sorted).
+ for (size_t r = 0; r + 3 < ranges.size(); r += 3) {
+ const uint32_t prev_range_end = ranges[r + 1];
+ const uint32_t curr_range_start = ranges[r + 3];
+ if (curr_range_start < prev_range_end) {
+ PERFETTO_DLOG(
+ "bytecode error @ message %u: overlapping ranges [%u, %u) "
+ "and [%u, ...)",
+ current_msg_index, ranges[r], prev_range_end, curr_range_start);
+ return false;
+ }
+ }
- // Perform a shallow (one level) merge of two messages.
- // The cursor must currently point to a message and 'data' must contain a
- // message. Merge fields from the 'data' message into the message pointed by
- // cursor. Existing fields in the cursor's message are overwritten by fields
- // from 'data'. Fields present in 'data' but not in the cursor's message are
- // added/created. If skip_submessages is set to true, any message node already
- // resolved in the dst are skipped, thus not overwritten by the parent merge.
- StatusOr<void> Merge(protozero::ConstBytes data, uint32_t flags);
+ // For each message append:
+ // 1. The "header" word telling how many directly indexed fields there
+ // are.
+ // 2. The words for the directly indexed fields (id < 128).
+ // 3. The rest of the fields, encoded as ranges.
+ // Also update the |message_offset_| index to remember the word offset for
+ // the current message.
+ message_offset_.emplace_back(static_cast<uint32_t>(words_.size()));
+ words_.emplace_back(static_cast<uint32_t>(direct_indexed_fields.size()));
+ words_.insert(words_.end(), direct_indexed_fields.begin(),
+ direct_indexed_fields.end());
+ words_.insert(words_.end(), ranges.begin(), ranges.end());
+ direct_indexed_fields.clear();
+ ranges.clear();
+ ++current_msg_index;
+ } else {
+ PERFETTO_DLOG("bytecode error @ word %zu: invalid opcode (%x)", i, word);
+ return false;
+ }
+ } // (for word in bytecode).
- StatusOr<void> Delete();
+ if (!is_eom) {
+ PERFETTO_DLOG(
+ "bytecode error: end of message not the last word in the bytecode");
+ return false;
+ }
- private:
- struct ParentLink {
- Node* node;
- IntrusiveMap* map;
- MapNode* map_node;
- };
+ if (overlay_idx != overlay.size()) {
+ PERFETTO_DLOG("bytecode error: overlay contains %zu unconsumed entries",
+ overlay.size() - overlay_idx);
+ return false;
+ }
- StatusOr<void> ConvertToMessageIfNeeded(Node* node);
- StatusOr<OwnedPtr<Node>> CreateNodeFromField(protozero::Field field);
- StatusOr<void> ConvertToMappedRepeatedFieldIfNeeded(
- Node* node,
- uint32_t map_key_field_id);
- StatusOr<void> ConvertToIndexedRepeatedFieldIfNeeded(Node* node);
- StatusOr<IntrusiveMap::Iterator> FindOrCreateMessageField(Node* node,
- uint32_t field_id);
- StatusOr<IntrusiveMap::Iterator> FindOrCreateIndexedRepeatedField(
- Node* node,
- uint32_t index);
- StatusOr<IntrusiveMap::Iterator> FindOrCreateMappedRepeatedField(
- Node* node,
- uint64_t key);
- StatusOr<IntrusiveMap::Iterator> MapInsert(IntrusiveMap* map,
- uint64_t key,
- OwnedPtr<Node> map_value);
- StatusOr<uint64_t> ReadScalarField(const Node& node, uint32_t field_id);
+ if (max_msg_index > 0 && max_msg_index >= message_offset_.size()) {
+ PERFETTO_DLOG(
+ "bytecode error: a message index (%u) is out of range "
+ "(num_messages=%zu)",
+ max_msg_index, message_offset_.size());
+ return false;
+ }
- StatusOr<void> CheckIsValid() const;
+ // Add a final entry to |message_offset_| so we can tell where the last
+ // message ends without an extra branch in the Query() hotpath.
+ message_offset_.emplace_back(static_cast<uint32_t>(words_.size()));
- Node* node_ = nullptr;
- ParentLink parent_link_ = {};
- Allocator* allocator_ = nullptr;
-};
+ return true;
+}
-} // namespace protovm
-} // namespace perfetto
+FilterBytecodeParser::QueryResult FilterBytecodeParser::Query(
+ uint32_t msg_index,
+ uint32_t field_id) const {
+ FilterBytecodeParser::QueryResult res{false, 0u, 0u};
+ if (static_cast<uint64_t>(msg_index) + 1 >=
+ static_cast<uint64_t>(message_offset_.size())) {
+ return res;
+ }
+ const uint32_t start_offset = message_offset_[msg_index];
+ // These are DCHECKs and not just CHECKS because the |words_| is populated
+ // by the LoadInternal call above. These cannot be violated with a malformed
+ // bytecode.
+ PERFETTO_DCHECK(start_offset < words_.size());
+ const uint32_t* word = &words_[start_offset];
+ const uint32_t end_off = message_offset_[msg_index + 1];
+ const uint32_t* const end = words_.data() + end_off;
+ PERFETTO_DCHECK(end > word && end <= words_.data() + words_.size());
+ const uint32_t num_directly_indexed = *(word++);
+ PERFETTO_DCHECK(num_directly_indexed <= kDirectlyIndexLimit);
+ PERFETTO_DCHECK(word + num_directly_indexed <= end);
+ uint32_t field_state = 0;
+ if (PERFETTO_LIKELY(field_id < num_directly_indexed)) {
+ PERFETTO_DCHECK(&word[field_id] < end);
+ field_state = word[field_id];
+ } else {
+ for (word = word + num_directly_indexed; word + 2 < end;) {
+ const uint32_t range_start = *(word++);
+ const uint32_t range_end = *(word++);
+ const uint32_t range_state = *(word++);
+ if (field_id >= range_start && field_id < range_end) {
+ field_state = range_state;
+ break;
+ }
+ } // for (word in ranges)
+ } // if (field_id >= num_directly_indexed)
-#endif // SRC_PROTOVM_RW_PROTO_CURSOR_H_
+ res.allowed = (field_state & kAllowed) != 0;
+ res.nested_msg_index = field_state & ~kAllowed;
+ // Extract semantic type if this is a FilterStringFieldWithType.
+ // Exclude kFilterStringField (0x7ffffffe) which doesn't have semantic type.
+ if ((res.nested_msg_index & kFilterStringFieldWithTypeMask) ==
+ kFilterStringFieldWithType &&
+ res.nested_msg_index != kFilterStringField) {
+ res.semantic_type = res.nested_msg_index & kSemanticTypeMask;
+ }
+ PERFETTO_DCHECK(!res.nested_msg_field() ||
+ res.nested_msg_index < message_offset_.size() - 1);
+ return res;
+}
+
+} // namespace protozero
+// gen_amalgamated begin source: src/protozero/filtering/string_filter.cc
+// gen_amalgamated begin header: src/protozero/filtering/string_filter.h
/*
- * Copyright (C) 2025 The Android Open Source Project
+ * 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.
@@ -55516,228 +60324,136 @@ class RwProtoCursor {
* limitations under the License.
*/
-#ifndef SRC_PROTOVM_RW_PROTO_H_
-#define SRC_PROTOVM_RW_PROTO_H_
+#ifndef SRC_PROTOZERO_FILTERING_STRING_FILTER_H_
+#define SRC_PROTOZERO_FILTERING_STRING_FILTER_H_
-// gen_amalgamated expanded: #include "perfetto/protozero/message.h"
+#include <array>
+#include <cstddef>
+#include <cstdint>
+#include <optional>
+#include <string>
+#include <string_view>
+#include <vector>
-// gen_amalgamated expanded: #include "src/protovm/allocator.h"
-// gen_amalgamated expanded: #include "src/protovm/node.h"
-// gen_amalgamated expanded: #include "src/protovm/rw_proto_cursor.h"
+// gen_amalgamated expanded: #include "perfetto/base/logging.h"
+// gen_amalgamated expanded: #include "perfetto/ext/base/regex.h"
+// gen_amalgamated expanded: #include "perfetto/public/compiler.h"
-namespace perfetto {
-namespace protovm {
+namespace protozero {
-// RwProto provides an API to create and manipulate protobuf messages without
-// requiring prior knowledge of the schema. Meaning that protobuf messages can
-// be dynamically built on-the-fly, without pre-compiled .proto definitions.
-//
-// Key features:
-//
-// - Schema-agnostic: RwProto dynamically learns the schema as fields and
-// messages are added.
-//
-// - Tree-like representation: protobuf messages are represented internally as a
-// tree of nodes, mirroring the nested structure of protobufs. This tree can
-// be traversed and manipulated using a Cursor object.
-//
-// - Fine-grained Memory Management: a centralized allocator is used to manage
-// memory for nodes, ensuring good data locality and fine-grained control over
-// memory usage.
-//
-// Overview of RwProto's internal node structure:
-//
-// ┌─────────┐
-// │ │
-// │ Message │
-// │ │ Map<field_id, OwnedPtr<Node>>
-// └─┬┬┬┬┬┬──┘
-// │││││└────────────────────────────────┐
-// ││││└───────────────────────┐ │
-// ┌───────────────┘││└──────────────┐ │ │
-// │ ┌───┘└────┐ │ │ │
-// │ │ ┌────▼────┐ ┌───▼───┐ ┌───▼───┐ ┌───▼────┐
-// │ │ │ │ │ │ │ │ │ │
-// │ │ │ Message │ │ Empty │ │ Bytes │ │ Scalar │
-// │ │ │ │ │ │ │ │ │ │
-// │ │ └────┬────┘ └───────┘ └───────┘ └────────┘
-// │ │ ▼
-// │ │ ...
-// │ │
-// │ │
-// │ *********▼********
-// │ * *
-// │ * Mapped *
-// │ * RepeatedField *
-// │ * *
-// │ ****************** Map<key, OwnedPtr<Node>>
-// │ │ │
-// │ ┌───┘ └────┐
-// │ │ │
-// │ ┌────▼────┐ ┌───▼───┐
-// │ │ │ │ │
-// │ │ Message │ │ Bytes │
-// │ │ │ │ │
-// │ └────┬────┘ └───────┘
-// │ ▼
-// │ ...
-// │
-//
-// ********▼*********
-// * *
-// * Indexed *
-// * RepeatedField *
-// * *
-// ****************** Map<index, OwnedPtr<Node>>
-// ││││
-// ┌──────┘││└────────────────────┐
-// │ │└───────────┐ │
-// │ └──┐ │ │
-// │ │ │ │
-// ┌────▼────┐ ┌───▼───┐ ┌───▼───┐ ┌───▼────┐
-// │ │ │ │ │ │ │ │
-// │ Message │ │ Empty │ │ Bytes │ │ Scalar │
-// │ │ │ │ │ │ │ │
-// └────┬────┘ └───────┘ └───────┘ └────────┘
-// ▼
-// ...
-//
-//
-// ┌─┐
-// │ │ Data node: corresponds to an actual field/message in the proto schema
-// └─┘ and eventually becomes part of the final serialized proto.
-//
-// ***
-// * * Structural node: used to organize and provide access to message fields.
-// *** It is an internal helper and doesn't appear in the
-// final serialized proto.
-//
-//
-// Message: Represents a protobuf message. It maps field_id to corresponding
-// node/value. It allows accessing fields as well as adding and
-// removing them.
-//
-//
-// Empty: Represents an empty or uninitialized node. It is used as a
-// placeholder before a node's type is determined. E.g. between an
-// "enter field" and a "set field value" operation.
-//
-//
-// Bytes: Stores a sequence of bytes, typically representing a length-delimited
-// protobuf field.
-//
-//
-// Scalar: Stores a scalar value.
-//
-//
-// IndexedRepeatedField: Represents a protobuf repeated field where elements
-// are accessed by index.
-//
-//
-// MappedRepeatedField: Represents a protobuf repeated field where elements
-// are accessed by key.
-class RwProto {
+// Performs filtering of strings in an "iptables" style. See the comments in
+// |TraceConfig.TraceFilter| for information on how this class works.
+class StringFilter {
public:
- using Cursor = RwProtoCursor;
-
- explicit RwProto(Allocator* allocator);
- ~RwProto();
- Cursor GetRoot();
- void Serialize(protozero::Message*) const;
+ // Bitmask for semantic types. Supports up to 128 semantic types.
+ class SemanticTypeMask {
+ public:
+ using Word = uint64_t;
+ static constexpr size_t kBitsPerWord = sizeof(Word) * 8;
+ static constexpr size_t kLimit = 128;
- private:
- void SerializeField(uint32_t field_id,
- const Node& node,
- protozero::Message* proto) const;
+ // Returns a SemanticTypeMask with only bit 0 set (UNSPECIFIED only).
+ // UNSPECIFIED is its own category and only matches if bit 0 is set.
+ static constexpr SemanticTypeMask Unspecified() {
+ return SemanticTypeMask(Word(1), Word(0));
+ }
- Allocator* allocator_{nullptr};
- Node root_;
-};
+ // Creates a SemanticTypeMask from raw word values (for testing).
+ static constexpr SemanticTypeMask FromWords(Word w0, Word w1) {
+ return SemanticTypeMask(w0, w1);
+ }
-} // namespace protovm
-} // namespace perfetto
+ // Default constructor: no bits set.
+ constexpr SemanticTypeMask() = default;
-#endif // SRC_PROTOVM_RW_PROTO_H_
-/*
- * Copyright (C) 2025 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.
- */
+ // Sets the bit for |semantic_type|.
+ PERFETTO_ALWAYS_INLINE void Set(uint32_t semantic_type) {
+ PERFETTO_DCHECK(semantic_type < kLimit);
+ uint32_t word_index = semantic_type / kBitsPerWord;
+ uint32_t bit_index = semantic_type % kBitsPerWord;
+ words_[word_index] |= Word(1) << bit_index;
+ }
-#ifndef SRC_PROTOVM_EXECUTOR_H_
-#define SRC_PROTOVM_EXECUTOR_H_
+ // Returns true if the bit for |semantic_type| is set.
+ PERFETTO_ALWAYS_INLINE bool IsSet(uint32_t semantic_type) const {
+ // If beyond supported range, return true (safe default: apply rule).
+ if (PERFETTO_UNLIKELY(semantic_type >= kLimit)) {
+ return true;
+ }
+ uint32_t word_index = semantic_type / kBitsPerWord;
+ uint32_t bit_index = semantic_type % kBitsPerWord;
+ return (words_[word_index] & (Word(1) << bit_index)) != 0;
+ }
-#include <cstdint>
-#include <optional>
+ private:
+ constexpr SemanticTypeMask(Word w0, Word w1) : words_{w0, w1} {}
-// gen_amalgamated expanded: #include "protos/perfetto/protovm/vm_program.pbzero.h"
+ std::array<Word, 2> words_ = {};
+ };
-// gen_amalgamated expanded: #include "src/protovm/error_handling.h"
-// gen_amalgamated expanded: #include "src/protovm/ro_cursor.h"
-// gen_amalgamated expanded: #include "src/protovm/rw_proto.h"
+ enum class Policy : uint8_t {
+ kMatchRedactGroups = 1,
+ kAtraceMatchRedactGroups = 2,
+ kMatchBreak = 3,
+ kAtraceMatchBreak = 4,
+ kAtraceRepeatedSearchRedactGroups = 5,
+ };
-namespace perfetto {
-namespace protovm {
+ // Adds a new rule for filtering strings.
+ //
+ // If `name` is non-empty and a rule with the same name already exists, it
+ // will be replaced; otherwise the rule is appended.
+ //
+ // `semantic_type_mask` is a bitmask indicating which semantic types this rule
+ // applies to. UNSPECIFIED (0) is its own category and only matches if bit 0
+ // is explicitly set. Defaults to matching only UNSPECIFIED.
+ void AddRule(
+ Policy policy,
+ std::string_view pattern,
+ std::string atrace_payload_starts_with,
+ std::string name = {},
+ SemanticTypeMask semantic_type_mask = SemanticTypeMask::Unspecified());
-using CursorEnum = perfetto::protos::pbzero::VmCursorEnum;
+ // Tries to filter the given string. Returns true if the string was modified
+ // in any way, false otherwise. Uses semantic_type=0 (unspecified).
+ bool MaybeFilter(char* ptr, size_t len) const {
+ return MaybeFilter(ptr, len, /*semantic_type=*/0);
+ }
-struct Cursors {
- RoCursor src;
- RwProto::Cursor dst;
- CursorEnum selected{CursorEnum::VM_CURSOR_UNSPECIFIED};
- bool create_if_not_exist{false};
+ // Tries to filter the given string with a specific semantic type.
+ // Only rules that match the semantic type (or have no type restriction)
+ // are applied.
+ bool MaybeFilter(char* ptr, size_t len, uint32_t semantic_type) const {
+ if (len == 0 || rules_.empty()) {
+ return false;
+ }
+ return MaybeFilterInternal(ptr, len, semantic_type);
+ }
- // Used internally by Parser to detect illegal "del" operations.
- // See detailed explanation in the Parser implementation.
- const RwProto::Cursor* innermost_saved_dst{nullptr};
-};
+ private:
+ struct Rule {
+ Policy policy;
+ std::optional<perfetto::base::CopyableRegex> pattern;
+ std::string atrace_payload_starts_with;
+ std::string name;
+ SemanticTypeMask semantic_type_mask = SemanticTypeMask::Unspecified();
+ };
-// Executor's methods are virtual to be overridden in tests
-class Executor {
- public:
- using MergeFlags = RwProto::Cursor::MergeFlags;
+ bool MaybeFilterInternal(char* ptr, size_t len, uint32_t semantic_type) const;
- virtual ~Executor();
- virtual StatusOr<void> EnterField(Cursors* cursors, uint32_t field_id) const;
- virtual StatusOr<void> EnterRepeatedFieldAt(Cursors* cursors,
- uint32_t field_id,
- uint32_t index) const;
- virtual StatusOr<void> EnterRepeatedFieldByKey(Cursors* cursors,
- uint32_t field_id,
- uint32_t map_key_field_id,
- uint64_t key) const;
- virtual StatusOr<RoCursor::RepeatedFieldIterator> IterateRepeatedField(
- RoCursor* src,
- uint32_t field_id) const;
- virtual StatusOr<RwProto::Cursor::RepeatedFieldIterator> IterateRepeatedField(
- RwProto::Cursor* dst,
- uint32_t field_id) const;
- virtual StatusOr<uint64_t> ReadRegister(uint8_t reg_id) const;
- virtual StatusOr<void> WriteRegister(const Cursors& cursors, uint8_t reg_id);
- virtual StatusOr<void> Delete(RwProto::Cursor* dst) const;
- virtual StatusOr<void> Merge(Cursors* cursors, uint32_t flags) const;
- virtual StatusOr<void> Set(Cursors* cursors) const;
+ // All rules, in the order they were added.
+ std::vector<Rule> rules_;
- private:
- std::array<std::optional<uint64_t>, 32> registers_;
+ // Reusable buffer for regex match groups, avoiding heap allocations on each
+ // filter call.
+ mutable std::vector<std::string_view> matches_;
};
-} // namespace protovm
-} // namespace perfetto
+} // namespace protozero
-#endif // SRC_PROTOVM_EXECUTOR_H_
+#endif // SRC_PROTOZERO_FILTERING_STRING_FILTER_H_
/*
- * Copyright (C) 2025 The Android Open Source Project
+ * 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.
@@ -55752,128 +60468,199 @@ class Executor {
* limitations under the License.
*/
-// gen_amalgamated expanded: #include "src/protovm/executor.h"
-
-namespace perfetto {
-namespace protovm {
-
-Executor::~Executor() = default;
+// gen_amalgamated expanded: #include "src/protozero/filtering/string_filter.h"
-StatusOr<void> Executor::EnterField(Cursors* cursors, uint32_t field_id) const {
- if (cursors->selected == CursorEnum::VM_CURSOR_SRC) {
- return cursors->src.EnterField(field_id);
- }
+#include <algorithm>
+#include <cstdint>
+#include <cstring>
+#include <string>
+#include <string_view>
+#include <utility>
+#include <vector>
- auto has_field = cursors->dst.HasField(field_id);
- PROTOVM_RETURN_IF_NOT_OK(has_field);
+// gen_amalgamated expanded: #include "perfetto/public/compiler.h"
- if (!has_field.value() && !cursors->create_if_not_exist) {
- return StatusOr<void>::Error();
- }
+namespace protozero {
+namespace {
- return cursors->dst.EnterField(field_id);
-}
+constexpr std::string_view kRedacted = "P60REDACTED";
+constexpr char kRedactedDash = '-';
-StatusOr<void> Executor::EnterRepeatedFieldAt(Cursors* cursors,
- uint32_t field_id,
- uint32_t index) const {
- if (cursors->selected == CursorEnum::VM_CURSOR_SRC) {
- return cursors->src.EnterRepeatedFieldAt(field_id, index);
+// Returns a pointer to the first character after the tgid pipe character in
+// the atrace string given by [ptr, end). Returns null if no such character
+// exists.
+//
+// Examples:
+// E|1024 -> nullptr
+// foobarbaz -> nullptr
+// B|1024|x -> pointer to x
+PERFETTO_ALWAYS_INLINE const char* FindAtracePayloadPtr(const char* ptr,
+ const char* end) {
+ // Don't even bother checking any strings which are so short that they could
+ // not contain a post-tgid section. This filters out strings like "E|" which
+ // emitted by Bionic.
+ //
+ // Also filter out any other strings starting with "E" as they never contain
+ // anything past the tgid: this removes >half of the strings for ~zero cost.
+ static constexpr size_t kEarliestSecondPipeIndex = 2;
+ const char* search_start = ptr + kEarliestSecondPipeIndex;
+ if (PERFETTO_UNLIKELY(search_start >= end || *ptr == 'E')) {
+ return nullptr;
}
- return cursors->dst.EnterRepeatedFieldAt(field_id, index);
+ // We skipped past the first '|' character by starting at the character at
+ // index 2. Just find the next pipe character (i.e. the one after tgid) using
+ // memchr.
+ const char* pipe = static_cast<const char*>(
+ memchr(search_start, '|', size_t(end - search_start)));
+ return pipe ? pipe + 1 : nullptr;
}
-StatusOr<void> Executor::EnterRepeatedFieldByKey(Cursors* cursors,
- uint32_t field_id,
- uint32_t map_key_field_id,
- uint64_t key) const {
- if (cursors->selected == CursorEnum::VM_CURSOR_SRC) {
- PROTOVM_ABORT(
- "Mapped repeated fields are currently supported only in RwProto");
- }
-
- auto has_field = cursors->dst.HasField(field_id);
- PROTOVM_RETURN_IF_NOT_OK(has_field);
+PERFETTO_ALWAYS_INLINE bool StartsWith(const char* ptr,
+ const char* end,
+ const std::string& starts_with) {
+ // Verify that the atrace string has enough characters to match against all
+ // the characters in the "starts with" string.
+ size_t len = starts_with.size();
+ if (PERFETTO_UNLIKELY(ptr + len > end))
+ return false;
- if (!has_field.value() && !cursors->create_if_not_exist) {
- return StatusOr<void>::Error();
- }
+ // Empty string matches everything.
+ if (PERFETTO_UNLIKELY(len == 0))
+ return true;
- return cursors->dst.EnterRepeatedFieldByKey(field_id, map_key_field_id, key);
-}
+ // Quick rejection: check first character before expensive memcmp.
+ // This is very effective since most strings don't match.
+ if (PERFETTO_LIKELY(*ptr != *starts_with.data()))
+ return false;
-StatusOr<RoCursor::RepeatedFieldIterator> Executor::IterateRepeatedField(
- RoCursor* src,
- uint32_t field_id) const {
- return src->IterateRepeatedField(field_id);
+ // If first char matches, do full memcmp for remaining characters.
+ return memcmp(ptr + 1, starts_with.data() + 1, len - 1) == 0;
}
-StatusOr<RwProto::Cursor::RepeatedFieldIterator> Executor::IterateRepeatedField(
- RwProto::Cursor* dst,
- uint32_t field_id) const {
- return dst->IterateRepeatedField(field_id);
-}
+void RedactMatches(const std::vector<std::string_view>& matches) {
+ // Go through every group in the matches.
+ for (size_t i = 1; i < matches.size(); ++i) {
+ const auto& match = matches[i];
+ // Skip unmatched optional groups: empty string_view may have nullptr
+ // data(), and passing nullptr to memcpy/memset is UB even with size 0.
+ if (match.empty())
+ continue;
-StatusOr<uint64_t> Executor::ReadRegister(uint8_t reg_id) const {
- if (reg_id >= registers_.size()) {
- PROTOVM_ABORT("Register (id = %d) is out of bounds", reg_id);
- }
- if (!registers_[reg_id]) {
- PROTOVM_ABORT("Register (id = %d) is not initialized)", reg_id);
- }
- return StatusOr<uint64_t>{*registers_[reg_id]};
-}
+ // Overwrite the match with characters from |kRedacted|. If match is
+ // smaller, we will not use all of |kRedacted| but that's fine (i.e. we
+ // will overwrite with a truncated |kRedacted|).
+ size_t match_len = match.size();
+ size_t redacted_len = std::min(match_len, kRedacted.size());
+ memcpy(const_cast<char*>(match.data()), kRedacted.data(), redacted_len);
-StatusOr<void> Executor::WriteRegister(const Cursors& cursors, uint8_t reg_id) {
- if (reg_id >= registers_.size()) {
- PROTOVM_ABORT("Register (id = %d) is out of bounds", reg_id);
+ // Overwrite any characters after |kRedacted| with |kRedactedDash|.
+ memset(const_cast<char*>(match.data()) + redacted_len, kRedactedDash,
+ match_len - redacted_len);
}
-
- auto status_or_scalar = cursors.selected == CursorEnum::VM_CURSOR_SRC
- ? cursors.src.GetScalar()
- : cursors.dst.GetScalar();
- PROTOVM_RETURN_IF_NOT_OK(status_or_scalar);
-
- registers_[reg_id] = status_or_scalar->value;
- return StatusOr<void>::Ok();
}
-StatusOr<void> Executor::Delete(RwProto::Cursor* dst) const {
- return dst->Delete();
-}
+} // namespace
-StatusOr<void> Executor::Merge(Cursors* cursors, uint32_t flags) const {
- if (!cursors->src.IsBytes()) {
- PROTOVM_ABORT(
- "Attempted MERGE operation but src cursor has incompatible data "
- "type");
+void StringFilter::AddRule(Policy policy,
+ std::string_view pattern_str,
+ std::string atrace_payload_starts_with,
+ std::string name,
+ SemanticTypeMask semantic_type_mask) {
+ perfetto::base::CopyableRegex re(
+ perfetto::base::Regex::CreateOrCheck(std::string(pattern_str)));
+ Rule new_rule{policy, std::move(re), std::move(atrace_payload_starts_with),
+ std::move(name), semantic_type_mask};
+ // If name is non-empty, look for existing rule with same name and replace.
+ if (!new_rule.name.empty()) {
+ for (Rule& existing : rules_) {
+ if (existing.name == new_rule.name) {
+ existing = std::move(new_rule);
+ return;
+ }
+ }
}
-
- return cursors->dst.Merge(*cursors->src.GetBytes(), flags);
+ rules_.push_back(std::move(new_rule));
}
-StatusOr<void> Executor::Set(Cursors* cursors) const {
- if (cursors->src.IsScalar()) {
- auto status_or_scalar = cursors->src.GetScalar();
- PROTOVM_RETURN_IF_NOT_OK(status_or_scalar);
- return cursors->dst.SetScalar(*status_or_scalar);
- }
+bool StringFilter::MaybeFilterInternal(char* ptr,
+ size_t len,
+ uint32_t semantic_type) const {
+ bool atrace_find_tried = false;
+ const char* atrace_payload_ptr = nullptr;
+ std::string_view input(ptr, len);
- if (cursors->src.IsBytes()) {
- auto status_or_bytes = cursors->src.GetBytes();
- PROTOVM_RETURN_IF_NOT_OK(status_or_bytes);
- return cursors->dst.SetBytes(*status_or_bytes);
+ for (const Rule& rule : rules_) {
+ if (!rule.semantic_type_mask.IsSet(semantic_type)) {
+ continue;
+ }
+ switch (rule.policy) {
+ case Policy::kMatchBreak:
+ if (PERFETTO_UNLIKELY(rule.pattern->FullMatch(input)))
+ return false;
+ break;
+ case Policy::kMatchRedactGroups:
+ if (PERFETTO_UNLIKELY(
+ rule.pattern->FullMatchWithGroups(input, matches_))) {
+ RedactMatches(matches_);
+ return true;
+ }
+ break;
+ case Policy::kAtraceMatchBreak:
+ atrace_payload_ptr = atrace_find_tried
+ ? atrace_payload_ptr
+ : FindAtracePayloadPtr(ptr, ptr + len);
+ atrace_find_tried = true;
+ if (atrace_payload_ptr &&
+ StartsWith(atrace_payload_ptr, ptr + len,
+ rule.atrace_payload_starts_with) &&
+ rule.pattern->FullMatch(input)) {
+ return false;
+ }
+ break;
+ case Policy::kAtraceMatchRedactGroups:
+ atrace_payload_ptr = atrace_find_tried
+ ? atrace_payload_ptr
+ : FindAtracePayloadPtr(ptr, ptr + len);
+ atrace_find_tried = true;
+ if (atrace_payload_ptr &&
+ StartsWith(atrace_payload_ptr, ptr + len,
+ rule.atrace_payload_starts_with) &&
+ PERFETTO_UNLIKELY(
+ rule.pattern->FullMatchWithGroups(input, matches_))) {
+ RedactMatches(matches_);
+ return true;
+ }
+ break;
+ case Policy::kAtraceRepeatedSearchRedactGroups:
+ atrace_payload_ptr = atrace_find_tried
+ ? atrace_payload_ptr
+ : FindAtracePayloadPtr(ptr, ptr + len);
+ atrace_find_tried = true;
+ if (atrace_payload_ptr && StartsWith(atrace_payload_ptr, ptr + len,
+ rule.atrace_payload_starts_with)) {
+ bool has_any_matches = false;
+ for (auto iter = rule.pattern->PartialMatchAll(input);
+ iter.NextWithGroups(matches_);) {
+ RedactMatches(matches_);
+ has_any_matches = true;
+ }
+ if (has_any_matches) {
+ return true;
+ }
+ }
+ break;
+ }
}
-
- PROTOVM_ABORT("Attempted SET operation but src cursor has no valid data");
+ return false;
}
-} // namespace protovm
-} // namespace perfetto
-// gen_amalgamated begin source: src/protovm/node.cc
+} // namespace protozero
+// gen_amalgamated begin source: src/protozero/filtering/message_filter.cc
+// gen_amalgamated begin header: src/protozero/filtering/message_filter.h
+// gen_amalgamated begin header: src/protozero/filtering/message_tokenizer.h
/*
- * Copyright (C) 2025 The Android Open Source Project
+ * Copyright (C) 2021 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.
@@ -55888,100 +60675,191 @@ StatusOr<void> Executor::Set(Cursors* cursors) const {
* limitations under the License.
*/
-// gen_amalgamated expanded: #include "src/protovm/node.h"
+#ifndef SRC_PROTOZERO_FILTERING_MESSAGE_TOKENIZER_H_
+#define SRC_PROTOZERO_FILTERING_MESSAGE_TOKENIZER_H_
-namespace perfetto {
-namespace protovm {
+#include <stdint.h>
-const char* Node::GetTypeName() const {
- return std::visit(
- [](auto&& value) {
- using T = std::decay_t<decltype(value)>;
- if constexpr (std::is_same_v<T, Node::Bytes>) {
- return "Bytes";
- } else if constexpr (std::is_same_v<T, Node::Empty>) {
- return "Empty";
- } else if constexpr (std::is_same_v<T, Node::IndexedRepeatedField>) {
- return "IndexedRepeatedField";
- } else if constexpr (std::is_same_v<T, Node::MappedRepeatedField>) {
- return "MappedRepeatedField";
- } else if constexpr (std::is_same_v<T, Node::Message>) {
- return "Message";
- } else if constexpr (std::is_same_v<T, Scalar>) {
- return "Scalar";
+// gen_amalgamated expanded: #include "perfetto/base/compiler.h"
+// gen_amalgamated expanded: #include "perfetto/base/logging.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/proto_utils.h"
+
+namespace protozero {
+
+// A helper class for schema-less tokenizing of protobuf messages.
+// This class takes a stream of proto-encoded bytes, pushed one by one in input
+// via Push(octet), and returns a stream of tokens (each Push() call can return
+// 0 or 1 token).
+// A "token" contains metadata about a field, specifically: its ID, its wire
+// type and:
+// - For varint and fixed32/64 fields: its payload.
+// - For string and bytes fields: the length of its payload.
+// In this case the caller is supposed to "eat" those N bytes before calling
+// Push() again.
+// Note that this class cannot differentiate between a string/bytes field or
+// a submessage, because they are encoded in the same way. The caller is
+// supposed to know whether a field can be recursed into by just keep calling
+// Push() or is a string that should be skipped.
+// This is inline to allow the compiler to see through the Push method and
+// avoid a function call for each byte.
+class MessageTokenizer {
+ public:
+ struct Token {
+ uint32_t field_id; // 0 == not valid.
+ proto_utils::ProtoWireType type;
+
+ // For kLengthDelimited, |value| represent the length of the payload.
+ uint64_t value;
+
+ inline bool valid() const { return field_id != 0; }
+ bool operator==(const Token& o) const {
+ return field_id == o.field_id && type == o.type && value == o.value;
+ }
+ };
+
+ // Pushes a byte in input and returns a token, only when getting to the last
+ // byte of each field. Specifically:
+ // - For varint and fixed32 fields, the Token is returned after the last byte
+ // of the numeric payload is pushed.
+ // - For length-delimited fields, this returns after the last byte of the
+ // length is pushed (i.e. right before the payload starts). The caller is
+ // expected to either skip the next |value| bytes (in the case of a string
+ // or bytes fields) or keep calling Push, in the case of a submessage.
+ inline Token Push(uint8_t octet) {
+ using protozero::proto_utils::ProtoWireType;
+
+ // Parsing a fixed32/64 field is the only case where we don't have to do
+ // any varint decoding. This is why this block is before the remaining
+ // switch statement below (all the rest is a varint).
+ if (PERFETTO_UNLIKELY(state_ == kFixedIntValue)) {
+ PERFETTO_DCHECK(fixed_int_bits_ == 32 || fixed_int_bits_ == 64);
+ fixed_int_value_ |= static_cast<uint64_t>(octet) << fixed_int_shift_;
+ fixed_int_shift_ += 8;
+ if (fixed_int_shift_ < fixed_int_bits_)
+ return Token{}; // Intermediate byte of a fixed32/64.
+ auto wire_type = fixed_int_bits_ == 32 ? ProtoWireType::kFixed32
+ : ProtoWireType::kFixed64;
+ uint64_t fixed_int_value = fixed_int_value_;
+ fixed_int_value_ = fixed_int_shift_ = fixed_int_bits_ = 0;
+ state_ = kFieldPreamble;
+ return Token{field_id_, wire_type, fixed_int_value};
+ }
+
+ // At this point either we are: (i) parsing a field preamble; (ii) parsing a
+ // varint field paylod; (iii) parsing the length of a length-delimited
+ // field. In all cases, we need to decode a varint before proceeding.
+ varint_ |= static_cast<uint64_t>(octet & 0x7F) << varint_shift_;
+ if (octet & 0x80) {
+ varint_shift_ += 7;
+ if (PERFETTO_UNLIKELY(varint_shift_ >= 64)) {
+ varint_shift_ = 0;
+ state_ = kInvalidVarInt;
+ }
+ return Token{}; // Still parsing a varint.
+ }
+
+ uint64_t varint = varint_;
+ varint_ = 0;
+ varint_shift_ = 0;
+
+ switch (state_) {
+ case kFieldPreamble: {
+ auto field_type = static_cast<uint32_t>(varint & 7u); // 7 = 0..0111
+ field_id_ = static_cast<uint32_t>(varint >> 3);
+
+ // The field type is legit, now check it's well formed and within
+ // boundaries.
+ if (field_type == static_cast<uint32_t>(ProtoWireType::kVarInt)) {
+ state_ = kVarIntValue;
+ } else if (field_type ==
+ static_cast<uint32_t>(ProtoWireType::kFixed32) ||
+ field_type ==
+ static_cast<uint32_t>(ProtoWireType::kFixed64)) {
+ state_ = kFixedIntValue;
+ fixed_int_shift_ = 0;
+ fixed_int_value_ = 0;
+ fixed_int_bits_ =
+ field_type == static_cast<uint32_t>(ProtoWireType::kFixed32) ? 32
+ : 64;
+ } else if (field_type ==
+ static_cast<uint32_t>(ProtoWireType::kLengthDelimited)) {
+ state_ = kLenDelimited;
} else {
- return "<unknown>";
+ state_ = kInvalidFieldType;
}
- },
- value);
-}
+ return Token{};
+ }
-} // namespace protovm
-} // namespace perfetto
-// gen_amalgamated begin source: src/protovm/parser.cc
-// gen_amalgamated begin header: src/protovm/parser.h
-/*
- * Copyright (C) 2025 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.
- */
+ case kVarIntValue: {
+ // Return the varint field payload and go back to the next field.
+ state_ = kFieldPreamble;
+ return Token{field_id_, ProtoWireType::kVarInt, varint};
+ }
+
+ case kLenDelimited: {
+ const auto payload_len = varint;
+ if (payload_len > protozero::proto_utils::kMaxMessageLength) {
+ state_ = kMessageTooBig;
+ return Token{};
+ }
+ state_ = kFieldPreamble;
+ // At this point the caller is expected to consume the next
+ // |payload_len| bytes.
+ return Token{field_id_, ProtoWireType::kLengthDelimited, payload_len};
+ }
-#ifndef SRC_PROTOVM_PARSER_H_
-#define SRC_PROTOVM_PARSER_H_
+ case kFixedIntValue:
+ // Unreachable because of the if before the switch.
+ PERFETTO_DCHECK(false);
+ break;
-// gen_amalgamated expanded: #include "perfetto/protozero/field.h"
-// gen_amalgamated expanded: #include "protos/perfetto/protovm/vm_program.pbzero.h"
+ // Unrecoverable error states.
+ case kInvalidFieldType:
+ case kMessageTooBig:
+ case kInvalidVarInt:
+ break;
+ } // switch(state_)
-// gen_amalgamated expanded: #include "src/protovm/error_handling.h"
-// gen_amalgamated expanded: #include "src/protovm/executor.h"
-// gen_amalgamated expanded: #include "src/protovm/ro_cursor.h"
-// gen_amalgamated expanded: #include "src/protovm/rw_proto.h"
+ return Token{}; // Keep GCC happy.
+ }
-namespace perfetto {
-namespace protovm {
+ // Returns true if the tokenizer FSM has reached quiescence (i.e. if we are
+ // NOT in the middle of parsing a field).
+ bool idle() const {
+ return state_ == kFieldPreamble && varint_shift_ == 0 &&
+ fixed_int_shift_ == 0;
+ }
-class Parser {
- public:
- Parser(protozero::ConstBytes program, Executor* executor);
- StatusOr<void> Run(RoCursor src, RwProto::Cursor dst);
+ // Only for reporting parser errors in the trace.
+ uint32_t state() const { return static_cast<uint32_t>(state_); }
private:
- StatusOr<void> ParseInstructions(
- protozero::RepeatedFieldIterator<protozero::ConstBytes> it_instruction);
- StatusOr<void> ParseInstruction(
- const protos::pbzero::VmInstruction::Decoder& instruction);
- StatusOr<void> ParseMerge(
- const protos::pbzero::VmInstruction::Decoder& instruction);
- StatusOr<void> ParseRegLoad(
- const protos::pbzero::VmInstruction::Decoder& instruction);
- StatusOr<void> ParseSelect(
- const protos::pbzero::VmInstruction::Decoder& instruction);
- StatusOr<void> ParseSelectRec(
- const protos::pbzero::VmInstruction::Decoder& instruction,
- protozero::RepeatedFieldIterator<protozero::ConstBytes>
- it_path_component);
+ enum State {
+ kFieldPreamble = 0, // Parsing the varint for the field preamble.
+ kVarIntValue = 1, // Parsing the payload of a varint field.
+ kFixedIntValue = 2, // Parsing the payload of a fixed32/64 field.
+ kLenDelimited = 3, // Parsing the length of a length-delimited field.
- protos::pbzero::VmProgram::Decoder program_;
- Cursors cursors_;
- Executor* executor_;
+ // Unrecoverable error states:
+ kInvalidFieldType = 4, // Encountered an invalid field type.
+ kMessageTooBig = 5, // Size of the length delimited message was too big.
+ kInvalidVarInt = 6, // Varint larger than 64 bits.
+ };
+
+ State state_ = kFieldPreamble;
+ uint32_t field_id_ = 0;
+ uint64_t varint_ = 0;
+ uint32_t varint_shift_ = 0;
+ uint32_t fixed_int_shift_ = 0;
+ uint32_t fixed_int_bits_ = 0;
+ uint64_t fixed_int_value_ = 0;
};
-} // namespace protovm
-} // namespace perfetto
+} // namespace protozero
-#endif // SRC_PROTOVM_PARSER_H_
+#endif // SRC_PROTOZERO_FILTERING_MESSAGE_TOKENIZER_H_
/*
- * Copyright (C) 2025 The Android Open Source Project
+ * Copyright (C) 2021 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.
@@ -55996,260 +60874,249 @@ class Parser {
* limitations under the License.
*/
-// gen_amalgamated expanded: #include "src/protovm/parser.h"
-// gen_amalgamated expanded: #include "protos/perfetto/protovm/vm_program.pbzero.h"
-// gen_amalgamated expanded: #include "src/protovm/error_handling.h"
+#ifndef SRC_PROTOZERO_FILTERING_MESSAGE_FILTER_H_
+#define SRC_PROTOZERO_FILTERING_MESSAGE_FILTER_H_
-namespace perfetto {
-namespace protovm {
+#include <stdint.h>
-Parser::Parser(protozero::ConstBytes program, Executor* executor)
- : program_{program}, executor_(executor) {}
+#include <memory>
+#include <string>
+#include <unordered_map>
-StatusOr<void> Parser::Run(RoCursor src, RwProto::Cursor dst) {
- cursors_.src = src;
- cursors_.dst = dst;
- cursors_.innermost_saved_dst = nullptr;
- return ParseInstructions(program_.instructions());
-}
+// gen_amalgamated expanded: #include "src/protozero/filtering/filter_bytecode_parser.h"
+// gen_amalgamated expanded: #include "src/protozero/filtering/message_tokenizer.h"
+// gen_amalgamated expanded: #include "src/protozero/filtering/string_filter.h"
-StatusOr<void> Parser::ParseInstructions(
- protozero::RepeatedFieldIterator<protozero::ConstBytes> it_instruction) {
- int instruction_index = 0;
- for (; it_instruction; ++it_instruction) {
- auto instruction = protos::pbzero::VmInstruction::Decoder(*it_instruction);
- auto status = ParseInstruction(instruction);
+namespace protozero {
- if (status.IsAbort()) {
- PROTOVM_RETURN(status, "instruction[%d]", instruction_index);
- }
+// A class to filter binary-encoded proto messages using an allow-list of field
+// ids, also known as "filter bytecode". The filter determines which fields are
+// allowed to be passed through in output and strips all the other fields.
+// See go/trace-filtering for full design.
+// This class takes in input:
+// 1) The filter bytecode, loaded once via the LoadFilterBytecode() method.
+// 2) A proto-encoded binary message. The message doesn't have to be contiguous,
+// it can be passed as an array of arbitrarily chunked fragments.
+// The FilterMessage*() method returns in output a proto message, stripping out
+// all unknown fields. If the input is malformed (e.g., unknown proto field wire
+// types, lengths out of bound) the whole filtering failed and the |error| flag
+// of the FilteredMessage object is set to true.
+// The filtering operation is based on rewriting a copy of the message into a
+// self-allocated buffer, which is then returned in the output. The input buffer
+// is NOT altered.
+// Note also that the process of rewriting the protos gets rid of most redundant
+// varint encoding (if present). So even if all fields are allow-listed, the
+// output might NOT be bitwise identical to the input (but it will be
+// semantically equivalent).
+// Furthermore the enable_field_usage_tracking() method allows to keep track of
+// a histogram of allowed / denied fields. It slows down filtering and is
+// intended only on host tools.
+class MessageFilter {
+ public:
+ class Config {
+ public:
+ // Loads filter bytecode. If a filter is already loaded, it is replaced.
+ // Optionally accepts an overlay (pass nullptr/0 if not needed).
+ // See FilterBytecodeParser::Load() for overlay format details.
+ bool LoadFilterBytecode(const void* filter_data,
+ size_t len,
+ const void* overlay_data = nullptr,
+ size_t overlay_len = 0);
- if (status.IsError()) {
- using AbortLevel = perfetto::protos::pbzero::VmInstruction::AbortLevel;
- auto abort_level =
- instruction.has_abort_level()
- ? static_cast<AbortLevel>(instruction.abort_level())
- : AbortLevel::SKIP_CURRENT_INSTRUCTION_AND_BREAK_OUTER;
- if (abort_level == AbortLevel::SKIP_CURRENT_INSTRUCTION_AND_BREAK_OUTER) {
- return StatusOr<void>::Error();
- }
- if (abort_level == AbortLevel::ABORT) {
- PROTOVM_ABORT(
- "instruction[%d]: returned status = error and instruction's "
- "abort level = 'abort'",
- instruction_index);
- }
- }
+ bool SetFilterRoot(std::initializer_list<uint32_t> field_ids);
- ++instruction_index;
- }
+ const FilterBytecodeParser& filter() const { return filter_; }
+ const StringFilter& string_filter() const { return string_filter_; }
+ StringFilter& string_filter() { return string_filter_; }
+ uint32_t root_msg_index() const { return root_msg_index_; }
- return StatusOr<void>::Ok();
-}
+ private:
+ FilterBytecodeParser filter_;
+ StringFilter string_filter_;
+ uint32_t root_msg_index_ = 0;
+ };
-StatusOr<void> Parser::ParseInstruction(
- const protos::pbzero::VmInstruction::Decoder& instruction) {
- if (instruction.has_select()) {
- auto status = ParseSelect(instruction);
- PROTOVM_RETURN(status, "select");
+ MessageFilter();
+ explicit MessageFilter(Config);
+ ~MessageFilter();
+
+ struct InputSlice {
+ const void* data;
+ size_t len;
+ };
+
+ struct FilteredMessage {
+ FilteredMessage(std::unique_ptr<uint8_t[]> d, size_t s)
+ : data(std::move(d)), size(s) {}
+ std::unique_ptr<uint8_t[]> data;
+ size_t size; // The used bytes in |data|. This is <= sizeof(data).
+ bool error = false;
+ };
+
+ // Loads the filter bytecode that will be used to filter any subsequent
+ // message. Must be called before the first call to FilterMessage*().
+ // |filter_data| must point to a byte buffer for a proto-encoded ProtoFilter
+ // message (see proto_filter.proto).
+ // Optionally accepts an overlay (pass nullptr/0 if not needed).
+ bool LoadFilterBytecode(const void* filter_data,
+ size_t len,
+ const void* overlay_data = nullptr,
+ size_t overlay_len = 0) {
+ return config_.LoadFilterBytecode(filter_data, len, overlay_data,
+ overlay_len);
}
- if (instruction.has_reg_load()) {
- auto status = ParseRegLoad(instruction);
- PROTOVM_RETURN_IF_NOT_OK(status, "reg_load");
- } else if (instruction.has_del()) {
- PROTOVM_ASSIGN_OR_RETURN(bool is_root, cursors_.dst.IsRoot());
- if (cursors_.innermost_saved_dst != nullptr &&
- cursors_.dst == *cursors_.innermost_saved_dst && !is_root) {
- // Illegal operation
- // For each "select" operation we effectively save a snapshot of the
- // cursors on the stack, so that they can be restored when a frame is
- // exited. This "del" operation is attempting to delete a "dst" cursor
- // that is currently aliased in the parent stack frame. This would result
- // in a dangling pointer when the current frame is exited and the aliased
- // "dst" is restored.
- PROTOVM_ABORT(
- "del would invalidate a cursor saved by an enclosing select");
- }
- auto status = executor_->Delete(&cursors_.dst);
- PROTOVM_RETURN_IF_NOT_OK(status, "del");
- } else if (instruction.has_merge()) {
- auto status = ParseMerge(instruction);
- PROTOVM_RETURN_IF_NOT_OK(status, "merge");
- } else if (instruction.has_set()) {
- auto status = executor_->Set(&cursors_);
- PROTOVM_RETURN_IF_NOT_OK(status, "set");
- } else {
- PROTOVM_ABORT("Unsupported instruction");
+ // This affects the filter starting point of the subsequent FilterMessage*()
+ // calls. By default the filtering process starts from the message @ index 0,
+ // the root message passed to proto_filter when generating the bytecode
+ // (in typical tracing use-cases, this is perfetto.protos.Trace). However, the
+ // caller (TracingServiceImpl) might want to filter packets from the 2nd level
+ // (perfetto.protos.TracePacket) because the root level is prepended after
+ // the fact. This call allows to change the root message for the filter.
+ // The argument |field_ids| is an array of proto field ids and determines the
+ // path to the new root. For instance, in the case of [1,2,3] SetFilterRoot
+ // will identify the sub-message for the field "root.1.2.3" and use that.
+ // In order for this to succeed all the fields in the path must be allowed
+ // in the filter and must be a nested message type.
+ bool SetFilterRoot(std::initializer_list<uint32_t> field_ids) {
+ return config_.SetFilterRoot(field_ids);
}
- return ParseInstructions(instruction.nested_instructions());
-}
+ // Takes an input message, fragmented in arbitrary slices, and returns a
+ // filtered message in output.
+ FilteredMessage FilterMessageFragments(const InputSlice*, size_t num_slices);
-StatusOr<void> Parser::ParseMerge(
- const protos::pbzero::VmInstruction::Decoder& instruction) {
- protos::pbzero::VmOpMerge::Decoder merge(instruction.merge());
- uint32_t flags = Executor::MergeFlags::kNone;
- if (merge.skip_submessages())
- flags |= Executor::MergeFlags::kSkipSubmessages;
- if (merge.del_if_src_empty())
- flags |= Executor::MergeFlags::kDelIfSrcEmpty;
- auto status = executor_->Merge(&cursors_, flags);
- PROTOVM_RETURN_IF_NOT_OK(status);
- return status;
-}
+ // Helper for tests, where the input is a contiguous buffer.
+ FilteredMessage FilterMessage(const void* data, size_t len) {
+ InputSlice slice{data, len};
+ return FilterMessageFragments(&slice, 1);
+ }
-StatusOr<void> Parser::ParseRegLoad(
- const protos::pbzero::VmInstruction::Decoder& instruction) {
- auto saved_selected = cursors_.selected;
+ // When enabled returns a map of "field path" to "usage counter".
+ // The key (std::string) is a binary buffer (i.e. NOT an ASCII/UTF-8 string)
+ // which contains a varint for each field. Consider the following:
+ // message Root { Sub1 f1 = 1; };
+ // message Sub1 { Sub2 f2 = 7;}
+ // message Sub2 { string f3 = 5; }
+ // The field .f1.f2.f3 will be encoded as \x01\0x07\x05.
+ // The value is the number of times that field has been encountered. If the
+ // field is not allow-listed in the bytecode (the field is stripped in output)
+ // the count will be negative.
+ void enable_field_usage_tracking(bool x) { track_field_usage_ = x; }
+ const std::unordered_map<std::string, int32_t>& field_usage() const {
+ return field_usage_;
+ }
- protos::pbzero::VmOpRegLoad::Decoder reg_load(instruction.reg_load());
- cursors_.selected = !reg_load.has_cursor()
- ? CursorEnum::VM_CURSOR_SRC
- : static_cast<CursorEnum>(reg_load.cursor());
- auto status = executor_->WriteRegister(
- cursors_, static_cast<uint8_t>(reg_load.dst_register()));
+ const Config& config() const { return config_; }
+ Config& config() { return config_; }
- cursors_.selected = saved_selected;
+ // Returns the helper class used to perform string filtering.
+ StringFilter& string_filter() { return config_.string_filter(); }
- PROTOVM_RETURN_IF_NOT_OK(status);
+ private:
+ // This is called by FilterMessageFragments().
+ // Inlining allows the compiler turn the per-byte call/return into a for loop,
+ // while, at the same time, keeping the code easy to read and reason about.
+ // It gives a 20-25% speedup (265ms vs 215ms for a 25MB trace).
+ void FilterOneByte(uint8_t octet) PERFETTO_ALWAYS_INLINE;
- return status;
-}
+ // No-inline because this is a slowpath (only when usage tracking is enabled).
+ void IncrementCurrentFieldUsage(uint32_t field_id,
+ bool allowed) PERFETTO_NO_INLINE;
-StatusOr<void> Parser::ParseSelect(
- const protos::pbzero::VmInstruction::Decoder& instruction) {
- auto saved_cursors = cursors_;
- cursors_.innermost_saved_dst = &saved_cursors.dst;
+ // Gets into an error state which swallows all the input and emits no output.
+ void SetUnrecoverableErrorState();
- protos::pbzero::VmOpSelect::Decoder select(instruction.select());
- cursors_.selected = !select.has_cursor()
- ? CursorEnum::VM_CURSOR_SRC
- : static_cast<CursorEnum>(select.cursor());
- cursors_.create_if_not_exist = select.create_if_not_exist();
+ // We keep track of the nest of messages in a stack. Each StackState
+ // object corresponds to a level of nesting in the proto message structure.
+ // Every time a new field of type len-delimited that has a corresponding
+ // sub-message in the bytecode is encountered, a new StackState is pushed in
+ // |stack_|. stack_[0] is a sentinel to prevent over-popping without adding
+ // extra branches in the fastpath.
+ // |stack_|. stack_[1] is the state of the root message.
+ struct StackState {
+ uint32_t in_bytes = 0; // Number of input bytes processed.
- if (cursors_.selected == CursorEnum::VM_CURSOR_SRC &&
- cursors_.create_if_not_exist) {
- PROTOVM_ABORT(
- "incompatible params: src cursor (read only) + create_if_not_exist");
- }
+ // When |in_bytes| reaches this value, the current state should be popped.
+ // This is set when recursing into nested submessages. This is 0 only for
+ // stack_[0] (we don't know the size of the root message upfront).
+ uint32_t in_bytes_limit = 0;
- auto status = ParseSelectRec(instruction, select.relative_path());
- cursors_ = saved_cursors;
+ // This is set when a len-delimited message is encountered, either a string
+ // or a nested submessage that is NOT allow-listed in the bytecode.
+ // This causes input bytes to be consumed without being parsed from the
+ // input stream. If |passthrough_eaten_bytes| == true, they will be copied
+ // as-is in output (e.g. in the case of an allowed string/bytes field).
+ uint32_t eat_next_bytes = 0;
- return status;
-}
+ // Keeps tracks of the stream_writer output counter (out_.written()) then
+ // the StackState is pushed. This is used to work out, when popping, how
+ // many bytes have been written for the current submessage.
+ uint32_t out_bytes_written_at_start = 0;
-StatusOr<void> Parser::ParseSelectRec(
- const protos::pbzero::VmInstruction::Decoder& instruction,
- protozero::RepeatedFieldIterator<protozero::ConstBytes> it_path_component) {
- protos::pbzero::VmOpSelect::Decoder select(instruction.select());
+ uint32_t field_id = 0; // The proto field id for the current message.
+ uint32_t msg_index = 0; // The index of the message filter in the bytecode.
- bool has_entered_all_path_components = !it_path_component;
- if (has_entered_all_path_components) {
- return ParseInstructions(instruction.nested_instructions());
- }
+ // This is a pointer to the proto preamble for the current submessage
+ // (it's nullptr for stack_[0] and non-null elsewhere). This will be filled
+ // with the actual size of the message (out_.written() -
+ // |out_bytes_written_at_start|) when finishing (popping) the message.
+ // This must be filled using WriteRedundantVarint(). Note that the
+ // |size_field_len| is variable and depends on the actual length of the
+ // input message. If the output message has roughly the same size of the
+ // input message, the length will not be redundant.
+ // In other words: the length of the field is reserved when the submessage
+ // starts. At that point we know the upper-bound for the output message
+ // (a filtered submessage can be <= the original one, but not >). So we
+ // reserve as many bytes it takes to write the input length in varint.
+ // Then, when the message is finalized and we know the actual output size
+ // we backfill the field.
+ // Consider the example of a submessage where the input size = 130 (>127,
+ // 2 varint bytes) and the output is 120 bytes. The length will be 2 bytes
+ // wide even though could have been encoded with just one byte.
+ uint8_t* size_field = nullptr;
+ uint32_t size_field_len = 0;
- auto curr_component =
- protos::pbzero::VmOpSelect::PathComponent::Decoder(*it_path_component);
- ++it_path_component;
+ // The pointer to the start of the string to update the string if it is
+ // filtered.
+ uint8_t* filter_string_ptr = nullptr;
- std::optional<protos::pbzero::VmOpSelect::PathComponent::Decoder>
- next_component =
- it_path_component
- ? std::make_optional(
- protos::pbzero::VmOpSelect::PathComponent::Decoder(
- *it_path_component))
- : std::nullopt;
+ // The semantic type of the string field being filtered (0 = unspecified).
+ uint32_t filter_string_semantic_type = 0;
- if (!curr_component.has_field_id()) {
- PROTOVM_ABORT("Invalid path. Expected path component with field_id.");
- }
+ // How |eat_next_bytes| should be handled. It seems that keeping this field
+ // at the end rather than next to |eat_next_bytes| makes the filter a little
+ // (but measurably) faster. (likely something related with struct layout vs
+ // cache sizes).
+ enum FilterAction {
+ kDrop,
+ kPassthrough,
+ kFilterString,
+ };
+ FilterAction action = FilterAction::kDrop;
+ };
- // iterate repeated field
- if (curr_component.is_repeated()) {
- if (cursors_.selected == CursorEnum::VM_CURSOR_SRC) {
- auto status_or_it = executor_->IterateRepeatedField(
- &cursors_.src, curr_component.field_id());
- PROTOVM_RETURN_IF_NOT_OK(status_or_it, "iterate repeated field (id = %d)",
- static_cast<int>(curr_component.field_id()));
- int index = 0;
- for (auto it = *status_or_it; it; ++it) {
- cursors_.src = *it;
- auto status = ParseSelectRec(instruction, it_path_component);
- PROTOVM_RETURN_IF_NOT_OK(status, "repeated field (id = %d, index = %d)",
- static_cast<int>(curr_component.field_id()),
- index);
- ++index;
- }
- } else if (cursors_.selected == CursorEnum::VM_CURSOR_DST) {
- auto status_or_it = executor_->IterateRepeatedField(
- &cursors_.dst, curr_component.field_id());
- PROTOVM_RETURN_IF_NOT_OK(status_or_it, "iterate repeated field (id = %d)",
- static_cast<int>(curr_component.field_id()));
- int index = 0;
- for (auto it = *status_or_it; it; ++it) {
- cursors_.dst = it.GetCursor();
- auto status = ParseSelectRec(instruction, it_path_component);
- PROTOVM_RETURN_IF_NOT_OK(status, "repeated field (id = %d, index = %d)",
- static_cast<int>(curr_component.field_id()),
- index);
- ++index;
- }
- } else {
- PROTOVM_ABORT(
- "Iteration over selected cursor (%d) is not supported. Should be "
- "either SRC or DST cursor.",
- static_cast<int>(cursors_.selected));
- }
- return StatusOr<void>::Ok();
- }
+ uint32_t out_written() { return static_cast<uint32_t>(out_ - &out_buf_[0]); }
- // enter indexed repeated field
- if (next_component && next_component->has_array_index()) {
- ++it_path_component;
- auto status_enter = executor_->EnterRepeatedFieldAt(
- &cursors_, curr_component.field_id(), next_component->array_index());
- PROTOVM_RETURN_IF_NOT_OK(status_enter, "enter indexed repeated field");
- auto status_select = ParseSelectRec(instruction, it_path_component);
- PROTOVM_RETURN(status_select, "repeated field (id = %d, index = %d)",
- static_cast<int>(curr_component.field_id()),
- static_cast<int>(next_component->array_index()));
- }
+ Config config_;
- // enter mapped repeated field
- if (next_component && next_component->has_map_key_field_id()) {
- ++it_path_component;
- if (!next_component->has_register_to_match()) {
- PROTOVM_ABORT(
- "enter mapped repeated field: expected field 'register_to_match'");
- }
- auto reg_id = static_cast<uint8_t>(next_component->register_to_match());
- auto key = executor_->ReadRegister(reg_id);
- PROTOVM_RETURN_IF_NOT_OK(key, "enter mapped repeated field");
- auto status_enter = executor_->EnterRepeatedFieldByKey(
- &cursors_, curr_component.field_id(),
- next_component->map_key_field_id(), static_cast<uint32_t>(*key));
- PROTOVM_RETURN_IF_NOT_OK(status_enter, "enter mapped repeated field");
- auto status_select = ParseSelectRec(instruction, it_path_component);
- PROTOVM_RETURN(status_select, "mapped repeated field (id = %d, key = %d)",
- static_cast<int>(curr_component.field_id()),
- static_cast<int>(*key));
- }
+ std::unique_ptr<uint8_t[]> out_buf_;
+ uint8_t* out_ = nullptr;
+ uint8_t* out_end_ = nullptr;
- // enter field
- auto status = executor_->EnterField(&cursors_, curr_component.field_id());
- PROTOVM_RETURN_IF_NOT_OK(status, "enter field (id = %d)",
- static_cast<int>(curr_component.field_id()));
+ MessageTokenizer tokenizer_;
+ std::vector<StackState> stack_;
- return ParseSelectRec(instruction, it_path_component);
-}
+ bool error_ = false;
+ bool track_field_usage_ = false;
+ std::unordered_map<std::string, int32_t> field_usage_;
+};
-} // namespace protovm
-} // namespace perfetto
-// gen_amalgamated begin source: src/protovm/ro_cursor.cc
+} // namespace protozero
+
+#endif // SRC_PROTOZERO_FILTERING_MESSAGE_FILTER_H_
/*
- * Copyright (C) 2025 The Android Open Source Project
+ * Copyright (C) 2021 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.
@@ -56264,173 +61131,367 @@ StatusOr<void> Parser::ParseSelectRec(
* limitations under the License.
*/
-// gen_amalgamated expanded: #include "src/protovm/ro_cursor.h"
+// gen_amalgamated expanded: #include "src/protozero/filtering/message_filter.h"
+// gen_amalgamated expanded: #include "perfetto/base/endian.h"
// gen_amalgamated expanded: #include "perfetto/base/logging.h"
// gen_amalgamated expanded: #include "perfetto/protozero/proto_utils.h"
+// gen_amalgamated expanded: #include "src/protozero/filtering/string_filter.h"
+
+namespace protozero {
+
+namespace {
-namespace perfetto {
-namespace protovm {
+// Inline helpers to append proto fields in output. They are the equivalent of
+// the protozero::Message::AppendXXX() fields but don't require building and
+// maintaining a full protozero::Message object or dealing with scattered
+// output slices.
+// All these functions assume there is enough space in the output buffer, which
+// should be always the case assuming that we don't end up generating more
+// output than input.
-RoCursor::RepeatedFieldIterator::RepeatedFieldIterator()
- : decoder_{protozero::ConstBytes{}}, field_id_{0}, field_{Advance()} {
- PERFETTO_DCHECK(!field_.valid());
+inline void AppendVarInt(uint32_t field_id, uint64_t value, uint8_t** out) {
+ *out = proto_utils::WriteVarInt(proto_utils::MakeTagVarInt(field_id), *out);
+ *out = proto_utils::WriteVarInt(value, *out);
}
-RoCursor::RepeatedFieldIterator::RepeatedFieldIterator(
- protozero::ProtoDecoder decoder,
- uint32_t field_id)
- : decoder_(decoder), field_id_(field_id), field_{Advance()} {}
+// For fixed32 / fixed64.
+template <typename INT_T /* uint32_t | uint64_t*/>
+inline void AppendFixed(uint32_t field_id, INT_T value, uint8_t** out) {
+ *out = proto_utils::WriteVarInt(proto_utils::MakeTagFixed<INT_T>(field_id),
+ *out);
+ INT_T le_value = perfetto::base::HostToLE(value);
+ memcpy(*out, &le_value, sizeof(value));
+ *out += sizeof(value);
+}
-RoCursor::RepeatedFieldIterator& RoCursor::RepeatedFieldIterator::operator++() {
- field_ = Advance();
- return *this;
+// For length-delimited (string, bytes) fields. Note: this function appends only
+// the proto preamble and the varint field that states the length of the payload
+// not the payload itself.
+// In the case of submessages, the caller needs to re-write the length at the
+// end in the in the returned memory area.
+// The problem here is that, because of filtering, the length of a submessage
+// might be < original length (the original length is still an upper-bound).
+// Returns a pair with: (1) the pointer where the final length should be written
+// into, (2) the length of the size field.
+// The caller must write a redundant varint to match the original size (i.e.
+// needs to use WriteRedundantVarInt()).
+inline std::pair<uint8_t*, uint32_t> AppendLenDelim(uint32_t field_id,
+ uint32_t len,
+ uint8_t** out) {
+ *out = proto_utils::WriteVarInt(proto_utils::MakeTagLengthDelimited(field_id),
+ *out);
+ uint8_t* size_field_start = *out;
+ *out = proto_utils::WriteVarInt(len, *out);
+ const size_t size_field_len = static_cast<size_t>(*out - size_field_start);
+ return std::make_pair(size_field_start, size_field_len);
}
+} // namespace
-RoCursor RoCursor::RepeatedFieldIterator::operator*() {
- return RoCursor(field_);
+MessageFilter::MessageFilter(Config config) : config_(std::move(config)) {
+ // Push a state on the stack for the implicit root message.
+ stack_.emplace_back();
}
-RoCursor::RepeatedFieldIterator::operator bool() const {
- return field_.valid();
+MessageFilter::MessageFilter() : MessageFilter(Config()) {}
+
+MessageFilter::~MessageFilter() = default;
+
+bool MessageFilter::Config::LoadFilterBytecode(const void* filter_data,
+ size_t len,
+ const void* overlay_data,
+ size_t overlay_len) {
+ return filter_.Load(filter_data, len, overlay_data, overlay_len);
}
-protozero::Field RoCursor::RepeatedFieldIterator::Advance() {
- auto field = decoder_.ReadField();
- while (field) {
- if (field.id() == field_id_) {
- break;
- }
- field = decoder_.ReadField();
+bool MessageFilter::Config::SetFilterRoot(
+ std::initializer_list<uint32_t> field_ids) {
+ uint32_t root_msg_idx = 0;
+ for (uint32_t field_id : field_ids) {
+ auto res = filter_.Query(root_msg_idx, field_id);
+ if (!res.allowed || !res.nested_msg_field())
+ return false;
+ root_msg_idx = res.nested_msg_index;
}
- return field;
+ root_msg_index_ = root_msg_idx;
+ return true;
}
-RoCursor::RoCursor() = default;
+MessageFilter::FilteredMessage MessageFilter::FilterMessageFragments(
+ const InputSlice* slices,
+ size_t num_slices) {
+ // First compute the upper bound for the output. The filtered message cannot
+ // be > the original message.
+ uint32_t total_len = 0;
+ for (size_t i = 0; i < num_slices; ++i)
+ total_len += slices[i].len;
+ out_buf_.reset(new uint8_t[total_len]);
+ out_ = out_buf_.get();
+ out_end_ = out_ + total_len;
-RoCursor::RoCursor(protozero::ConstBytes data) : data_{data} {}
+ // Reset the parser state.
+ tokenizer_ = MessageTokenizer();
+ error_ = false;
+ stack_.clear();
+ stack_.resize(2);
+ // stack_[0] is a sentinel and should never be hit in nominal cases. If we
+ // end up there we will just keep consuming the input stream and detecting
+ // at the end, without hurting the fastpath.
+ stack_[0].in_bytes_limit = UINT32_MAX;
+ stack_[0].eat_next_bytes = UINT32_MAX;
+ // stack_[1] is the actual root message.
+ stack_[1].in_bytes_limit = total_len;
+ stack_[1].msg_index = config_.root_msg_index();
-RoCursor::RoCursor(protozero::Field data) : data_{data} {}
+ // Process the input data and write the output.
+ for (size_t slice_idx = 0; slice_idx < num_slices; ++slice_idx) {
+ const InputSlice& slice = slices[slice_idx];
+ const uint8_t* data = static_cast<const uint8_t*>(slice.data);
+ for (size_t i = 0; i < slice.len; ++i)
+ FilterOneByte(data[i]);
+ }
-StatusOr<void> RoCursor::EnterField(uint32_t field_id) {
- auto status_or_data = GetLengthDelimitedData();
- PROTOVM_RETURN_IF_NOT_OK(status_or_data);
+ // Construct the output object.
+ PERFETTO_CHECK(out_ >= out_buf_.get() && out_ <= out_end_);
+ auto used_size = static_cast<size_t>(out_ - out_buf_.get());
+ FilteredMessage res{std::move(out_buf_), used_size};
+ res.error = error_;
+ if (stack_.size() != 1 || !tokenizer_.idle() ||
+ stack_[0].in_bytes != total_len) {
+ res.error = true;
+ }
+ return res;
+}
- protozero::ProtoDecoder decoder(*status_or_data);
+void MessageFilter::FilterOneByte(uint8_t octet) {
+ PERFETTO_DCHECK(!stack_.empty());
- for (auto field = decoder.ReadField(); field.valid();
- field = decoder.ReadField()) {
- if (field.id() == field_id) {
- data_ = field;
- return StatusOr<void>::Ok();
+ auto* state = &stack_.back();
+ StackState next_state{};
+ bool push_next_state = false;
+
+ if (state->eat_next_bytes > 0) {
+ // This is the case where the previous tokenizer_.Push() call returned a
+ // length delimited message which is NOT a submessage (a string or a bytes
+ // field). We just want to consume it, and pass it through/filter strings
+ // if the field was allowed.
+ --state->eat_next_bytes;
+ if (state->action == StackState::kPassthrough) {
+ *(out_++) = octet;
+ } else if (state->action == StackState::kFilterString) {
+ *(out_++) = octet;
+ if (state->eat_next_bytes == 0) {
+ config_.string_filter().MaybeFilter(
+ reinterpret_cast<char*>(state->filter_string_ptr),
+ static_cast<size_t>(out_ - state->filter_string_ptr),
+ state->filter_string_semantic_type);
+ }
}
- }
+ } else {
+ MessageTokenizer::Token token = tokenizer_.Push(octet);
+ // |token| will not be valid() in most cases and this is WAI. When pushing
+ // a varint field, only the last byte yields a token, all the other bytes
+ // return an invalid token, they just update the internal tokenizer state.
+ if (token.valid()) {
+ auto filter = config_.filter().Query(state->msg_index, token.field_id);
+ switch (token.type) {
+ case proto_utils::ProtoWireType::kVarInt:
+ if (filter.allowed && filter.simple_field())
+ AppendVarInt(token.field_id, token.value, &out_);
+ break;
+ case proto_utils::ProtoWireType::kFixed32:
+ if (filter.allowed && filter.simple_field())
+ AppendFixed(token.field_id, static_cast<uint32_t>(token.value),
+ &out_);
+ break;
+ case proto_utils::ProtoWireType::kFixed64:
+ if (filter.allowed && filter.simple_field())
+ AppendFixed(token.field_id, static_cast<uint64_t>(token.value),
+ &out_);
+ break;
+ case proto_utils::ProtoWireType::kLengthDelimited:
+ // Here we have two cases:
+ // A. A simple string/bytes field: we just want to consume the next
+ // bytes (the string payload), optionally passing them through in
+ // output if the field is allowed.
+ // B. This is a nested submessage. In this case we want to recurse and
+ // push a new state on the stack.
+ // Note that we can't tell the difference between a
+ // "non-allowed string" and a "non-allowed submessage". But it doesn't
+ // matter because in both cases we just want to skip the next N bytes.
+ const auto submessage_len = static_cast<uint32_t>(token.value);
+ auto in_bytes_left = state->in_bytes_limit - state->in_bytes - 1;
+ if (PERFETTO_UNLIKELY(submessage_len > in_bytes_left)) {
+ // This is a malicious / malformed string/bytes/submessage that
+ // claims to be larger than the outer message that contains it.
+ return SetUnrecoverableErrorState();
+ }
- return StatusOr<void>::Error();
-}
+ if (filter.allowed && filter.nested_msg_field() &&
+ submessage_len > 0) {
+ // submessage_len == 0 is the edge case of a message with a 0-len
+ // (but present) submessage. In this case, if allowed, we don't want
+ // to push any further state (doing so would desync the FSM) but we
+ // still want to emit it.
+ // At this point |submessage_len| is only an upper bound. The
+ // final message written in output can be <= the one in input,
+ // only some of its fields might be allowed (also remember that
+ // this class implicitly removes redundancy varint encoding of
+ // len-delimited field lengths). The final length varint (the
+ // return value of AppendLenDelim()) will be filled when popping
+ // from |stack_|.
+ auto size_field =
+ AppendLenDelim(token.field_id, submessage_len, &out_);
+ push_next_state = true;
+ next_state.field_id = token.field_id;
+ next_state.msg_index = filter.nested_msg_index;
+ next_state.in_bytes_limit = submessage_len;
+ next_state.size_field = size_field.first;
+ next_state.size_field_len = size_field.second;
+ next_state.out_bytes_written_at_start = out_written();
+ } else {
+ // A string or bytes field, or a 0 length submessage.
+ state->eat_next_bytes = submessage_len;
+ if (filter.allowed && filter.filter_string_field()) {
+ state->action = StackState::kFilterString;
+ AppendLenDelim(token.field_id, submessage_len, &out_);
+ state->filter_string_ptr = out_;
+ state->filter_string_semantic_type = filter.semantic_type;
+ } else if (filter.allowed) {
+ state->action = StackState::kPassthrough;
+ AppendLenDelim(token.field_id, submessage_len, &out_);
+ } else {
+ state->action = StackState::kDrop;
+ }
+ }
+ break;
+ } // switch(type)
-StatusOr<void> RoCursor::EnterRepeatedFieldAt(uint32_t field_id,
- uint32_t index) {
- auto status_or_data = GetLengthDelimitedData();
- PROTOVM_RETURN_IF_NOT_OK(status_or_data);
+ if (PERFETTO_UNLIKELY(track_field_usage_)) {
+ IncrementCurrentFieldUsage(token.field_id, filter.allowed);
+ }
+ } // if (token.valid)
+ } // if (eat_next_bytes == 0)
- protozero::ProtoDecoder decoder(*status_or_data);
+ ++state->in_bytes;
+ while (state->in_bytes >= state->in_bytes_limit) {
+ PERFETTO_DCHECK(state->in_bytes == state->in_bytes_limit);
+ push_next_state = false;
- uint32_t current_index = 0;
+ // We can't possibly write more than we read.
+ const uint32_t msg_bytes_written = static_cast<uint32_t>(
+ out_written() - state->out_bytes_written_at_start);
+ PERFETTO_DCHECK(msg_bytes_written <= state->in_bytes_limit);
- for (auto field = decoder.ReadField(); field.valid();
- field = decoder.ReadField()) {
- if (field.id() != field_id) {
- continue;
- }
+ // Backfill the length field of the
+ proto_utils::WriteRedundantVarInt(msg_bytes_written, state->size_field,
+ state->size_field_len);
- if (current_index == index) {
- data_ = field.as_bytes();
- return StatusOr<void>::Ok();
+ const uint32_t in_bytes_processes_for_last_msg = state->in_bytes;
+ stack_.pop_back();
+ PERFETTO_CHECK(!stack_.empty());
+ state = &stack_.back();
+ state->in_bytes += in_bytes_processes_for_last_msg;
+ if (PERFETTO_UNLIKELY(!tokenizer_.idle())) {
+ // If we hit this case, it means that we got to the end of a submessage
+ // while decoding a field. We can't recover from this and we don't want to
+ // propagate a broken sub-message.
+ return SetUnrecoverableErrorState();
}
-
- ++current_index;
}
- return StatusOr<void>::Error();
+ if (push_next_state) {
+ PERFETTO_DCHECK(tokenizer_.idle());
+ stack_.emplace_back(std::move(next_state));
+ state = &stack_.back();
+ }
}
-StatusOr<RoCursor::RepeatedFieldIterator> RoCursor::IterateRepeatedField(
- uint32_t field_id) const {
- auto status_or_data = GetLengthDelimitedData();
- PROTOVM_RETURN_IF_NOT_OK(status_or_data);
- protozero::ProtoDecoder decoder(*status_or_data);
- return RepeatedFieldIterator(decoder, field_id);
+void MessageFilter::SetUnrecoverableErrorState() {
+ error_ = true;
+ stack_.clear();
+ stack_.resize(1);
+ auto& state = stack_[0];
+ state.eat_next_bytes = UINT32_MAX;
+ state.in_bytes_limit = UINT32_MAX;
+ state.action = StackState::kDrop;
+ out_ = out_buf_.get(); // Reset the write pointer.
}
-bool RoCursor::IsScalar() const {
- auto* field = std::get_if<protozero::Field>(&data_);
- if (!field) {
- return false;
- }
+void MessageFilter::IncrementCurrentFieldUsage(uint32_t field_id,
+ bool allowed) {
+ // Slowpath. Used mainly in offline tools and tests to workout used fields in
+ // a proto.
+ PERFETTO_DCHECK(track_field_usage_);
- return field->type() == protozero::proto_utils::ProtoWireType::kVarInt ||
- field->type() == protozero::proto_utils::ProtoWireType::kFixed32 ||
- field->type() == protozero::proto_utils::ProtoWireType::kFixed64;
-}
+ // Field path contains a concatenation of varints, one for each nesting level.
+ // e.g. y in message Root { Sub x = 2; }; message Sub { SubSub y = 7; }
+ // is encoded as [varint(2) + varint(7)].
+ // We use varint to take the most out of SSO (small string opt). In most cases
+ // the path will fit in the on-stack 22 bytes, requiring no heap.
+ std::string field_path;
-bool RoCursor::IsBytes() const {
- if (std::holds_alternative<protozero::ConstBytes>(data_)) {
- return true;
- }
+ auto append_field_id = [&field_path](uint32_t id) {
+ uint8_t buf[10];
+ uint8_t* end = proto_utils::WriteVarInt(id, buf);
+ field_path.append(reinterpret_cast<char*>(buf),
+ static_cast<size_t>(end - buf));
+ };
- auto& field = std::get<protozero::Field>(data_);
- return field.type() ==
- protozero::proto_utils::ProtoWireType::kLengthDelimited;
+ // Append all the ancestors IDs from the state stack.
+ // The first entry of the stack has always ID 0 and we skip it (we don't know
+ // the ID of the root message itself).
+ PERFETTO_DCHECK(stack_.size() >= 2 && stack_[1].field_id == 0);
+ for (size_t i = 2; i < stack_.size(); ++i)
+ append_field_id(stack_[i].field_id);
+ // Append the id of the field in the current message.
+ append_field_id(field_id);
+ field_usage_[field_path] += allowed ? 1 : -1;
}
-StatusOr<Scalar> RoCursor::GetScalar() const {
- if (!IsScalar()) {
- PROTOVM_ABORT("Attempted to access length-delimited field as a scalar");
- }
-
- auto& field = std::get<protozero::Field>(data_);
- return Scalar{field.type(), field.as_uint64()};
-}
+} // namespace protozero
+// gen_amalgamated begin source: src/protozero/filtering/message_filter_config.cc
+// gen_amalgamated begin header: src/protozero/filtering/message_filter_config.h
+/*
+ * Copyright (C) 2026 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.
+ */
-StatusOr<protozero::ConstBytes> RoCursor::GetBytes() const {
- if (std::holds_alternative<protozero::ConstBytes>(data_)) {
- return std::get<protozero::ConstBytes>(data_);
- }
+#ifndef SRC_PROTOZERO_FILTERING_MESSAGE_FILTER_CONFIG_H_
+#define SRC_PROTOZERO_FILTERING_MESSAGE_FILTER_CONFIG_H_
- auto& field = std::get<protozero::Field>(data_);
- if (field.type() != protozero::proto_utils::ProtoWireType::kLengthDelimited) {
- PROTOVM_ABORT(
- "Attempted to access field as length-delimited but actual wire "
- "type is "
- "%u",
- static_cast<uint32_t>(field.type()));
- }
+// gen_amalgamated expanded: #include "perfetto/base/status.h"
+// gen_amalgamated expanded: #include "protos/perfetto/config/trace_config.gen.h"
+// gen_amalgamated expanded: #include "src/protozero/filtering/message_filter.h"
- return field.as_bytes();
-}
+namespace protozero {
-StatusOr<protozero::ConstBytes> RoCursor::GetLengthDelimitedData() const {
- if (std::holds_alternative<protozero::Field>(data_)) {
- auto& field = std::get<protozero::Field>(data_);
- if (field.type() !=
- protozero::proto_utils::ProtoWireType::kLengthDelimited) {
- PROTOVM_ABORT(
- "Attempted to access field as length-delimited, but actual "
- "wire type is %u",
- static_cast<uint32_t>(field.type()));
- }
- return field.as_bytes();
- }
+// Loads a MessageFilter from the trace_filter field of a TraceConfig.
+// This sets up the string filter rules (both base and v54 chains) and loads
+// the bytecode (v1/v2 + v54 overlay).
+// On failure, returns a non-ok status with a descriptive error message.
+// On success, the caller may optionally call SetFilterRoot() to adjust the
+// root message (e.g. for per-packet filtering in the tracing service).
+perfetto::base::Status LoadMessageFilterConfig(
+ const perfetto::protos::gen::TraceConfig::TraceFilter& filt,
+ MessageFilter* filter);
- return std::get<protozero::ConstBytes>(data_);
-}
+} // namespace protozero
-} // namespace protovm
-} // namespace perfetto
-// gen_amalgamated begin source: src/protovm/rw_proto.cc
+#endif // SRC_PROTOZERO_FILTERING_MESSAGE_FILTER_CONFIG_H_
/*
- * Copyright (C) 2025 The Android Open Source Project
+ * Copyright (C) 2026 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.
@@ -56445,101 +61506,119 @@ StatusOr<protozero::ConstBytes> RoCursor::GetLengthDelimitedData() const {
* limitations under the License.
*/
-// gen_amalgamated expanded: #include "src/protovm/rw_proto.h"
+// gen_amalgamated expanded: #include "src/protozero/filtering/message_filter_config.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/message.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/proto_utils.h"
+#include <cstdint>
+#include <optional>
+#include <string>
-namespace perfetto {
-namespace protovm {
+// gen_amalgamated expanded: #include "perfetto/base/status.h"
+// gen_amalgamated expanded: #include "protos/perfetto/config/trace_config.gen.h"
+// gen_amalgamated expanded: #include "src/protozero/filtering/message_filter.h"
+// gen_amalgamated expanded: #include "src/protozero/filtering/string_filter.h"
-RwProto::RwProto(Allocator* allocator)
- : allocator_{allocator}, root_{Node::Empty{}} {}
+namespace protozero {
-RwProto::~RwProto() {
- allocator_->DeleteReferencedData(&root_);
-}
+namespace {
-RwProto::Cursor RwProto::GetRoot() {
- return Cursor{&root_, allocator_};
-}
+using TraceFilter = perfetto::protos::gen::TraceConfig::TraceFilter;
+using StringFilterRule = TraceFilter::StringFilterRule;
-void RwProto::Serialize(protozero::Message* proto) const {
- if (root_.GetIf<Node::Empty>()) {
- return;
+std::optional<StringFilter::Policy> ConvertPolicy(
+ TraceFilter::StringFilterPolicy policy) {
+ switch (policy) {
+ case TraceFilter::SFP_UNSPECIFIED:
+ return std::nullopt;
+ case TraceFilter::SFP_MATCH_REDACT_GROUPS:
+ return StringFilter::Policy::kMatchRedactGroups;
+ case TraceFilter::SFP_ATRACE_MATCH_REDACT_GROUPS:
+ return StringFilter::Policy::kAtraceMatchRedactGroups;
+ case TraceFilter::SFP_MATCH_BREAK:
+ return StringFilter::Policy::kMatchBreak;
+ case TraceFilter::SFP_ATRACE_MATCH_BREAK:
+ return StringFilter::Policy::kAtraceMatchBreak;
+ case TraceFilter::SFP_ATRACE_REPEATED_SEARCH_REDACT_GROUPS:
+ return StringFilter::Policy::kAtraceRepeatedSearchRedactGroups;
}
+ return std::nullopt;
+}
- if (auto* bytes = root_.GetIf<Node::Bytes>()) {
- proto->AppendRawProtoBytes(bytes->data.get(), bytes->size);
- return;
+std::optional<StringFilter::SemanticTypeMask> ConvertSemanticTypeMask(
+ const StringFilterRule& rule) {
+ // UNSPECIFIED (0) is treated as its own category - it only matches rules
+ // that explicitly include bit 0 in their mask. If no semantic types are
+ // specified, default to matching only UNSPECIFIED (bit 0).
+ if (rule.semantic_type().empty()) {
+ return StringFilter::SemanticTypeMask::Unspecified();
}
-
- auto* message = root_.GetIf<Node::Message>();
- PERFETTO_DCHECK(message);
-
- for (auto it = message->field_id_to_node.begin(); it; ++it) {
- auto field_id = static_cast<uint32_t>(it->key);
- SerializeField(field_id, *it->value, proto);
+ StringFilter::SemanticTypeMask mask;
+ for (const auto& type : rule.semantic_type()) {
+ auto semantic_type = static_cast<uint32_t>(type);
+ if (semantic_type >= StringFilter::SemanticTypeMask::kLimit) {
+ return std::nullopt;
+ }
+ mask.Set(semantic_type);
}
+ return mask;
}
-void RwProto::SerializeField(uint32_t field_id,
- const Node& node,
- protozero::Message* proto) const {
- if (node.GetIf<Node::Empty>()) {
- return;
- }
+} // namespace
- if (auto* bytes = node.GetIf<Node::Bytes>()) {
- proto->AppendBytes(field_id, bytes->data.get(), bytes->size);
- return;
- }
+perfetto::base::Status LoadMessageFilterConfig(const TraceFilter& filt,
+ MessageFilter* filter) {
+ StringFilter& string_filter = filter->string_filter();
- if (auto* scalar = node.GetIf<Scalar>()) {
- if (scalar->wire_type == protozero::proto_utils::ProtoWireType::kFixed32) {
- proto->AppendFixed(field_id, static_cast<uint32_t>(scalar->value));
- return;
+ auto add_rule = [&](const auto& rule) -> perfetto::base::Status {
+ auto policy = ConvertPolicy(rule.policy());
+ if (!policy.has_value()) {
+ return perfetto::base::ErrStatus(
+ "Trace filter has invalid string filtering rules");
}
-
- if (scalar->wire_type == protozero::proto_utils::ProtoWireType::kFixed64) {
- proto->AppendFixed(field_id, static_cast<uint64_t>(scalar->value));
- return;
+ auto semantic_type = ConvertSemanticTypeMask(rule);
+ if (!semantic_type.has_value()) {
+ return perfetto::base::ErrStatus(
+ "Trace filter has invalid semantic types in string filtering rules");
}
+ string_filter.AddRule(*policy, rule.regex_pattern(),
+ rule.atrace_payload_starts_with(), rule.name(),
+ *semantic_type);
+ return perfetto::base::OkStatus();
+ };
- proto->AppendVarInt(field_id, scalar->value);
- return;
+ // Load base string filter chain.
+ for (const auto& rule : filt.string_filter_chain().rules()) {
+ auto status = add_rule(rule);
+ if (!status.ok())
+ return status;
}
- if (auto* message = node.GetIf<Node::Message>()) {
- auto* message_proto =
- proto->BeginNestedMessage<protozero::Message>(field_id);
-
- for (auto it = message->field_id_to_node.begin(); it; ++it) {
- auto message_field_id = static_cast<uint32_t>(it->key);
- SerializeField(message_field_id, *it->value, message_proto);
- }
+ // Load v54 string filter chain. Rules with matching names will replace
+ // existing rules; others will be appended.
+ for (const auto& rule : filt.string_filter_chain_v54().rules()) {
+ auto status = add_rule(rule);
+ if (!status.ok())
+ return status;
}
- if (node.GetIf<Node::IndexedRepeatedField>() ||
- node.GetIf<Node::MappedRepeatedField>()) {
- const IntrusiveMap* map;
- if (auto* indexed = node.GetIf<Node::IndexedRepeatedField>()) {
- map = &indexed->index_to_node;
- } else {
- map = &node.GetIf<Node::MappedRepeatedField>()->key_to_node;
- }
-
- for (auto it = map->begin(); it; ++it) {
- SerializeField(field_id, *it->value, proto);
- }
+ const std::string& bytecode_v1 = filt.bytecode();
+ const std::string& bytecode_v2 = filt.bytecode_v2();
+ const std::string& bytecode = bytecode_v2.empty() ? bytecode_v1 : bytecode_v2;
+ const std::string& overlay = filt.bytecode_overlay_v54();
+ if (!filter->LoadFilterBytecode(bytecode.data(), bytecode.size(),
+ overlay.empty() ? nullptr : overlay.data(),
+ overlay.size())) {
+ return perfetto::base::ErrStatus("Trace filter bytecode invalid");
}
+
+ return perfetto::base::OkStatus();
}
-} // namespace protovm
-} // namespace perfetto
-// gen_amalgamated begin source: src/protovm/rw_proto_cursor.cc
+} // namespace protozero
+// gen_amalgamated begin source: src/tracing/service/proto_group_rewriter.cc
+// gen_amalgamated begin header: src/tracing/service/proto_group_rewriter.h
+// gen_amalgamated begin header: include/perfetto/ext/base/small_vector.h
/*
- * Copyright (C) 2025 The Android Open Source Project
+ * Copyright (C) 2021 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.
@@ -56554,695 +61633,875 @@ void RwProto::SerializeField(uint32_t field_id,
* limitations under the License.
*/
-// gen_amalgamated expanded: #include "src/protovm/rw_proto_cursor.h"
-
-// gen_amalgamated expanded: #include "perfetto/protozero/proto_decoder.h"
-// gen_amalgamated expanded: #include "src/protovm/error_handling.h"
-
-namespace perfetto {
-namespace protovm {
-
-RwProtoCursor::RepeatedFieldIterator::RepeatedFieldIterator()
- : allocator_{nullptr}, it_{} {}
-
-RwProtoCursor::RepeatedFieldIterator::RepeatedFieldIterator(
- Allocator* allocator,
- IntrusiveMap::Iterator it)
- : allocator_{allocator}, it_{it} {}
-
-RwProtoCursor::RepeatedFieldIterator&
-RwProtoCursor::RepeatedFieldIterator::RepeatedFieldIterator::operator++() {
- ++it_;
- return *this;
-}
-
-RwProtoCursor RwProtoCursor::RepeatedFieldIterator::GetCursor() {
- return RwProtoCursor{it_->value.get(), allocator_};
-}
-
-RwProtoCursor::RepeatedFieldIterator::operator bool() const {
- return static_cast<bool>(it_);
-}
-
-RwProtoCursor::RwProtoCursor() = default;
-
-RwProtoCursor::RwProtoCursor(Node* node, Allocator* allocator)
- : node_{node}, allocator_{allocator} {}
-
-bool RwProtoCursor::operator==(const RwProtoCursor& other) const {
- return node_ == other.node_;
-}
-bool RwProtoCursor::operator!=(const RwProtoCursor& other) const {
- return !(*this == other);
-}
+#ifndef INCLUDE_PERFETTO_EXT_BASE_SMALL_VECTOR_H_
+#define INCLUDE_PERFETTO_EXT_BASE_SMALL_VECTOR_H_
-StatusOr<bool> RwProtoCursor::IsRoot() const {
- PROTOVM_RETURN_IF_NOT_OK(CheckIsValid());
- return parent_link_.node == nullptr;
-}
+#include <algorithm>
+#include <type_traits>
+#include <utility>
-StatusOr<bool> RwProtoCursor::HasField(uint32_t field_id) {
- PROTOVM_RETURN_IF_NOT_OK(CheckIsValid());
+// gen_amalgamated expanded: #include "perfetto/base/compiler.h"
+// gen_amalgamated expanded: #include "perfetto/base/logging.h"
+// gen_amalgamated expanded: #include "perfetto/ext/base/utils.h"
- // Eagerly decompose bytes because the field being tested will be entered
- // later anyways. See Executor::EnterField().
- auto status = ConvertToMessageIfNeeded(node_);
- PROTOVM_RETURN_IF_NOT_OK(status);
- auto* message = node_->GetIf<Node::Message>();
- bool found = static_cast<bool>(message->field_id_to_node.Find(field_id));
- return found;
-}
+namespace perfetto {
+namespace base {
-StatusOr<void> RwProtoCursor::EnterField(uint32_t field_id) {
- PROTOVM_RETURN_IF_NOT_OK(CheckIsValid());
+// Uses inline storage first, switches to dynamic storage when it overflows.
+template <typename T, size_t kSize>
+class SmallVector {
+ public:
+ static constexpr size_t kInlineSize = kSize;
- auto status_or_it = FindOrCreateMessageField(node_, field_id);
- PROTOVM_RETURN_IF_NOT_OK(status_or_it);
- auto it = *status_or_it;
+ explicit SmallVector() = default;
- if (it->value->GetIf<Node::IndexedRepeatedField>()) {
- PROTOVM_ABORT(
- "Attempted to enter field (id=%u) as a simple field but it is an "
- "indexed repeated field",
- field_id);
+ ~SmallVector() {
+ clear();
+ if (PERFETTO_UNLIKELY(is_using_heap()))
+ AlignedFree(begin_);
+ begin_ = end_ = end_of_storage_ = nullptr;
}
- if (it->value->GetIf<Node::MappedRepeatedField>()) {
- PROTOVM_ABORT(
- "Attempted to enter field (id=%u) as a simple field but it is a "
- "mapped repeated field",
- field_id);
+ // Move operators.
+ SmallVector(SmallVector&& other) noexcept(
+ std::is_nothrow_move_constructible<T>::value) {
+ if (other.is_using_heap()) {
+ // Move the heap content, no need to move the individual objects as their
+ // location won't change.
+ begin_ = other.begin_;
+ end_ = other.end_;
+ end_of_storage_ = other.end_of_storage_;
+ } else {
+ const size_t other_size = other.size();
+ PERFETTO_DCHECK(other_size <= capacity());
+ for (size_t i = 0; i < other_size; i++) {
+ // Move the entries and destroy the ones in the moved-from object.
+ new (&begin_[i]) T(std::move(other.begin_[i]));
+ other.begin_[i].~T();
+ }
+ end_ = begin_ + other_size;
+ }
+ auto* const other_inline_storage = other.inline_storage_begin();
+ other.end_ = other.begin_ = other_inline_storage;
+ other.end_of_storage_ = other_inline_storage + kInlineSize;
}
- parent_link_ = {node_, &node_->GetIf<Node::Message>()->field_id_to_node,
- std::addressof(*it)};
- node_ = it->value.get();
- return StatusOr<void>::Ok();
-}
-
-StatusOr<void> RwProtoCursor::EnterRepeatedFieldAt(uint32_t field_id,
- uint32_t index) {
- PROTOVM_RETURN_IF_NOT_OK(CheckIsValid());
-
- auto status_or_message_field = FindOrCreateMessageField(node_, field_id);
- PROTOVM_RETURN_IF_NOT_OK(status_or_message_field);
- auto message_field = *status_or_message_field;
+ SmallVector& operator=(SmallVector&& other) noexcept(
+ std::is_nothrow_move_constructible<T>::value) {
+ this->~SmallVector();
+ new (this) SmallVector<T, kSize>(std::move(other));
+ return *this;
+ }
- auto status =
- ConvertToIndexedRepeatedFieldIfNeeded(message_field->value.get());
- PROTOVM_RETURN_IF_NOT_OK(status);
+ // Copy operators.
+ SmallVector(const SmallVector& other) {
+ const size_t other_size = other.size();
+ if (other_size > capacity())
+ Grow(other_size);
+ // Copy-construct the elements.
+ for (size_t i = 0; i < other_size; ++i)
+ new (&begin_[i]) T(other.begin_[i]);
+ end_ = begin_ + other_size;
+ }
- auto status_or_repeated_field =
- FindOrCreateIndexedRepeatedField(message_field->value.get(), index);
- PROTOVM_RETURN_IF_NOT_OK(status_or_repeated_field);
+ SmallVector& operator=(const SmallVector& other) {
+ if (PERFETTO_UNLIKELY(this == &other))
+ return *this;
+ this->~SmallVector();
+ new (this) SmallVector<T, kSize>(other);
+ return *this;
+ }
- parent_link_ = {
- message_field->value.get(),
- &message_field->value->GetIf<Node::IndexedRepeatedField>()->index_to_node,
- std::addressof(**status_or_repeated_field)};
- node_ = (*status_or_repeated_field)->value.get();
+ T* data() { return begin_; }
+ const T* data() const { return begin_; }
- return StatusOr<void>::Ok();
-}
+ T* begin() { return begin_; }
+ const T* begin() const { return begin_; }
-StatusOr<RwProtoCursor::RepeatedFieldIterator>
-RwProtoCursor::IterateRepeatedField(uint32_t field_id) {
- PROTOVM_RETURN_IF_NOT_OK(CheckIsValid());
+ T* end() { return end_; }
+ const T* end() const { return end_; }
- auto status_convertion_to_message = ConvertToMessageIfNeeded(node_);
- PROTOVM_RETURN_IF_NOT_OK(status_convertion_to_message);
+ size_t size() const { return static_cast<size_t>(end_ - begin_); }
- auto* message = node_->GetIf<Node::Message>();
- auto it = message->field_id_to_node.Find(field_id);
+ bool empty() const { return end_ == begin_; }
- if (!it) {
- return RepeatedFieldIterator{};
+ size_t capacity() const {
+ return static_cast<size_t>(end_of_storage_ - begin_);
}
- auto* field = it->value.get();
- auto status_convertion_to_repeated_field =
- ConvertToIndexedRepeatedFieldIfNeeded(field);
- PROTOVM_RETURN_IF_NOT_OK(status_convertion_to_repeated_field);
-
- return RepeatedFieldIterator{
- allocator_,
- field->GetIf<Node::IndexedRepeatedField>()->index_to_node.begin()};
-}
-
-StatusOr<void> RwProtoCursor::EnterRepeatedFieldByKey(uint32_t field_id,
- uint32_t map_key_field_id,
- uint64_t key) {
- PROTOVM_RETURN_IF_NOT_OK(CheckIsValid());
+ T& front() {
+ PERFETTO_DCHECK(!empty());
+ return begin_[0];
+ }
+ const T& front() const {
+ PERFETTO_DCHECK(!empty());
+ return begin_[0];
+ }
- auto status_or_message_field = FindOrCreateMessageField(node_, field_id);
- PROTOVM_RETURN_IF_NOT_OK(status_or_message_field);
- auto message_field = *status_or_message_field;
+ T& back() {
+ PERFETTO_DCHECK(!empty());
+ return end_[-1];
+ }
+ const T& back() const {
+ PERFETTO_DCHECK(!empty());
+ return end_[-1];
+ }
- auto status_conversion = ConvertToMappedRepeatedFieldIfNeeded(
- message_field->value.get(), map_key_field_id);
- PROTOVM_RETURN_IF_NOT_OK(status_conversion);
+ T& operator[](size_t index) {
+ PERFETTO_DCHECK(index < size());
+ return begin_[index];
+ }
- auto status_or_repeated_field =
- FindOrCreateMappedRepeatedField(message_field->value.get(), key);
- PROTOVM_RETURN_IF_NOT_OK(status_or_repeated_field);
+ const T& operator[](size_t index) const {
+ PERFETTO_DCHECK(index < size());
+ return begin_[index];
+ }
- parent_link_ = {
- message_field->value.get(),
- &message_field->value->GetIf<Node::MappedRepeatedField>()->key_to_node,
- std::addressof(**status_or_repeated_field)};
- node_ = (*status_or_repeated_field)->value.get();
+ template <typename... Args>
+ void emplace_back(Args&&... args) {
+ T* end = end_;
+ if (PERFETTO_UNLIKELY(end == end_of_storage_))
+ end = Grow();
+ new (end) T(std::forward<Args>(args)...);
+ end_ = end + 1;
+ }
- return StatusOr<void>::Ok();
-}
+ void pop_back() {
+ PERFETTO_DCHECK(!empty());
+ back().~T();
+ --end_;
+ }
-StatusOr<Scalar> RwProtoCursor::GetScalar() const {
- PROTOVM_RETURN_IF_NOT_OK(CheckIsValid());
+ // Clear without reverting back to inline storage.
+ void clear() {
+ while (!empty())
+ pop_back();
+ }
- auto* scalar = node_->GetIf<Scalar>();
- if (!scalar) {
- PROTOVM_ABORT("Attempted \"get scalar\" operation but node has type %s",
- node_->GetTypeName());
+ private:
+ PERFETTO_NO_INLINE T* Grow(size_t desired_capacity = 0) {
+ size_t cur_size = size();
+ size_t new_capacity = desired_capacity;
+ if (desired_capacity <= cur_size)
+ new_capacity = std::max(capacity() * 2, size_t(128));
+ T* new_storage =
+ static_cast<T*>(AlignedAlloc(alignof(T), new_capacity * sizeof(T)));
+ for (size_t i = 0; i < cur_size; ++i) {
+ // Move the elements into the new heap buffer and destroy the old ones.
+ new (&new_storage[i]) T(std::move(begin_[i]));
+ begin_[i].~T();
+ }
+ if (is_using_heap())
+ AlignedFree(begin_);
+ begin_ = new_storage;
+ end_ = new_storage + cur_size;
+ end_of_storage_ = new_storage + new_capacity;
+ return end_;
}
- return *scalar;
-}
-StatusOr<void> RwProtoCursor::SetBytes(protozero::ConstBytes data) {
- PROTOVM_RETURN_IF_NOT_OK(CheckIsValid());
+ T* inline_storage_begin() { return reinterpret_cast<T*>(inline_storage_); }
+ bool is_using_heap() { return begin_ != inline_storage_begin(); }
- if (bool is_compatible = node_->GetIf<Node::Empty>() ||
- node_->GetIf<Node::Bytes>() ||
- node_->GetIf<Node::Message>();
- !is_compatible) {
- PROTOVM_ABORT("Attempted \"set bytes\" operation but node has type %s",
- node_->GetTypeName());
- }
+ T* begin_ = inline_storage_begin();
+ T* end_ = begin_;
+ T* end_of_storage_ = begin_ + kInlineSize;
- auto status_or_bytes = allocator_->AllocateAndCopyBytes(data);
- PROTOVM_RETURN_IF_NOT_OK(status_or_bytes);
+ alignas(T) char inline_storage_[sizeof(T) * kInlineSize];
+};
- allocator_->DeleteReferencedData(node_);
- node_->value = Node::Bytes{std::move(*status_or_bytes)};
+} // namespace base
+} // namespace perfetto
- return StatusOr<void>::Ok();
-}
+#endif // INCLUDE_PERFETTO_EXT_BASE_SMALL_VECTOR_H_
+/*
+ * Copyright (C) 2026 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.
+ */
-StatusOr<void> RwProtoCursor::SetScalar(Scalar scalar) {
- PROTOVM_RETURN_IF_NOT_OK(CheckIsValid());
+#ifndef SRC_TRACING_SERVICE_PROTO_GROUP_REWRITER_H_
+#define SRC_TRACING_SERVICE_PROTO_GROUP_REWRITER_H_
- if (bool is_compatible =
- node_->GetIf<Node::Empty>() || node_->GetIf<Scalar>();
- !is_compatible) {
- PROTOVM_ABORT("Attempted \"set scalar\" operation but node has type %s",
- node_->GetTypeName());
- }
+#include <stddef.h>
- node_->value = scalar;
- return StatusOr<void>::Ok();
-}
+#include <optional>
-StatusOr<void> RwProtoCursor::Merge(protozero::ConstBytes data,
- uint32_t flags) {
- PROTOVM_RETURN_IF_NOT_OK(CheckIsValid());
+// gen_amalgamated expanded: #include "perfetto/ext/base/small_vector.h"
+// gen_amalgamated expanded: #include "perfetto/ext/tracing/core/slice.h"
- if (bool is_compatible = node_->GetIf<Node::Empty>() ||
- node_->GetIf<Node::Message>() ||
- node_->GetIf<Node::Bytes>();
- !is_compatible) {
- PROTOVM_ABORT("Attempted MERGE operation but node has type %s",
- node_->GetTypeName());
- }
+namespace perfetto::tracing_v2 {
+
+enum class RewriteResult {
+ // The output slice owns the rewritten packet.
+ kRewritten,
+ // The packet has no groups. The caller must keep the input slices.
+ kUnchanged,
+ // The input has an invalid field or unmatched group boundary.
+ // This result also applies above kMaxNestingDepth.
+ kMalformedInput,
+ // A rewritten group exceeds proto_utils::kMaxMessageLength bytes.
+ kGroupTooLarge,
+};
- if (data.size == 0) {
- return StatusOr<void>::Ok();
- }
+// Converts an SMB v2 packet to length-delimited protobuf during readback.
+// The rewriter replaces group boundaries with length-delimited field headers.
+// It keeps the field ID, tag byte count, and all other input bytes unchanged.
+//
+// Input (hex): 0b 10 07 04 field 1 { field 2: 7 }
+// Output: 0a 02 10 07
+// ^ length
+//
+// Only the bare byte 0x04 closes a group. The packet has no root wrapper.
+// The rewriter checks each field but does not parse length-delimited contents.
+// See proto_utils::kProtoGroupEndByte for the input format.
+//
+// Group lengths follow the v1 encoding: one byte for contents up to 127 bytes,
+// or a 4-byte padded varint for larger contents. The maximum is 256 MiB - 1.
+// A packet can have at most kMaxNestingDepth open groups, excluding the root.
+//
+// Each rewritten packet owns its output buffer. Packets without groups need
+// no copy or output allocation. The rewriter never returns partial output.
+class ProtoGroupRewriter {
+ public:
+ // Maximum number of groups open at once.
+ static constexpr size_t kMaxNestingDepth = 1024;
- auto status_convert_to_message = ConvertToMessageIfNeeded(node_);
- PROTOVM_RETURN_IF_NOT_OK(status_convert_to_message);
- auto* message = node_->GetIf<Node::Message>();
+ // Rewrite() converts the packet in |input| to standard protobuf.
+ // Each slice must be nonempty. An empty input list returns kUnchanged.
+ // - On kRewritten, |*output| owns the rewritten packet in a new slice.
+ // - For any other result, Rewrite() keeps |*output| unchanged.
+ RewriteResult Rewrite(const Slices& input, std::optional<Slice>* output);
- protozero::ProtoDecoder decoder(data);
+ private:
+ // Each entry holds the output offset of an open group's length slot.
+ base::SmallVector<size_t, 128> open_group_length_offsets_;
+};
- for (auto field = decoder.ReadField(); field.valid();
- field = decoder.ReadField()) {
- auto it = message->field_id_to_node.Find(field.id());
+} // namespace perfetto::tracing_v2
- bool del_if_src_empty = (flags & kDelIfSrcEmpty) != 0;
- if (it && del_if_src_empty &&
- field.type() ==
- protozero::proto_utils::ProtoWireType::kLengthDelimited &&
- field.size() == 0) {
- // Implements remove submessage semantics: empty src field means delete
- // the dst field
- message->field_id_to_node.Remove(*it);
- allocator_->Delete(&*it);
- continue;
- }
+#endif // SRC_TRACING_SERVICE_PROTO_GROUP_REWRITER_H_
+/*
+ * Copyright (C) 2026 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.
+ */
- bool skip_submessages = (flags & kSkipSubmessages) != 0;
- if (skip_submessages && it && it->value->GetIf<Node::Message>()) {
- // Implements deep merge semantics: skip this message that was already
- // merged by a previous operation
- continue;
- }
+// gen_amalgamated expanded: #include "src/tracing/service/proto_group_rewriter.h"
- auto status_or_map_value = CreateNodeFromField(field);
- PROTOVM_RETURN_IF_NOT_OK(status_or_map_value);
+#include <stddef.h>
+#include <stdint.h>
+#include <string.h>
- if (!it) {
- auto status_or_it = MapInsert(&message->field_id_to_node, field.id(),
- std::move(*status_or_map_value));
- PROTOVM_RETURN_IF_NOT_OK(status_or_it);
- (*status_or_it)->value->has_been_merged = true;
- continue;
- }
+#include <algorithm>
+#include <memory>
+#include <utility>
- if (it->value->GetIf<Node::MappedRepeatedField>()) {
- PROTOVM_ABORT(
- "Merge operation of mapped repeated field is not supported (field id "
- "= %u)",
- field.id());
- }
+// gen_amalgamated expanded: #include "perfetto/base/compiler.h"
+// gen_amalgamated expanded: #include "perfetto/base/logging.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/proto_utils.h"
+// gen_amalgamated expanded: #include "perfetto/public/pb_utils.h"
- // Promote field as repeated if needed:
- // If this is the second time that the same field ID is being merged, then
- // they are a repeated fields and they should live within an
- // IndexedRepeatedField node.
- if (it->value->has_been_merged) {
- auto status_convert_to_indexed =
- ConvertToIndexedRepeatedFieldIfNeeded(it->value.get());
- PROTOVM_RETURN_IF_NOT_OK(status_convert_to_indexed);
- }
+namespace perfetto::tracing_v2 {
+namespace {
- if (auto* indexed_fields = it->value->GetIf<Node::IndexedRepeatedField>()) {
- // Implements merge semantics for repeated fields: all existing fields are
- // removed and replaced with the newly received fields.
- if (!it->value->has_been_merged) {
- // Optimization opportunity: reuse the existing nodes to avoid N
- // allocation-deallocation pairs, where N is the number of newly
- // received repeated fields.
- allocator_->DeleteReferencedData(it->value.get());
- it->value->has_been_merged = true;
- }
- MapInsert(&indexed_fields->index_to_node,
- indexed_fields->index_to_node.Size(),
- std::move(*status_or_map_value));
- continue;
- }
+namespace pu = ::protozero::proto_utils;
+
+// Reads nonempty slices as one byte stream. At the packet end,
+// read_ptr_ equals current_slice_end_.
+class SliceCursor {
+ public:
+ explicit SliceCursor(const Slices& slices)
+ : next_slice_(slices.data()),
+ slice_list_end_(slices.data() + slices.size()) {
+ for (const Slice& slice : slices)
+ input_size_ += slice.size;
- // Optimization oppurtunity: reuse the existing node to avoid one
- // allocation-deallocation pair
- allocator_->Delete(it->value.release());
- it->value = std::move(*status_or_map_value);
- it->value->has_been_merged = true;
+ LoadNextSlice();
}
- // Reset the merge flags
- for (auto& field : message->field_id_to_node) {
- field.value->has_been_merged = false;
- }
+ // Total input bytes across all slices.
+ size_t input_size() const { return input_size_; }
+ size_t offset() const { return offset_; }
+ bool at_end() const { return read_ptr_ == current_slice_end_; }
- return StatusOr<void>::Ok();
-}
+ // Before this call, at_end() must be false.
+ uint8_t PeekByte() const { return *read_ptr_; }
-StatusOr<void> RwProtoCursor::Delete() {
- PROTOVM_RETURN_IF_NOT_OK(CheckIsValid());
+ // Read one varint across slice boundaries. Failure can advance the cursor.
+ bool ReadVarInt(uint64_t* value) {
+ const uint8_t* next_ptr =
+ pu::ParseVarIntFast(read_ptr_, current_slice_end_, value);
+ if (PERFETTO_LIKELY(next_ptr)) {
+ AdvanceTo(next_ptr);
+ return true;
+ }
- PROTOVM_ASSIGN_OR_RETURN(bool is_root, IsRoot());
- if (is_root) {
- node_->value = Node::Empty{};
- return StatusOr<void>::Ok();
- }
+ // No complete varint was found in this slice. If at least 10 bytes
+ // remain, reject it: a 64-bit varint must end within 10 bytes.
+ if (PERFETTO_UNLIKELY(slice_bytes_left() >=
+ PERFETTO_PB_VARINT_MAX_SIZE_64)) {
+ return false;
+ }
- PERFETTO_DCHECK(parent_link_.map);
- PERFETTO_DCHECK(parent_link_.map_node);
+ // Read one byte at a time across slices.
+ // As in ParseVarInt(), only the low bit of the tenth byte contributes.
+ uint64_t decoded_value = 0;
+ for (uint32_t shift = 0; shift < 64 && !at_end(); shift += 7) {
+ const uint8_t byte = *read_ptr_;
+ AdvanceTo(read_ptr_ + 1);
- parent_link_.map->Remove(*parent_link_.map_node);
- allocator_->Delete(parent_link_.map_node);
+ // Place the seven data bits at this byte's bit offset in the value.
+ decoded_value |= static_cast<uint64_t>(byte & 0b0111'1111) << shift;
- // Delete operation invalidates cursor
- node_ = nullptr;
- parent_link_ = {};
+ // A clear high bit marks the last byte of the varint.
+ if ((byte & 0b1000'0000) == 0) {
+ *value = decoded_value;
+ return true;
+ }
+ }
+ return false;
+ }
- return StatusOr<void>::Ok();
-}
+ // Skip bytes across slices. Return false without advancing on truncated
+ // input.
+ bool Skip(uint64_t num_bytes) {
+ if (PERFETTO_LIKELY(num_bytes <= slice_bytes_left())) {
+ AdvanceTo(read_ptr_ + num_bytes);
+ return true;
+ }
+ if (num_bytes > input_bytes_left())
+ return false;
-StatusOr<void> RwProtoCursor::ConvertToMessageIfNeeded(Node* node) {
- if (node->GetIf<Node::Message>()) {
- return StatusOr<void>::Ok();
+ CopyOrSkipAcrossSlices(/*dst=*/nullptr, static_cast<size_t>(num_bytes));
+ return true;
}
- if (node->GetIf<Node::Empty>()) {
- node->value = Node::Message{};
- return StatusOr<void>::Ok();
+ // Copy bytes across slices. The input and |dst| must have enough space.
+ void CopyTo(uint8_t* dst, size_t num_bytes) {
+ PERFETTO_DCHECK(num_bytes <= input_bytes_left());
+ if (PERFETTO_LIKELY(num_bytes <= slice_bytes_left())) {
+ memcpy(dst, read_ptr_, num_bytes);
+ AdvanceTo(read_ptr_ + num_bytes);
+ return;
+ }
+ CopyOrSkipAcrossSlices(dst, num_bytes);
}
- auto* bytes = node->GetIf<Node::Bytes>();
- if (!bytes) {
- PROTOVM_ABORT("Attempted conversion to message but node has type %s",
- node->GetTypeName());
+ private:
+ size_t input_bytes_left() const { return input_size_ - offset(); }
+
+ size_t slice_bytes_left() const {
+ return static_cast<size_t>(current_slice_end_ - read_ptr_);
}
- Node::Message message;
+ // |next_ptr| must be in [read_ptr_, current_slice_end_].
+ // At the slice end, select the next slice, if available.
+ PERFETTO_ALWAYS_INLINE void AdvanceTo(const uint8_t* next_ptr) {
+ PERFETTO_DCHECK(next_ptr >= read_ptr_ && next_ptr <= current_slice_end_);
+ offset_ += static_cast<size_t>(next_ptr - read_ptr_);
+ read_ptr_ = next_ptr;
- protozero::ProtoDecoder decoder(protozero::ConstBytes{
- static_cast<const uint8_t*>(bytes->data.get()), bytes->size});
+ if (PERFETTO_UNLIKELY(read_ptr_ == current_slice_end_))
+ LoadNextSlice();
+ }
- for (auto field = decoder.ReadField(); field.valid();
- field = decoder.ReadField()) {
- auto status_or_map_value = CreateNodeFromField(field);
- if (!status_or_map_value.IsOk()) {
- allocator_->DeleteReferencedData(&message);
- PROTOVM_RETURN(status_or_map_value);
- }
+ void LoadNextSlice() {
+ if (next_slice_ == slice_list_end_)
+ return;
- auto it = message.field_id_to_node.Find(field.id());
+ PERFETTO_DCHECK(next_slice_->size > 0);
+ read_ptr_ = static_cast<const uint8_t*>(next_slice_->start);
+ current_slice_end_ = read_ptr_ + next_slice_->size;
+ ++next_slice_;
+ }
- // First occurrence of this field id. Just insert a new field into the
- // map.
- if (!it) {
- auto status_or_it = MapInsert(&message.field_id_to_node, field.id(),
- std::move(*status_or_map_value));
- if (!status_or_it.IsOk()) {
- allocator_->DeleteReferencedData(&message);
- PROTOVM_RETURN(status_or_it, "Insert message field (id = %u)",
- field.id());
+ // The caller checks the input size. A null |dst| skips bytes without a copy.
+ void CopyOrSkipAcrossSlices(uint8_t* dst, size_t num_bytes) {
+ while (num_bytes > 0) {
+ const size_t chunk_size = std::min(num_bytes, slice_bytes_left());
+ if (dst) {
+ memcpy(dst, read_ptr_, chunk_size);
+ dst += chunk_size;
}
- continue;
+ num_bytes -= chunk_size;
+ AdvanceTo(read_ptr_ + chunk_size);
}
+ }
- // Nth occurrence of this field id:
- // 1. Make sure we have an IndexedRepeatedField node
- // 2. Append into the IndexedRepeatedField's map
- auto status_conversion =
- ConvertToIndexedRepeatedFieldIfNeeded(it->value.get());
- if (!status_conversion.IsOk()) {
- allocator_->DeleteReferencedData(&message);
- allocator_->Delete(status_or_map_value->release());
- PROTOVM_RETURN(status_conversion);
- }
+ // The next slice to load. read_ptr_ already points into the current slice.
+ const Slice* next_slice_;
+ const Slice* const slice_list_end_;
+ const uint8_t* current_slice_end_ = nullptr;
+ const uint8_t* read_ptr_ = nullptr;
+ size_t offset_ = 0;
+ size_t input_size_ = 0;
+};
- auto& index_to_node =
- it->value->GetIf<Node::IndexedRepeatedField>()->index_to_node;
- auto status_or_it = MapInsert(&index_to_node, index_to_node.Size(),
- std::move(*status_or_map_value));
- if (!status_or_it.IsOk()) {
- allocator_->DeleteReferencedData(&message);
- PROTOVM_RETURN(status_or_it,
- "Insert repeated field (id = %u, index = %d)", field.id(),
- static_cast<int>(index_to_node.Size()));
+// Converts group boundaries and copies the input between them.
+// BeginGroup() allocates output on the first group and reserves a length slot.
+// EndGroup() writes the length and removes 3 slot bytes for short messages.
+//
+// Open group: ... | tag | _ _ _ _ | contents ... |
+// Contents <= 127: ... | tag | length | contents ... |
+// Contents > 127: ... | tag | L L L L | contents ... |
+//
+// Group stack offsets stay valid if the output buffer moves.
+class OutputWriter {
+ public:
+ using GroupLengthOffsets = base::SmallVector<size_t, 128>;
+
+ OutputWriter(const SliceCursor& input_cursor,
+ GroupLengthOffsets& group_length_offsets)
+ : copy_cursor_(input_cursor),
+ open_group_length_offsets_(group_length_offsets) {}
+
+ // Convert the start tag. Return false if the group exceeds the nesting limit.
+ bool BeginGroup(size_t tag_start_offset, size_t tag_size) {
+ if (PERFETTO_UNLIKELY(open_group_length_offsets_.size() >=
+ ProtoGroupRewriter::kMaxNestingDepth)) {
+ return false;
}
- }
- allocator_->DeleteReferencedData(node);
- node->value = message;
+ // Copy the input fields before this group's start tag.
+ CopyInputUntil(tag_start_offset);
- return StatusOr<void>::Ok();
-}
+ // Reserve space for the tag and the group's length slot.
+ EnsureAdditionalCapacity(tag_size + pu::kMessageLengthFieldSize);
-StatusOr<OwnedPtr<Node>> RwProtoCursor::CreateNodeFromField(
- protozero::Field field) {
- if (field.type() == protozero::proto_utils::ProtoWireType::kLengthDelimited) {
- auto status_or_bytes = allocator_->AllocateAndCopyBytes(field.as_bytes());
- PROTOVM_RETURN_IF_NOT_OK(status_or_bytes);
- auto status_or_node =
- allocator_->CreateNode<Node::Bytes>(std::move(*status_or_bytes));
- if (!status_or_node.IsOk()) {
- allocator_->DeleteReferencedData(&status_or_bytes.value());
- PROTOVM_RETURN(status_or_node);
- }
+ // Copy the start tag and change its wire type to length-delimited.
+ uint8_t* const tag_ptr = output_buffer_.get() + output_size_;
+ copy_cursor_.CopyTo(tag_ptr, tag_size);
+ // Clear bit 0 to change wire type 3 to 2 while preserving the field ID
+ // and continuation bit in the same byte.
+ PERFETTO_DCHECK(pu::GetTagFieldType(*tag_ptr) == pu::kWireTypeStartGroup);
+ *tag_ptr &= 0b1111'1110;
+ output_size_ += tag_size;
- return std::move(*status_or_node);
+ // Save the length slot offset for EndGroup() and leave space for its value.
+ open_group_length_offsets_.emplace_back(output_size_);
+ output_size_ += pu::kMessageLengthFieldSize;
+ return true;
}
- auto status_or_node =
- allocator_->CreateNode<Scalar>(field.type(), field.as_uint64());
- if (!status_or_node.IsOk()) {
- PROTOVM_RETURN(status_or_node);
+ // Close the innermost group and fill its length slot.
+ RewriteResult EndGroup(size_t end_byte_offset) {
+ if (PERFETTO_UNLIKELY(!HasOpenGroups()))
+ return RewriteResult::kMalformedInput;
+
+ // The group contains output already written and input fields not yet
+ // copied. Measure both parts to calculate the final group length.
+ const size_t group_length_offset = open_group_length_offsets_.back();
+ const size_t group_content_offset =
+ group_length_offset + pu::kMessageLengthFieldSize;
+ const size_t content_bytes_written = output_size_ - group_content_offset;
+ PERFETTO_DCHECK(end_byte_offset >= copy_cursor_.offset());
+ const size_t pending_input_size = end_byte_offset - copy_cursor_.offset();
+
+ // Check both sizes before adding them to prevent overflow.
+ if (PERFETTO_UNLIKELY(content_bytes_written > pu::kMaxMessageLength))
+ return RewriteResult::kGroupTooLarge;
+ const size_t max_pending_bytes =
+ pu::kMaxMessageLength - content_bytes_written;
+ if (PERFETTO_UNLIKELY(pending_input_size > max_pending_bytes)) {
+ return RewriteResult::kGroupTooLarge;
+ }
+ const size_t content_size = content_bytes_written + pending_input_size;
+
+ // Copy the remaining contents and skip the group's end byte.
+ CopyInputUntil(end_byte_offset);
+ copy_cursor_.Skip(1);
+
+ // CopyInputUntil() can allocate a larger buffer and invalidate old
+ // pointers. Use the saved offset to get a pointer into the current buffer.
+ uint8_t* const length_ptr = output_buffer_.get() + group_length_offset;
+
+ // Write the final length into the reserved slot.
+ if (content_size > pu::kMaxOneByteMessageLength) {
+ pu::WriteRedundantVarInt(static_cast<uint32_t>(content_size), length_ptr);
+ } else {
+ // The length needs only one of the four reserved bytes.
+ // Move the contents 3 bytes earlier to close the gap after the length.
+ uint8_t* const content_ptr = output_buffer_.get() + group_content_offset;
+ memmove(length_ptr + 1, content_ptr, content_size);
+ *length_ptr = static_cast<uint8_t>(content_size);
+ output_size_ -= (pu::kMessageLengthFieldSize - 1);
+ }
+
+ // Remove the closed group from the stack.
+ open_group_length_offsets_.pop_back();
+ return RewriteResult::kRewritten;
}
- return std::move(*status_or_node);
-}
+ // Transfer the output after the parser validates and closes all groups.
+ Slice Finish() {
+ PERFETTO_DCHECK(HasRewrittenGroups() && !HasOpenGroups());
-StatusOr<void> RwProtoCursor::ConvertToMappedRepeatedFieldIfNeeded(
- Node* node,
- uint32_t map_key_field_id) {
- if (node->GetIf<Node::MappedRepeatedField>()) {
- return StatusOr<void>::Ok();
+ // Copy any fields after the last group. Input offsets start at zero.
+ CopyInputUntil(copy_cursor_.input_size());
+ return Slice::TakeOwnership(std::move(output_buffer_), output_size_);
}
- if (node->GetIf<Node::Empty>()) {
- node->value = Node::MappedRepeatedField{};
- return StatusOr<void>::Ok();
- }
+ bool HasOpenGroups() const { return !open_group_length_offsets_.empty(); }
- // If the current node contains a message (either raw bytes or a decomposed
- // Node::Message), convert it into a Node::MappedRepeatedField.
- //
- // The process is:
- // 1. Extract the key (identified by 'map_key_field_id') from the message data
- // within the current 'node'.
- // 2. Allocate a new node. The original message content from the current node
- // is moved into this new node.
- // 3. Repurpose the current node, replacing it with an empty
- // Node::MappedRepeatedField
- // (intrusive tree that stores message fields ordered by key).
- // 4. Insert the new node (containing Node::Message) into the repurposed
- // current node (Node::MappedRepeatedField) using the key extracted in step 1.
- if (node->GetIf<Node::Bytes>() || node->GetIf<Node::Message>()) {
- auto status_or_key = ReadScalarField(*node, map_key_field_id);
- PROTOVM_RETURN_IF_NOT_OK(status_or_key);
+ // True after the first BeginGroup(). Only BeginGroup() allocates output.
+ bool HasRewrittenGroups() const { return output_buffer_ != nullptr; }
- auto status_or_map_value = allocator_->CreateNode<Node::Empty>();
- PROTOVM_RETURN_IF_NOT_OK(status_or_map_value);
+ private:
+ // Append input bytes before |input_end_offset| to the output.
+ // The parser has validated these bytes.
+ void CopyInputUntil(size_t input_end_offset) {
+ PERFETTO_DCHECK(input_end_offset >= copy_cursor_.offset());
+ const size_t bytes_to_copy = input_end_offset - copy_cursor_.offset();
+ if (bytes_to_copy == 0)
+ return;
- auto map_value = std::move(*status_or_map_value);
- map_value->value = std::move(node->value);
- node->value = Node::MappedRepeatedField{};
+ // Reserve space before taking a pointer into the output buffer.
+ EnsureAdditionalCapacity(bytes_to_copy);
- auto status_or_it =
- MapInsert(&node->GetIf<Node::MappedRepeatedField>()->key_to_node,
- *status_or_key, std::move(map_value));
- PROTOVM_RETURN(status_or_it);
+ // Append the bytes. CopyTo() advances the input cursor.
+ copy_cursor_.CopyTo(output_buffer_.get() + output_size_, bytes_to_copy);
+ output_size_ += bytes_to_copy;
}
- // If the current node is a Node::IndexedRepeatedField (intrusive tree with
- // message fields ordered by index), this block converts it into a
- // Node::MappedRepeatedField (intrusive tree with message fields ordered by
- // key).
- //
- // The process is:
- // 1. Initialize an empty Node::MappedRepeatedField
- // 2. For each field in the current node (Node::IndexedRepeatedField):
- // 2.1. Extract the key (identified by 'map_key_field_id'). Note that the
- // iterated fields must be messages.
- // 2.2. Remove the field from the current node
- // (Node::IndexedRepeatedField).
- // 2.3. Insert the field into the Node::MappedRepeatedField using the key
- // extracted in step 2.1.
- // 3. Assign the Node::MappedRepeatedField to the current node, i.e. repurpose
- // current node from Node::IndexedRepeatedField to
- // Node::MappedRepeatedField)
- if (auto* indexed = node->GetIf<Node::IndexedRepeatedField>()) {
- Node::MappedRepeatedField mapped_repeated_field;
+ // Ensure room for |additional_bytes| after the current output.
+ // Buffer growth invalidates pointers into the old buffer.
+ void EnsureAdditionalCapacity(size_t additional_bytes) {
+ const size_t required_capacity = output_size_ + additional_bytes;
+ if (PERFETTO_LIKELY(required_capacity <= output_capacity_))
+ return;
- for (auto it = indexed->index_to_node.begin(); it;) {
- auto& map_entry = *it;
- auto& value_node = *it->value;
+ size_t new_capacity;
+ if (output_capacity_ == 0) {
+ // Heuristic for the first allocation.
+ // - input_size: space for the original packet bytes.
+ // - input_size / 16: spare for groups that grow by 3 bytes.
+ // - 64: spare for length slots reserved before their groups close.
+ const size_t input_size = copy_cursor_.input_size();
+ new_capacity = input_size + input_size / 16 + 64;
+ } else {
+ // Double the existing capacity to limit repeated allocations and copies.
+ new_capacity = output_capacity_ * 2;
+ }
+ new_capacity = std::max(new_capacity, required_capacity);
- it = indexed->index_to_node.Remove(it);
+ // Allocate a larger buffer and copy the output already written.
+ std::unique_ptr<uint8_t[]> larger_buffer(new uint8_t[new_capacity]);
+ if (output_size_)
+ memcpy(larger_buffer.get(), output_buffer_.get(), output_size_);
- auto status_or_key = ReadScalarField(value_node, map_key_field_id);
- PROTOVM_RETURN_IF_NOT_OK(status_or_key);
+ // Replace the old buffer after the copy completes.
+ output_buffer_ = std::move(larger_buffer);
+ output_capacity_ = new_capacity;
+ }
- map_entry.key = *status_or_key;
- mapped_repeated_field.key_to_node.Insert(map_entry);
+ // Next input byte to copy. The parser can be ahead of this cursor.
+ SliceCursor copy_cursor_;
+ GroupLengthOffsets& open_group_length_offsets_;
+ std::unique_ptr<uint8_t[]> output_buffer_;
+ // Used output bytes, including reserved length slots.
+ size_t output_size_ = 0;
+ // Allocated bytes in output_buffer_.
+ size_t output_capacity_ = 0;
+};
+
+// Parse field boundaries. A 0x04 inside a field value is ordinary data.
+RewriteResult RewriteFields(SliceCursor input_cursor, OutputWriter* writer) {
+ // A tag value has 32 bits: 29 for the field ID and 3 for the wire type.
+ constexpr uint64_t kMaxFieldId = UINT32_MAX >> pu::kFieldTypeNumBits;
+
+ while (!input_cursor.at_end()) {
+ // The bare end byte has no field ID. Handle it before tag validation.
+ if (input_cursor.PeekByte() == pu::kProtoGroupEndByte) {
+ const RewriteResult result = writer->EndGroup(input_cursor.offset());
+ PERFETTO_DCHECK(result != RewriteResult::kUnchanged);
+ if (PERFETTO_UNLIKELY(result != RewriteResult::kRewritten))
+ return result;
+ input_cursor.Skip(1);
+ continue;
}
- node->value = mapped_repeated_field;
+ // Save the start before ReadVarInt() advances past the tag.
+ const size_t tag_start_offset = input_cursor.offset();
+ uint64_t tag = 0;
+ if (PERFETTO_UNLIKELY(!input_cursor.ReadVarInt(&tag)))
+ return RewriteResult::kMalformedInput;
- return StatusOr<void>::Ok();
- }
+ const uint64_t field_id = pu::GetTagFieldId(tag);
+ if (PERFETTO_UNLIKELY(field_id == 0 || field_id > kMaxFieldId))
+ return RewriteResult::kMalformedInput;
- PROTOVM_ABORT(
- "Attempted to access field as MappedRepeatedField but node has type "
- "%s",
- node->GetTypeName());
-}
+ uint64_t value = 0;
+ bool valid = false;
+ switch (pu::GetTagFieldType(tag)) {
+ case pu::kWireTypeStartGroup:
+ valid = writer->BeginGroup(tag_start_offset,
+ input_cursor.offset() - tag_start_offset);
+ break;
+ case static_cast<uint32_t>(pu::ProtoWireType::kVarInt):
+ valid = input_cursor.ReadVarInt(&value);
+ break;
+ case static_cast<uint32_t>(pu::ProtoWireType::kFixed64):
+ valid = input_cursor.Skip(sizeof(uint64_t));
+ break;
+ case static_cast<uint32_t>(pu::ProtoWireType::kFixed32):
+ valid = input_cursor.Skip(sizeof(uint32_t));
+ break;
+ case static_cast<uint32_t>(pu::ProtoWireType::kLengthDelimited):
+ valid = input_cursor.ReadVarInt(&value) && input_cursor.Skip(value);
+ break;
+ default:
+ // Only the bare byte 0x04 closes a group.
+ // Reject standard end-group tags. Wire types 6 and 7 are undefined.
+ return RewriteResult::kMalformedInput;
+ }
-StatusOr<void> RwProtoCursor::ConvertToIndexedRepeatedFieldIfNeeded(
- Node* node) {
- if (node->GetIf<Node::IndexedRepeatedField>()) {
- return StatusOr<void>::Ok();
+ if (PERFETTO_UNLIKELY(!valid))
+ return RewriteResult::kMalformedInput;
}
- if (node->GetIf<Node::MappedRepeatedField>()) {
- PROTOVM_ABORT(
- "Attempted \"convert to indexed repeated field\" operation but "
- "node has type %s",
- node->GetTypeName());
- }
+ if (writer->HasOpenGroups())
+ return RewriteResult::kMalformedInput;
- if (node->GetIf<Node::Empty>()) {
- node->value = Node::IndexedRepeatedField{};
- return StatusOr<void>::Ok();
- }
+ return writer->HasRewrittenGroups() ? RewriteResult::kRewritten
+ : RewriteResult::kUnchanged;
+}
- auto status_or_map_value = allocator_->CreateNode<Node::Empty>();
- PROTOVM_RETURN_IF_NOT_OK(status_or_map_value);
+} // namespace
- auto map_value = std::move(*status_or_map_value);
- map_value->value = std::move(node->value);
- node->value = Node::IndexedRepeatedField{};
+RewriteResult ProtoGroupRewriter::Rewrite(const Slices& input,
+ std::optional<Slice>* output) {
+ open_group_length_offsets_.clear();
- auto status_or_it =
- MapInsert(&node->GetIf<Node::IndexedRepeatedField>()->index_to_node, 0,
- std::move(map_value));
- PROTOVM_RETURN(status_or_it);
+ // Cursor over the input for RewriteFields() to read and validate fields.
+ const SliceCursor initial_cursor(input);
+ // Writes validated fields to the output buffer and replaces group boundaries.
+ OutputWriter writer(initial_cursor, open_group_length_offsets_);
+
+ const RewriteResult result = RewriteFields(initial_cursor, &writer);
+ if (result != RewriteResult::kRewritten)
+ return result;
+
+ output->emplace(writer.Finish());
+ return RewriteResult::kRewritten;
}
-StatusOr<IntrusiveMap::Iterator> RwProtoCursor::FindOrCreateMessageField(
- Node* node,
- uint32_t field_id) {
- auto status = ConvertToMessageIfNeeded(node);
- PROTOVM_RETURN_IF_NOT_OK(status);
+} // namespace perfetto::tracing_v2
+// gen_amalgamated begin source: src/tracing/service/zlib_compressor.cc
+// gen_amalgamated begin header: src/tracing/service/zlib_compressor.h
+/*
+ * 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.
+ */
- auto* message = node->GetIf<Node::Message>();
- auto it = message->field_id_to_node.Find(field_id);
- if (it) {
- return it;
- }
+#ifndef SRC_TRACING_SERVICE_ZLIB_COMPRESSOR_H_
+#define SRC_TRACING_SERVICE_ZLIB_COMPRESSOR_H_
- auto status_or_map_value = allocator_->CreateNode<Node::Empty>();
- PROTOVM_RETURN_IF_NOT_OK(status_or_map_value);
+#include <vector>
- auto status_or_it = MapInsert(&message->field_id_to_node, field_id,
- std::move(*status_or_map_value));
- PROTOVM_RETURN(status_or_it);
-}
+// gen_amalgamated expanded: #include "perfetto/base/build_config.h"
+// gen_amalgamated expanded: #include "perfetto/ext/tracing/core/trace_packet.h"
-StatusOr<IntrusiveMap::Iterator>
-RwProtoCursor::FindOrCreateIndexedRepeatedField(Node* node, uint32_t index) {
- auto& index_to_node =
- node->GetIf<Node::IndexedRepeatedField>()->index_to_node;
+namespace perfetto {
- auto it = index_to_node.Find(index);
- if (it) {
- return it;
- }
+#if PERFETTO_BUILDFLAG(PERFETTO_ZLIB)
+void ZlibCompressFn(std::vector<TracePacket>*);
+#endif
- bool requires_creation_and_is_not_simple_append =
- index > index_to_node.Size();
- if (requires_creation_and_is_not_simple_append) {
- PROTOVM_ABORT(
- "Attempted to insert repeated field at arbitrary position (only "
- "append operation is supported)");
- }
+} // namespace perfetto
- auto status_or_map_value = allocator_->CreateNode<Node::Empty>();
- PROTOVM_RETURN_IF_NOT_OK(status_or_map_value);
+#endif // SRC_TRACING_SERVICE_ZLIB_COMPRESSOR_H_
+/*
+ * 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.
+ */
- return MapInsert(&node->GetIf<Node::IndexedRepeatedField>()->index_to_node,
- index, std::move(*status_or_map_value));
-}
+// gen_amalgamated expanded: #include "src/tracing/service/zlib_compressor.h"
-StatusOr<IntrusiveMap::Iterator> RwProtoCursor::FindOrCreateMappedRepeatedField(
- Node* node,
- uint64_t key) {
- auto it = node->GetIf<Node::MappedRepeatedField>()->key_to_node.Find(key);
+// gen_amalgamated expanded: #include "perfetto/base/build_config.h"
- if (it) {
- return it;
- }
+// File compiles to nothing when the buildflag is off (e.g. SDK opt-out).
+#if PERFETTO_BUILDFLAG(PERFETTO_ZLIB)
- auto status_or_map_value = allocator_->CreateNode<Node::Empty>();
- PROTOVM_RETURN_IF_NOT_OK(status_or_map_value);
+#include <zlib.h>
- return MapInsert(&node->GetIf<Node::MappedRepeatedField>()->key_to_node, key,
- std::move(*status_or_map_value));
-}
+// gen_amalgamated expanded: #include "protos/perfetto/trace/trace.pbzero.h"
+// gen_amalgamated expanded: #include "protos/perfetto/trace/trace_packet.pbzero.h"
+// gen_amalgamated expanded: #include "src/tracing/service/packet_compressor_common.h"
-StatusOr<IntrusiveMap::Iterator> RwProtoCursor::MapInsert(
- IntrusiveMap* map,
- uint64_t key,
- OwnedPtr<Node> map_value) {
- auto status_or_map_node =
- allocator_->CreateMapNode(key, std::move(map_value));
- PROTOVM_RETURN_IF_NOT_OK(status_or_map_node, "Failed to allocate node");
+namespace perfetto {
- auto [it, inserted] = map->Insert(*status_or_map_node->get());
- if (!inserted) {
- allocator_->Delete(status_or_map_node->release());
- PROTOVM_ABORT(
- "Failed to insert intrusive map entry (key = %d). Duplicated key?",
- static_cast<int>(key));
- }
+namespace {
- status_or_map_node->release();
- return it;
-}
+using packet_compressor::GetPreamble;
+using packet_compressor::kCompressSliceSize;
+using packet_compressor::Preamble;
+using packet_compressor::PreambleToSlice;
-StatusOr<uint64_t> RwProtoCursor::ReadScalarField(const Node& node,
- uint32_t field_id) {
- if (auto* bytes = node.GetIf<Node::Bytes>()) {
- protozero::ProtoDecoder decoder(protozero::ConstBytes{
- static_cast<const uint8_t*>(bytes->data.get()), bytes->size});
+// A compressor for `TracePacket`s that uses zlib. The class is exposed for
+// testing.
+class ZlibPacketCompressor {
+ public:
+ ZlibPacketCompressor();
+ ~ZlibPacketCompressor();
- auto field = decoder.ReadField();
- while (field.valid() && field.id() != field_id) {
- field = decoder.ReadField();
- }
+ // Can be called multiple times, before Finish() is called.
+ void PushPacket(const TracePacket& packet);
- if (!field.valid()) {
- PROTOVM_ABORT(
- "Attempted to read scalar field (id=%u) but it is not present",
- field_id);
- }
+ // Returned the compressed data. Can be called at most once. After this call,
+ // the object is unusable (PushPacket should not be called) and must be
+ // destroyed.
+ TracePacket Finish();
- if (field.type() ==
- protozero::proto_utils::ProtoWireType::kLengthDelimited) {
- PROTOVM_ABORT("Attempted to length-delimited field (id=%u) as scalar",
- field_id);
- }
+ private:
+ void PushData(const void* data, uint32_t size);
+ void NewOutputSlice();
+ void PushCurSlice();
- return field.as_uint64();
+ z_stream stream_;
+ size_t total_new_slices_size_ = 0;
+ std::vector<Slice> new_slices_;
+ std::unique_ptr<uint8_t[]> cur_slice_;
+};
+
+ZlibPacketCompressor::ZlibPacketCompressor() {
+ memset(&stream_, 0, sizeof(stream_));
+ int status = deflateInit(&stream_, 6);
+ PERFETTO_CHECK(status == Z_OK);
+}
+
+ZlibPacketCompressor::~ZlibPacketCompressor() {
+ int status = deflateEnd(&stream_);
+ PERFETTO_CHECK(status == Z_OK);
+}
+
+void ZlibPacketCompressor::PushPacket(const TracePacket& packet) {
+ // We need to be able to tokenize packets in the compressed stream, so we
+ // prefix a proto preamble to each packet. The compressed stream looks like a
+ // valid Trace proto.
+ Preamble preamble =
+ GetPreamble<protos::pbzero::Trace::kPacketFieldNumber>(packet.size());
+ PushData(preamble.buf.data(), preamble.size);
+ for (const Slice& slice : packet.slices()) {
+ PushData(slice.start, static_cast<uint32_t>(slice.size));
}
+}
- if (auto* message = node.GetIf<Node::Message>()) {
- auto it = message->field_id_to_node.Find(field_id);
- if (!it) {
- PROTOVM_ABORT(
- "Attempted to read scalar field (id=%u) but it is not present",
- field_id);
+void ZlibPacketCompressor::PushData(const void* data, uint32_t size) {
+ stream_.next_in = const_cast<Bytef*>(static_cast<const Bytef*>(data));
+ stream_.avail_in = static_cast<uInt>(size);
+ while (stream_.avail_in != 0) {
+ if (stream_.avail_out == 0) {
+ NewOutputSlice();
}
+ int status = deflate(&stream_, Z_NO_FLUSH);
+ PERFETTO_CHECK(status == Z_OK);
+ }
+}
- auto* scalar = it->value->GetIf<Scalar>();
- if (!scalar) {
- PROTOVM_ABORT(
- "Attempted to read scalar field (id=%u) from node with type %s",
- field_id, it->value->GetTypeName());
- }
+TracePacket ZlibPacketCompressor::Finish() {
+ for (;;) {
+ int status = deflate(&stream_, Z_FINISH);
+ if (status == Z_STREAM_END)
+ break;
+ PERFETTO_CHECK(status == Z_OK || status == Z_BUF_ERROR);
+ NewOutputSlice();
+ }
- return scalar->value;
+ PushCurSlice();
+
+ TracePacket packet;
+ packet.AddSlice(PreambleToSlice(
+ GetPreamble<protos::pbzero::TracePacket::kCompressedPacketsFieldNumber>(
+ total_new_slices_size_)));
+ for (auto& slice : new_slices_) {
+ packet.AddSlice(std::move(slice));
}
+ return packet;
+}
- PROTOVM_ABORT(
- "Attempted to read scalar field (id=%u) but parent node has type %s",
- field_id, node.GetTypeName());
+void ZlibPacketCompressor::NewOutputSlice() {
+ PushCurSlice();
+ cur_slice_ = std::make_unique<uint8_t[]>(kCompressSliceSize);
+ stream_.next_out = reinterpret_cast<Bytef*>(cur_slice_.get());
+ stream_.avail_out = kCompressSliceSize;
}
-StatusOr<void> RwProtoCursor::CheckIsValid() const {
- if (!node_) {
- PROTOVM_ABORT("Attempted to access invalid cursor");
+void ZlibPacketCompressor::PushCurSlice() {
+ if (cur_slice_) {
+ total_new_slices_size_ += kCompressSliceSize - stream_.avail_out;
+ new_slices_.push_back(Slice::TakeOwnership(
+ std::move(cur_slice_), kCompressSliceSize - stream_.avail_out));
}
- return StatusOr<void>::Ok();
}
-} // namespace protovm
+} // namespace
+
+void ZlibCompressFn(std::vector<TracePacket>* packets) {
+ if (packets->empty()) {
+ return;
+ }
+
+ ZlibPacketCompressor stream;
+
+ for (const TracePacket& packet : *packets) {
+ stream.PushPacket(packet);
+ }
+
+ TracePacket packet = stream.Finish();
+
+ packets->clear();
+ packets->push_back(std::move(packet));
+}
+
} // namespace perfetto
-// gen_amalgamated begin source: src/protovm/vm.cc
-// gen_amalgamated begin header: src/protovm/vm.h
+
+#endif // PERFETTO_BUILDFLAG(PERFETTO_ZLIB)
+// gen_amalgamated begin source: src/tracing/service/zstd_compressor.cc
+// gen_amalgamated begin header: src/tracing/service/zstd_compressor.h
/*
- * Copyright (C) 2025 The Android Open Source Project
+ * Copyright (C) 2026 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.
@@ -57257,152 +62516,26 @@ StatusOr<void> RwProtoCursor::CheckIsValid() const {
* limitations under the License.
*/
-#ifndef SRC_PROTOVM_VM_H_
-#define SRC_PROTOVM_VM_H_
-
-#include <memory>
+#ifndef SRC_TRACING_SERVICE_ZSTD_COMPRESSOR_H_
+#define SRC_TRACING_SERVICE_ZSTD_COMPRESSOR_H_
-// gen_amalgamated expanded: #include "perfetto/protozero/field.h"
+#include <vector>
-// gen_amalgamated expanded: #include "src/protovm/error_handling.h"
-// gen_amalgamated expanded: #include "src/protovm/executor.h"
-// gen_amalgamated expanded: #include "src/protovm/parser.h"
+// gen_amalgamated expanded: #include "perfetto/base/build_config.h"
+// gen_amalgamated expanded: #include "perfetto/ext/tracing/core/trace_packet.h"
namespace perfetto {
-namespace protovm {
-
-// A VM that executes programs defined by data sources at registration time.
-// Used by traced to apply patches (packets overwritten in the ring buffer) to
-// an incremental state packet, thus allowing efficient incremental tracing of
-// Layers/Windows/Views without requiring periodic invalidation and achieve
-// perfect interning.
-//
-// Overview of the VM's architecture and interactions:
-//
-//
-// ***********
-// * *
-// * Program *
-// * *
-// ***********
-// │
-// │
-// │
-// ┌───┴──┐ ┌────────┐
-// │ │ │ │
-// │Parser├────────────┤Executor│
-// │ │ │ │
-// └──────┘ └─┬────┬─┘
-// │ │
-// ┌─────┘ └─────┐
-// │ │
-// │ │
-// ┌───┴────┐ ┌───┴────┐
-// │ │ │ │
-// │RoCursor│ │RwProto │
-// │ │ │::Cursor│
-// └────┬───┘ │ │
-// │ └───┬────┘
-// │ │
-// │ │
-// │ │
-// ********* ***************
-// * * * *
-// * Patch * * Incremental *
-// * * * state *
-// ********* * *
-// ***************
-//
-// ┌─┐
-// │ │ VM's component
-// └─┘
-//
-// ***
-// * * Data
-// ***
-//
-//
-// Parser: Understands the instructions semantic and controls the program flow.
-// It delegates to the Executor operations like navigating through the
-// patch and incremental state data, reading values, and manipulating
-// fields.
-//
-//
-// Executor: Thin glue layer that mainly forwards data back and forth between
-// the Parser and cursors. Mainly useful for testing, as it can
-// be easily mocked and allows to test the Parser in isolation.
-//
-//
-// RoCursor: Provides read-only access to the incoming data (the patch) to be
-// applied. It allows to traverse the proto message structure of the
-// patch, iterating over fields and extracting field values.
-//
-//
-// RwProto::Cursor: Provides read-write access to the incremental state. It
-// allows traversing the proto message structure of the
-// incremental state, as well as deleting/inserting/merging
-// fields.
-class Vm {
- public:
- Vm(protozero::ConstBytes program,
- size_t memory_limit_bytes,
- protozero::ConstBytes initial_incremental_state = {nullptr, 0});
- StatusOr<void> ApplyPatch(protozero::ConstBytes packet);
- void SerializeIncrementalState(protozero::Message*) const;
- std::string SerializeProgram() const;
- std::unique_ptr<Vm> CloneReadOnly() const;
- uint64_t GetMemoryUsageBytes() const;
-
- private:
- struct ReadWriteState {
- ReadWriteState(std::string& program,
- size_t memory_limit_bytes,
- protozero::ConstBytes initial_incremental_state)
- : executor{},
- parser{protozero::ConstBytes{
- reinterpret_cast<const uint8_t*>(program.data()),
- program.size()},
- &executor},
- allocator{memory_limit_bytes},
- incremental_state{&allocator} {
- if (initial_incremental_state.data) {
- incremental_state.GetRoot().SetBytes(initial_incremental_state);
- }
- }
-
- Executor executor;
- Parser parser;
- Allocator allocator;
- RwProto incremental_state;
- };
-
- struct ReadOnlyState {
- explicit ReadOnlyState(std::string incremental_state)
- : serialized_incremental_state(std::move(incremental_state)) {}
- std::string serialized_incremental_state;
- };
-
- // Constructor used to produce read-only copies of the ProtoVm.
- // Private to avoid unintended copies. It should be used only for
- // CloneReadOnly().
- Vm(const Vm&);
-
- // Constructor used only for cloning
- explicit Vm(std::string incremental_state);
-
- std::string SerializeIncrementalStateAsString() const;
-
- std::string owned_program_;
- std::variant<ReadWriteState, ReadOnlyState> state_;
-};
+#if PERFETTO_BUILDFLAG(PERFETTO_ZSTD)
+// Compresses `packets` with zstd at the given compression `level`.
+void ZstdCompressFn(std::vector<TracePacket>*, int level);
+#endif
-} // namespace protovm
} // namespace perfetto
-#endif // SRC_PROTOVM_VM_H_
+#endif // SRC_TRACING_SERVICE_ZSTD_COMPRESSOR_H_
/*
- * Copyright (C) 2025 The Android Open Source Project
+ * Copyright (C) 2026 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.
@@ -57417,81 +62550,179 @@ class Vm {
* limitations under the License.
*/
-// gen_amalgamated expanded: #include "src/protovm/vm.h"
+// gen_amalgamated expanded: #include "src/tracing/service/zstd_compressor.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/field.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/scattered_heap_buffer.h"
-// gen_amalgamated expanded: #include "src/protovm/error_handling.h"
-// gen_amalgamated expanded: #include "src/protovm/ro_cursor.h"
-// gen_amalgamated expanded: #include "src/protovm/rw_proto.h"
+// gen_amalgamated expanded: #include "perfetto/base/build_config.h"
+
+#if PERFETTO_BUILDFLAG(PERFETTO_ZSTD)
+
+#include <memory>
+
+#include <zstd.h>
+
+// gen_amalgamated expanded: #include "perfetto/base/logging.h"
+// gen_amalgamated expanded: #include "perfetto/ext/base/scoped_file.h"
+// gen_amalgamated expanded: #include "protos/perfetto/trace/trace.pbzero.h"
+// gen_amalgamated expanded: #include "protos/perfetto/trace/trace_packet.pbzero.h"
+// gen_amalgamated expanded: #include "src/tracing/service/packet_compressor_common.h"
namespace perfetto {
-namespace protovm {
-Vm::Vm(protozero::ConstBytes program,
- size_t memory_limit_bytes,
- protozero::ConstBytes initial_incremental_state)
- : owned_program_(program.ToStdString()),
- state_(std::in_place_type_t<ReadWriteState>{},
- owned_program_,
- memory_limit_bytes,
- initial_incremental_state) {}
+namespace {
-Vm::Vm(const Vm& other)
- : owned_program_(other.SerializeProgram()),
- state_(std::in_place_type_t<ReadOnlyState>{},
- other.SerializeIncrementalStateAsString()) {}
+using packet_compressor::GetPreamble;
+using packet_compressor::kCompressSliceSize;
+using packet_compressor::Preamble;
+using packet_compressor::PreambleToSlice;
-StatusOr<void> Vm::ApplyPatch(protozero::ConstBytes packet) {
- ReadWriteState* rw_state = std::get_if<ReadWriteState>(&state_);
- if (!rw_state) {
- return StatusOr<void>::Abort();
- }
- auto src = RoCursor(packet);
- auto dst = rw_state->incremental_state.GetRoot();
- return rw_state->parser.Run(src, dst);
+// ScopedResource's close function must return int; ZSTD_freeCStream returns
+// size_t, so wrap it. It only fails for a static-allocated stream, not the
+// heap one ZSTD_createCStream gives us, so returning 0 is safe.
+inline int ZstdFreeCStream(ZSTD_CStream* cstream) {
+ ZSTD_freeCStream(cstream);
+ return 0;
}
+using ScopedZstdCStream = base::ScopedResource<ZSTD_CStream*,
+ ZstdFreeCStream,
+ /*InvalidValue=*/nullptr,
+ /*CheckClose=*/false>;
-void Vm::SerializeIncrementalState(protozero::Message* proto) const {
- if (const ReadOnlyState* state = std::get_if<ReadOnlyState>(&state_); state) {
- proto->AppendRawProtoBytes(state->serialized_incremental_state.data(),
- state->serialized_incremental_state.size());
- return;
+// A compressor for `TracePacket`s that uses zstd's streaming API: data is fed
+// in with ZSTD_compressStream2(ZSTD_e_continue) and the frame is finalized with
+// ZSTD_e_end, emitting output in fixed-size slices (kCompressSliceSize).
+// zstd API reference: https://facebook.github.io/zstd/zstd_manual.html
+class ZstdPacketCompressor {
+ public:
+ explicit ZstdPacketCompressor(int level);
+
+ // Can be called multiple times, before Finish() is called.
+ void PushPacket(const TracePacket& packet);
+
+ // Returns the compressed data. Can be called at most once. After this call,
+ // the object is unusable (PushPacket should not be called) and must be
+ // destroyed.
+ TracePacket Finish();
+
+ private:
+ void PushData(const void* data, uint32_t size);
+ void NewOutputSlice();
+ void PushCurSlice();
+
+ ScopedZstdCStream cstream_;
+ // Points into `cur_slice_`. Zero-initialized so that the first compression
+ // call observes a full output buffer and allocates the initial slice.
+ ZSTD_outBuffer out_{/*dst=*/nullptr, /*size=*/0, /*pos=*/0};
+ size_t total_new_slices_size_ = 0;
+ std::vector<Slice> new_slices_;
+ std::unique_ptr<uint8_t[]> cur_slice_;
+};
+
+ZstdPacketCompressor::ZstdPacketCompressor(int level) {
+ cstream_.reset(ZSTD_createCStream());
+ PERFETTO_CHECK(cstream_);
+ // zstd maps 0 to its default level, clamps levels above its max, and treats
+ // negatives as fast modes, so any int is safe to pass through here.
+ size_t rc =
+ ZSTD_CCtx_setParameter(cstream_.get(), ZSTD_c_compressionLevel, level);
+ PERFETTO_CHECK(!ZSTD_isError(rc));
+}
+
+void ZstdPacketCompressor::PushPacket(const TracePacket& packet) {
+ // Prefix each packet with its proto preamble so the compressed stream itself
+ // parses as a valid Trace proto, and its packets can be tokenized back out.
+ Preamble preamble =
+ GetPreamble<protos::pbzero::Trace::kPacketFieldNumber>(packet.size());
+ PushData(preamble.buf.data(), preamble.size);
+ for (const Slice& slice : packet.slices()) {
+ PushData(slice.start, static_cast<uint32_t>(slice.size));
}
+}
- const ReadWriteState* state = std::get_if<ReadWriteState>(&state_);
- state->incremental_state.Serialize(proto);
+void ZstdPacketCompressor::PushData(const void* data, uint32_t size) {
+ // ZSTD_e_continue hands data to the encoder, which buffers and emits at its
+ // own discretion. It may not consume all input in one call (e.g. when the
+ // output slice fills), so loop until `in` is drained, giving it a fresh slice
+ // whenever `out_` is full.
+ ZSTD_inBuffer in = {/*src=*/data, /*size=*/size, /*pos=*/0};
+ while (in.pos < in.size) {
+ if (out_.pos == out_.size) {
+ NewOutputSlice();
+ }
+ size_t rc =
+ ZSTD_compressStream2(cstream_.get(), &out_, &in, ZSTD_e_continue);
+ PERFETTO_CHECK(!ZSTD_isError(rc));
+ }
}
-std::string Vm::SerializeIncrementalStateAsString() const {
- protozero::HeapBuffered<protozero::Message> proto;
- SerializeIncrementalState(proto.get());
- return proto.SerializeAsString();
+TracePacket ZstdPacketCompressor::Finish() {
+ // ZSTD_e_end flushes buffered data and writes the frame epilogue. Per the
+ // contract, keep calling (draining `out_` into new slices) until it reports 0
+ // bytes remaining.
+ size_t remaining;
+ do {
+ if (out_.pos == out_.size) {
+ NewOutputSlice();
+ }
+ ZSTD_inBuffer in = {/*src=*/nullptr, /*size=*/0, /*pos=*/0};
+ remaining = ZSTD_compressStream2(cstream_.get(), &out_, &in, ZSTD_e_end);
+ PERFETTO_CHECK(!ZSTD_isError(remaining));
+ } while (remaining != 0);
+
+ PushCurSlice();
+
+ TracePacket packet;
+ packet.AddSlice(PreambleToSlice(
+ GetPreamble<
+ protos::pbzero::TracePacket::kZstdCompressedPacketsFieldNumber>(
+ total_new_slices_size_)));
+ for (auto& slice : new_slices_) {
+ packet.AddSlice(std::move(slice));
+ }
+ return packet;
}
-std::string Vm::SerializeProgram() const {
- return owned_program_;
+void ZstdPacketCompressor::NewOutputSlice() {
+ PushCurSlice();
+ cur_slice_ = std::make_unique<uint8_t[]>(kCompressSliceSize);
+ out_.dst = cur_slice_.get();
+ out_.size = kCompressSliceSize;
+ out_.pos = 0;
}
-std::unique_ptr<Vm> Vm::CloneReadOnly() const {
- return std::unique_ptr<Vm>(new Vm(*this));
+void ZstdPacketCompressor::PushCurSlice() {
+ if (!cur_slice_) {
+ return;
+ }
+ total_new_slices_size_ += out_.pos;
+ new_slices_.push_back(Slice::TakeOwnership(std::move(cur_slice_), out_.pos));
}
-uint64_t Vm::GetMemoryUsageBytes() const {
- if (const ReadOnlyState* state = std::get_if<ReadOnlyState>(&state_); state) {
- return owned_program_.size() + state->serialized_incremental_state.size();
+} // namespace
+
+void ZstdCompressFn(std::vector<TracePacket>* packets, int level) {
+ if (packets->empty()) {
+ return;
}
- const ReadWriteState* state = std::get_if<ReadWriteState>(&state_);
- return owned_program_.size() + state->allocator.GetMemoryUsageBytes();
+ ZstdPacketCompressor stream(level);
+
+ for (const TracePacket& packet : *packets) {
+ stream.PushPacket(packet);
+ }
+
+ TracePacket packet = stream.Finish();
+
+ packets->clear();
+ packets->push_back(std::move(packet));
}
-} // namespace protovm
} // namespace perfetto
-// gen_amalgamated begin source: src/protozero/filtering/filter_bytecode_parser.cc
-// gen_amalgamated begin header: src/protozero/filtering/filter_bytecode_parser.h
+
+#endif // PERFETTO_BUILDFLAG(PERFETTO_ZSTD)
+// gen_amalgamated begin source: src/tracing/ipc/default_socket.cc
+// gen_amalgamated begin header: include/perfetto/ext/ipc/basic_types.h
/*
- * Copyright (C) 2021 The Android Open Source Project
+ * 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.
@@ -57506,166 +62737,177 @@ uint64_t Vm::GetMemoryUsageBytes() const {
* limitations under the License.
*/
-#ifndef SRC_PROTOZERO_FILTERING_FILTER_BYTECODE_PARSER_H_
-#define SRC_PROTOZERO_FILTERING_FILTER_BYTECODE_PARSER_H_
+#ifndef INCLUDE_PERFETTO_EXT_IPC_BASIC_TYPES_H_
+#define INCLUDE_PERFETTO_EXT_IPC_BASIC_TYPES_H_
#include <stddef.h>
#include <stdint.h>
+#include <sys/types.h>
-#include <vector>
+// gen_amalgamated expanded: #include "perfetto/ext/base/utils.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/cpp_message_obj.h"
-namespace protozero {
+namespace perfetto {
+namespace ipc {
-// Loads the proto-encoded bytecode in memory and allows fast lookups for tuples
-// (msg_index, field_id) to tell if a given field should be allowed or not and,
-// in the case of nested fields, what is the next message index to recurse into.
-// This class does two things:
-// 1. Expands the array of varint from the proto into a vector<uint32_t>. This
-// is to avoid performing varint decoding on every lookup, at the cost of
-// some extra memory (2KB-4KB). Note that the expanded vector is not just a
-// 1:1 copy of the proto one (more below). This is to avoid O(Fields) linear
-// lookup complexity.
-// 2. Creates an index of offsets to remember the start word for each message.
-// This is so we can jump to O(1) to the N-th message when recursing into a
-// nested fields, without having to scan and find the (N-1)-th END_OF_MESSAGE
-// marker.
-// Overall lookups are O(1) for field ids < 128 (kDirectlyIndexLimit) and O(N),
-// with N being the number of allowed field ranges for other fields.
-// See comments around |word_| below for the structure of the word vector.
-class FilterBytecodeParser {
- public:
- static constexpr uint32_t kSimpleField = 0x7fffffff;
- static constexpr uint32_t kFilterStringField = 0x7ffffffe;
- // FilterStringFieldWithType uses a range: 0x7fff0000 to 0x7ffffffd.
- // The semantic type is encoded in the lower 16 bits.
- static constexpr uint32_t kFilterStringFieldWithType = 0x7fff0000;
- static constexpr uint32_t kFilterStringFieldWithTypeMask = 0x7fff0000;
- static constexpr uint32_t kSemanticTypeMask = 0xffff;
+using ProtoMessage = ::protozero::CppMessageObj;
+using ServiceID = uint32_t;
+using MethodID = uint32_t;
+using ClientID = uint64_t;
+using RequestID = uint64_t;
- // Result of a Query() operation
- struct QueryResult {
- bool allowed; // Whether the field is allowed at all or no.
+#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
+// AF_UNIX on Windows is supported only on Windows 10 from build 17063.
+// Also it doesn't bring major advantages compared to a TCP socket.
+// See go/perfetto-win .
+constexpr bool kUseTCPSocket = true;
+#else
+// Android, Linux, Mac, Fuchsia use local sockets.
+constexpr bool kUseTCPSocket = false;
+#endif
- // If |allowed|==true && nested_msg_field() == true, this tells the message
- // index of the nested field that should be used when recursing in the
- // parser.
- uint32_t nested_msg_index;
+// This determines the maximum size allowed for an IPC message. Trying to send
+// or receive a larger message will hit DCHECK(s) and auto-disconnect.
+constexpr size_t kIPCBufferSize = 128 * 1024;
- // The semantic type of the field (only meaningful when
- // filter_string_field() returns true). A value of 0 means unspecified.
- uint32_t semantic_type;
+constexpr uid_t kInvalidUid = static_cast<uid_t>(-1);
- // If |allowed|==true, specifies if the field is of a simple type (varint,
- // fixed32/64, string or byte).
- bool simple_field() const { return nested_msg_index == kSimpleField; }
+} // namespace ipc
+} // namespace perfetto
- // If |allowed|==true, specifies if this field is a string field that needs
- // to be filtered.
- bool filter_string_field() const {
- // Range: [kFilterStringFieldWithType, kFilterStringField] i.e.
- // [0x7fff0000, 0x7ffffffe]. This excludes kSimpleField (0x7fffffff).
- return nested_msg_index >= kFilterStringFieldWithType &&
- nested_msg_index <= kFilterStringField;
- }
+#endif // INCLUDE_PERFETTO_EXT_IPC_BASIC_TYPES_H_
+/*
+ * 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.
+ */
- // If |allowed|==true, specifies if the field is a nested field that needs
- // recursion. The caller is expected to use |nested_msg_index| for the next
- // Query() calls.
- bool nested_msg_field() const {
- static_assert(kFilterStringFieldWithType < kFilterStringField,
- "kFilterStringFieldWithType < kFilterStringField");
- static_assert(kFilterStringField < kSimpleField,
- "kFilterStringField < kSimpleField");
- return nested_msg_index < kFilterStringFieldWithType;
- }
- };
+// gen_amalgamated expanded: #include "perfetto/tracing/default_socket.h"
- // Loads a filter. The filter data consists of a sequence of varints which
- // contains the filter opcodes and a final checksum.
- // If a filter is already loaded, it is replaced.
- //
- // Optionally accepts an overlay (pass nullptr/0 if not needed). The overlay
- // can add new fields or upgrade existing fields (e.g., to FilterString).
- // The overlay uses the same opcode format as the base bytecode, but with an
- // explicit message index prefix:
- // [msg_index, (field_id << 3) | opcode, argument] ... [checksum]
- // Entry sizes depend on the opcode (same as base bytecode).
- // Entries must be sorted by (msg_index, field_id). The base bytecode and
- // overlay are merged during loading, maintaining sorted field order.
- // See /rfcs/0011-subset-string-filter-rules.md for design details.
- bool Load(const void* filter_data,
- size_t len,
- const void* overlay_data = nullptr,
- size_t overlay_len = 0);
+// gen_amalgamated expanded: #include "perfetto/base/build_config.h"
+// gen_amalgamated expanded: #include "perfetto/base/logging.h"
+// gen_amalgamated expanded: #include "perfetto/ext/base/android_utils.h"
+// gen_amalgamated expanded: #include "perfetto/ext/base/string_utils.h"
+// gen_amalgamated expanded: #include "perfetto/ext/base/utils.h"
+// gen_amalgamated expanded: #include "perfetto/ext/ipc/basic_types.h"
+// gen_amalgamated expanded: #include "perfetto/ext/tracing/core/basic_types.h"
- // Checks wheter a given field is allowed or not.
- // msg_index = 0 is the index of the root message, where all queries should
- // start from (typically perfetto.protos.Trace).
- QueryResult Query(uint32_t msg_index, uint32_t field_id) const;
+#include <stdlib.h>
- void Reset();
- void set_suppress_logs_for_fuzzer(bool x) { suppress_logs_for_fuzzer_ = x; }
+#if PERFETTO_BUILDFLAG(PERFETTO_OS_LINUX) || \
+ PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID) || \
+ PERFETTO_BUILDFLAG(PERFETTO_OS_FREEBSD) || \
+ PERFETTO_BUILDFLAG(PERFETTO_OS_APPLE)
+#include <unistd.h>
+#endif
- private:
- static constexpr uint32_t kDirectlyIndexLimit = 128;
- static constexpr uint32_t kAllowed = 1u << 31u;
+namespace perfetto {
+namespace {
+
+const char* kRunPerfettoBaseDir = "/run/perfetto/";
+
+// On Linux and CrOS, check /run/perfetto/ before using /tmp/ as the socket
+// base directory.
+bool UseRunPerfettoBaseDir() {
+#if PERFETTO_BUILDFLAG(PERFETTO_OS_LINUX)
+ // Note that the trailing / in |kRunPerfettoBaseDir| ensures we are checking
+ // against a directory, not a file.
+ int res = PERFETTO_EINTR(access(kRunPerfettoBaseDir, X_OK));
+ if (!res)
+ return true;
- bool LoadInternal(const uint8_t* filter_data,
- size_t len,
- const uint8_t* overlay_data,
- size_t overlay_len);
+ // If the path doesn't exist (ENOENT), fail silently to the caller. Otherwise,
+ // fail with an explicit error message.
+ if (errno != ENOENT
+#if PERFETTO_BUILDFLAG(PERFETTO_CHROMIUM_BUILD)
+ // access(2) won't return EPERM, but Chromium sandbox returns EPERM if the
+ // sandbox doesn't allow the call (e.g. in the child processes).
+ && errno != EPERM
+#endif
+ ) {
+ PERFETTO_PLOG("%s exists but cannot be accessed. Falling back on /tmp/ ",
+ kRunPerfettoBaseDir);
+ }
+ return false;
+#else
+ base::ignore_result(kRunPerfettoBaseDir);
+ return false;
+#endif
+}
- // The state of all fields for all messages is stored in one contiguous array.
- // This is to avoid memory fragmentation and allocator overhead.
- // We expect a high number of messages (hundreds), but each message is small.
- // For each message we store two sets of uint32:
- // 1. A set of "directly indexed" fields, for field ids < 128.
- // 2. The remainder is a set of ranges.
- // So each message descriptor consists of a sequence of words as follows:
- //
- // [0] -> how many directly indexed fields are stored next (up to 128)
- //
- // [1..N] -> One word per field id (See "field state" below).
- //
- // [N + 1] -> Start of field id range 1
- // [N + 2] -> End of field id range 1 (exclusive, STL-style).
- // [N + 3] -> Field state for fields in range 1 (below)
- //
- // [N + 4] -> Start of field id range 2
- // [N + 5] -> End of field id range 2 (exclusive, STL-style).
- // [N + 6] -> Field state for fields in range 2 (below)
+} // anonymous namespace
- // The "field state" word is as follows:
- // Bit 31: 1 if the field is allowed, 0 if disallowed.
- // Only directly indexed fields can be 0 (it doesn't make sense to add
- // a range and then say "btw it's NOT allowed".. don't add it then.
- // 0 is only used for filling gaps in the directly indexed bucket.
- // Bits [30..0] (only when MSB == allowed):
- // 0x7fffffff: The field is "simple" (varint, fixed32/64, string, bytes) and
- // can be directly passed through in output. No recursion is needed.
- // 0x7ffffffe: The field is string field which needs to be filtered.
- // 0x7fff0000-0x7ffffffd: The field is a string field with a semantic type.
- // The lower 16 bits encode the semantic type.
- // [0, 0x7ffeffff]: The field is a nested submessage. The value is the index
- // that must be passed as first argument to the next Query() calls.
- // Note that the message index is purely a monotonic counter in the
- std::vector<uint32_t> words_;
+const char* GetProducerSocket() {
+ const char* name = getenv("PERFETTO_PRODUCER_SOCK_NAME");
+ if (name == nullptr) {
+#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
+ name = "127.0.0.1:32278";
+#elif PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID)
+ name = "/dev/socket/traced_producer";
+#else
+ // Use /run/perfetto if it exists. Then fallback to /tmp.
+ static const char* producer_socket =
+ UseRunPerfettoBaseDir() ? "/run/perfetto/traced-producer.sock"
+ : "/tmp/perfetto-producer";
+ name = producer_socket;
+#endif
+ }
+ base::ignore_result(UseRunPerfettoBaseDir); // Silence unused func warnings.
+ return name;
+}
- // One entry for each message index stored in the filter plus a sentinel at
- // the end. Maps each message index to the offset in |words_| where the
- // Nth message start.
- // message_offset_.size() - 2 == the max message id that can be parsed.
- std::vector<uint32_t> message_offset_;
+std::string GetRelaySocket() {
+ // The relay socket is optional and is connected only when the env var is set.
+ // In Android, if the env var isn't set then we check the
+ // |traced_relay.relay_port| system property.
+ const char* name = getenv("PERFETTO_RELAY_SOCK_NAME");
+ if (name != nullptr)
+ return std::string(name);
+#if PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID)
+ return base::GetAndroidProp("traced_relay.relay_port");
+#else
+ return std::string();
+#endif
+}
- bool suppress_logs_for_fuzzer_ = false;
-};
+std::vector<std::string> TokenizeProducerSockets(
+ const char* producer_socket_names) {
+ return base::SplitString(producer_socket_names, ",");
+}
-} // namespace protozero
+const char* GetConsumerSocket() {
+ const char* name = getenv("PERFETTO_CONSUMER_SOCK_NAME");
+ if (name == nullptr) {
+#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
+ name = "127.0.0.1:32279";
+#elif PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID)
+ name = "/dev/socket/traced_consumer";
+#else
+ // Use /run/perfetto if it exists. Then fallback to /tmp.
+ static const char* consumer_socket =
+ UseRunPerfettoBaseDir() ? "/run/perfetto/traced-consumer.sock"
+ : "/tmp/perfetto-consumer";
+ name = consumer_socket;
+#endif
+ }
+ return name;
+}
-#endif // SRC_PROTOZERO_FILTERING_FILTER_BYTECODE_PARSER_H_
-// gen_amalgamated begin header: src/protozero/filtering/filter_bytecode_common.h
+} // namespace perfetto
+// gen_amalgamated begin source: src/tracing/ipc/memfd.cc
+// gen_amalgamated begin header: src/tracing/ipc/memfd.h
/*
- * Copyright (C) 2021 The Android Open Source Project
+ * 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.
@@ -57680,52 +62922,52 @@ class FilterBytecodeParser {
* limitations under the License.
*/
-#ifndef SRC_PROTOZERO_FILTERING_FILTER_BYTECODE_COMMON_H_
-#define SRC_PROTOZERO_FILTERING_FILTER_BYTECODE_COMMON_H_
+#ifndef SRC_TRACING_IPC_MEMFD_H_
+#define SRC_TRACING_IPC_MEMFD_H_
-#include <stdint.h>
+// gen_amalgamated expanded: #include "perfetto/base/build_config.h"
-namespace protozero {
+// gen_amalgamated expanded: #include "perfetto/ext/base/scoped_file.h"
-enum FilterOpcode : uint32_t {
- // The immediate value is 0 in this case.
- kFilterOpcode_EndOfMessage = 0,
+// The build has the memfd code. HasMemfdSupport() also checks the kernel.
+#define PERFETTO_MEMFD_ENABLED() \
+ (PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID) || \
+ PERFETTO_BUILDFLAG(PERFETTO_OS_LINUX_BUT_NOT_QNX))
- // The immediate value is the id of the allowed field.
- kFilterOpcode_SimpleField = 1,
+// Some android build bots use a sysroot that doesn't support memfd when
+// compiling for the host, so we define the flags we need ourselves.
- // The immediate value is the start of the range. The next word (without
- // any shifting) is the length of the range.
- kFilterOpcode_SimpleFieldRange = 2,
+// from memfd.h
+#ifndef MFD_CLOEXEC
+#define MFD_CLOEXEC 0x0001U
+#define MFD_ALLOW_SEALING 0x0002U
+#endif
- // The immediate value is the id of the allowed field. The next word
- // (without any shifting) is the index of the filter that should be used to
- // recurse into the nested message.
- kFilterOpcode_NestedField = 3,
+// from fcntl.h
+#ifndef F_ADD_SEALS
+#define F_ADD_SEALS 1033
+#define F_GET_SEALS 1034
+#define F_SEAL_SEAL 0x0001
+#define F_SEAL_SHRINK 0x0002
+#define F_SEAL_GROW 0x0004
+#define F_SEAL_WRITE 0x0008
+#endif
- // The immediate value is the id of the allowed field. The behaviour of this
- // opcode is the same as kFilterOpcode_SimpleField, with the further semantic
- // that the field is a string and needs to be processed using the string
- // filtering rules.
- kFilterOpcode_FilterString = 4,
+namespace perfetto {
- // The immediate value is the id of the allowed field. The next word (without
- // any shifting) is the semantic type of the string field. The behaviour is
- // similar to kFilterOpcode_FilterString, but carries semantic type info so
- // that the string filter can apply type-specific rules.
- kFilterOpcode_FilterStringWithType = 5,
-};
+// Whether the operating system supports memfd.
+bool HasMemfdSupport();
-// Constants for extracting opcode and field_id from bytecode words.
-// Bytecode words are encoded as: (field_id << kOpcodeShift) | opcode
-constexpr uint32_t kOpcodeMask = 0x7u;
-constexpr uint32_t kOpcodeShift = 3;
+// Call memfd(2) if available on platform and return the fd as result. This call
+// also makes a kernel version check for safety on older kernels (b/116769556).
+// Returns an invalid ScopedFile on failure.
+base::ScopedFile CreateMemfd(const char* name, unsigned int flags);
-} // namespace protozero
+} // namespace perfetto
-#endif // SRC_PROTOZERO_FILTERING_FILTER_BYTECODE_COMMON_H_
+#endif // SRC_TRACING_IPC_MEMFD_H_
/*
- * Copyright (C) 2021 The Android Open Source Project
+ * 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.
@@ -57740,463 +62982,341 @@ constexpr uint32_t kOpcodeShift = 3;
* limitations under the License.
*/
-// gen_amalgamated expanded: #include "src/protozero/filtering/filter_bytecode_parser.h"
-
-#include <algorithm>
-#include <cstddef>
-#include <cstdint>
-#include <limits>
-#include <vector>
-
-// gen_amalgamated expanded: #include "perfetto/base/logging.h"
-// gen_amalgamated expanded: #include "perfetto/ext/base/fnv_hash.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/proto_decoder.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/proto_utils.h"
-// gen_amalgamated expanded: #include "perfetto/public/compiler.h"
-// gen_amalgamated expanded: #include "src/protozero/filtering/filter_bytecode_common.h"
+// gen_amalgamated expanded: #include "src/tracing/ipc/memfd.h"
-namespace protozero {
+#include <errno.h>
-namespace {
+#if PERFETTO_MEMFD_ENABLED()
-// Parses varint-encoded bytecode and verifies checksum.
-// Returns true on success, with the checksum removed from |words|.
-bool ParseAndVerifyChecksum(const uint8_t* data,
- size_t len,
- std::vector<uint32_t>* words,
- bool suppress_logs) {
- if (len == 0) {
- return false;
- }
- words->reserve(len); // An overestimation, but avoids reallocations.
+#include <stdio.h>
+#include <string.h>
+#include <sys/syscall.h>
+#include <sys/utsname.h>
+#include <unistd.h>
- // Parse varints while computing checksum in a single pass.
- // The last word is the checksum itself and should not be hashed.
- perfetto::base::FnvHasher hasher;
- uint32_t actual_csum = 0;
+// Some android build bots use a sysroot that doesn't support memfd when
+// compiling for the host, so we redefine it if necessary.
+#if !defined(__NR_memfd_create)
+#if defined(__x86_64__)
+#define __NR_memfd_create 319
+#elif defined(__i386__)
+#define __NR_memfd_create 356
+#elif defined(__aarch64__)
+#define __NR_memfd_create 279
+#elif defined(__arm__)
+#define __NR_memfd_create 385
+#else
+#error "unsupported sysroot without memfd support"
+#endif
+#endif // !defined(__NR_memfd_create)
- using BytecodeDecoder =
- PackedRepeatedFieldIterator<proto_utils::ProtoWireType::kVarInt,
- uint32_t>;
- bool has_checksum = false;
- bool packed_parse_err = false;
- for (BytecodeDecoder it(data, len, &packed_parse_err); it;) {
- uint32_t word = *it++;
- if (bool is_last_word = !it; is_last_word) {
- actual_csum = word;
- has_checksum = true;
- break;
- }
- words->emplace_back(word);
- hasher.Update(word);
- }
- if (packed_parse_err || !has_checksum) {
- words->clear();
- return false;
- }
- auto expected_csum = static_cast<uint32_t>(hasher.digest());
- if (expected_csum != actual_csum) {
- if (!suppress_logs) {
- PERFETTO_ELOG("Filter bytecode checksum failed. Expected: %x, actual: %x",
- expected_csum, actual_csum);
+namespace perfetto {
+bool HasMemfdSupport() {
+ static bool kSupportsMemfd = [] {
+ // Check kernel version supports memfd_create(). Some older kernels segfault
+ // executing memfd_create() rather than returning ENOSYS (b/116769556).
+ static constexpr int kRequiredMajor = 3;
+ static constexpr int kRequiredMinor = 17;
+ struct utsname uts;
+ int major, minor;
+ if (uname(&uts) == 0 && strcmp(uts.sysname, "Linux") == 0 &&
+ sscanf(uts.release, "%d.%d", &major, &minor) == 2 &&
+ ((major < kRequiredMajor ||
+ (major == kRequiredMajor && minor < kRequiredMinor)))) {
+ return false;
}
- words->clear();
- return false;
- }
- return true;
-}
-struct OverlayEntry {
- uint32_t msg_index;
- uint32_t field_id;
- uint32_t message_id;
-};
+ base::ScopedFile fd;
+ fd.reset(static_cast<int>(syscall(__NR_memfd_create, "perfetto_shmem",
+ MFD_CLOEXEC | MFD_ALLOW_SEALING)));
+ return !!fd;
+ }();
+ return kSupportsMemfd;
+}
-// Returns the message_id for an overlay entry based on opcode and argument.
-// Returns 0 if the opcode is invalid.
-uint32_t GetMessageIdForOverlay(uint32_t opcode, uint32_t argument) {
- switch (opcode) {
- case kFilterOpcode_SimpleField:
- return FilterBytecodeParser::kSimpleField;
- case kFilterOpcode_FilterString:
- return FilterBytecodeParser::kFilterStringField;
- case kFilterOpcode_FilterStringWithType:
- // For FilterStringWithType, incorporate semantic type into message_id.
- return FilterBytecodeParser::kFilterStringFieldWithType |
- (argument & FilterBytecodeParser::kSemanticTypeMask);
- default:
- return 0; // Invalid opcode
+base::ScopedFile CreateMemfd(const char* name, unsigned int flags) {
+ if (!HasMemfdSupport()) {
+ errno = ENOSYS;
+ return base::ScopedFile();
}
+ return base::ScopedFile(
+ static_cast<int>(syscall(__NR_memfd_create, name, flags)));
}
+} // namespace perfetto
-} // namespace
+#else // PERFETTO_MEMFD_ENABLED()
-void FilterBytecodeParser::Reset() {
- bool suppress = suppress_logs_for_fuzzer_;
- *this = FilterBytecodeParser();
- suppress_logs_for_fuzzer_ = suppress;
+namespace perfetto {
+bool HasMemfdSupport() {
+ return false;
}
-
-bool FilterBytecodeParser::Load(const void* filter_data,
- size_t len,
- const void* overlay_data,
- size_t overlay_len) {
- Reset();
- bool res =
- LoadInternal(static_cast<const uint8_t*>(filter_data), len,
- static_cast<const uint8_t*>(overlay_data), overlay_len);
- // If load fails, don't leave the parser in a half broken state.
- if (!res)
- Reset();
- return res;
+base::ScopedFile CreateMemfd(const char*, unsigned int) {
+ errno = ENOSYS;
+ return base::ScopedFile();
}
+} // namespace perfetto
-bool FilterBytecodeParser::LoadInternal(const uint8_t* filter_data,
- size_t len,
- const uint8_t* overlay_data,
- size_t overlay_len) {
- // First unpack the varints into a plain uint32 vector, so it's easy to
- // iterate through them and look ahead.
- std::vector<uint32_t> words;
- if (!ParseAndVerifyChecksum(filter_data, len, &words,
- suppress_logs_for_fuzzer_))
- return false;
+#endif // PERFETTO_MEMFD_ENABLED()
+// gen_amalgamated begin source: src/tracing/ipc/posix_shared_memory.cc
+// gen_amalgamated begin header: src/tracing/ipc/posix_shared_memory.h
+/*
+ * 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.
+ */
- // Parse the overlay (if provided).
- std::vector<OverlayEntry> overlay;
- if (overlay_data && overlay_len > 0) {
- std::vector<uint32_t> overlay_words;
- if (!ParseAndVerifyChecksum(overlay_data, overlay_len, &overlay_words,
- suppress_logs_for_fuzzer_)) {
- return false;
- }
+#ifndef SRC_TRACING_IPC_POSIX_SHARED_MEMORY_H_
+#define SRC_TRACING_IPC_POSIX_SHARED_MEMORY_H_
- // Each entry is exactly 3 words: [msg_index, field_word, argument]
- // where field_id = field_word >> 3. The argument is 0 when not needed.
- if (overlay_words.size() % 3 != 0) {
- PERFETTO_DLOG("overlay error: size %zu not multiple of 3",
- overlay_words.size());
- return false;
- }
+// gen_amalgamated expanded: #include "perfetto/base/build_config.h"
- for (size_t i = 0; i < overlay_words.size(); i += 3) {
- overlay.emplace_back();
+#if PERFETTO_BUILDFLAG(PERFETTO_OS_LINUX) || \
+ PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID) || \
+ PERFETTO_BUILDFLAG(PERFETTO_OS_APPLE) || \
+ PERFETTO_BUILDFLAG(PERFETTO_OS_FUCHSIA) || \
+ PERFETTO_BUILDFLAG(PERFETTO_OS_FREEBSD) || \
+ PERFETTO_BUILDFLAG(PERFETTO_OS_WASM)
- uint32_t opcode = overlay_words[i + 1] & kOpcodeMask;
- uint32_t message_id =
- GetMessageIdForOverlay(opcode, overlay_words[i + 2]);
- if (message_id == 0) {
- PERFETTO_DLOG("overlay error: invalid opcode %u at index %zu", opcode,
- i + 1);
- return false;
- }
+#include <stddef.h>
- OverlayEntry& entry = overlay.back();
- entry.msg_index = overlay_words[i];
- entry.field_id = overlay_words[i + 1] >> kOpcodeShift;
- entry.message_id = message_id;
+#include <memory>
- if (overlay.size() == 1) {
- continue;
- }
- // Validate that overlay entries are sorted by (msg_index, field_id).
- const OverlayEntry& prev_entry = overlay[overlay.size() - 2];
- if (entry.msg_index < prev_entry.msg_index ||
- (entry.msg_index == prev_entry.msg_index &&
- entry.field_id <= prev_entry.field_id)) {
- PERFETTO_DLOG(
- "overlay error: entries not sorted at index %zu (msg %u, "
- "field %u) after (msg %u, field %u)",
- i, entry.msg_index, entry.field_id, prev_entry.msg_index,
- prev_entry.field_id);
- return false;
- }
- }
- }
+// gen_amalgamated expanded: #include "perfetto/ext/base/scoped_file.h"
+// gen_amalgamated expanded: #include "perfetto/ext/base/status_or.h"
+// gen_amalgamated expanded: #include "perfetto/ext/tracing/core/shared_memory.h"
- // Temporary storage for each message. Cleared on every END_OF_MESSAGE.
- std::vector<uint32_t> direct_indexed_fields;
- std::vector<uint32_t> ranges;
- uint32_t max_msg_index = 0;
- uint32_t current_msg_index = 0;
- size_t overlay_idx = 0;
+namespace perfetto {
- auto add_directly_indexed_field = [&](uint32_t field_id, uint32_t msg_id) {
- PERFETTO_DCHECK(field_id > 0 && field_id < kDirectlyIndexLimit);
- direct_indexed_fields.resize(std::max(direct_indexed_fields.size(),
- static_cast<size_t>(field_id) + 1));
- direct_indexed_fields[field_id] = kAllowed | msg_id;
+// Implements the SharedMemory and its factory for the posix-based transport.
+class PosixSharedMemory : public SharedMemory {
+ public:
+ class Factory : public SharedMemory::Factory {
+ public:
+ ~Factory() override;
+ std::unique_ptr<SharedMemory> CreateSharedMemory(size_t) override;
};
- auto add_range = [&](uint32_t id_start, uint32_t id_end, uint32_t msg_id) {
- PERFETTO_DCHECK(id_end > id_start);
- PERFETTO_DCHECK(id_start >= kDirectlyIndexLimit);
- ranges.emplace_back(id_start);
- ranges.emplace_back(id_end);
- ranges.emplace_back(kAllowed | msg_id);
- };
+ // Creates and maps a shared memory region of |size| bytes.
+ // Uses a memfd with seals that prevent resizing and adding further seals.
+ // In-tree Android builds require a sealed memfd.
+ // Other builds fall back to an unlinked temporary file if memfd creation
+ // fails.
+ // Returns an error status on failure.
+ static base::StatusOr<std::unique_ptr<PosixSharedMemory>> Create(size_t size);
+
+ // Mmaps an existing SHM region for shared read/write access.
+ // - Takes ownership of the descriptor, also on failure.
+ // - Returns nullptr if descriptor validation fails.
+ // - Also returns nullptr if mmap() fails (e.g. OOM).
+ // - Rejects an empty file, and a file larger than |max_size|, before mmap().
+ // - If |require_seals_if_supported| is true and the system supports
+ // memfd_create, requires F_SEAL_SEAL, F_SEAL_GROW and F_SEAL_SHRINK
+ // before it reads the size.
+ static std::unique_ptr<PosixSharedMemory> AttachToFd(
+ base::ScopedFile,
+ bool require_seals_if_supported,
+ size_t max_size);
- // Merges overlay entries into the current message being built.
- //
- // This function processes overlay entries for the current message up to (and
- // including) the given |field_id|. Since both base bytecode and overlay are
- // sorted by (msg_index, field_id), we can use a two-pointer merge approach:
- // - Entries with field_id < the given field_id are ADDed as new fields
- // - An entry with field_id == the given field_id is an UPGRADE (returned)
- // - Entries with field_id > the given field_id are left for later
- //
- // Pass std::numeric_limits<uint32_t>::max() as field_id to drain all
- // remaining entries for the current message (called at EndOfMessage).
- //
- // Returns:
- // - The msg_id to use if there's an exact match (upgrade case)
- // - 0 if no match (use the base bytecode's msg_id)
- // - std::numeric_limits<uint32_t>::max() on error
- constexpr uint32_t kOverlayError = std::numeric_limits<uint32_t>::max();
- auto process_overlay = [&](uint32_t field_id) -> uint32_t {
- while (overlay_idx < overlay.size()) {
- const OverlayEntry& entry = overlay[overlay_idx];
+ ~PosixSharedMemory() override;
+
+ int fd() const { return fd_.get(); }
+
+ // SharedMemory implementation.
+ using SharedMemory::start; // Equal priority to const and non-const versions
+ const void* start() const override { return start_; }
+ size_t size() const override { return size_; }
+
+ private:
+ // Returns an error status if mmap() fails.
+ static base::StatusOr<std::unique_ptr<PosixSharedMemory>> MapFD(
+ base::ScopedFile,
+ size_t);
+
+ PosixSharedMemory(void* start, size_t size, base::ScopedFile);
+ PosixSharedMemory(const PosixSharedMemory&) = delete;
+ PosixSharedMemory& operator=(const PosixSharedMemory&) = delete;
+
+ void* const start_;
+ const size_t size_;
+ base::ScopedFile fd_;
+};
+
+} // namespace perfetto
+
+#endif // OS_LINUX || OS_ANDROID || OS_APPLE
+#endif // SRC_TRACING_IPC_POSIX_SHARED_MEMORY_H_
+/*
+ * 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.
+ */
- // Stop if this entry is for a later message or a later field.
- if (entry.msg_index > current_msg_index ||
- (entry.msg_index == current_msg_index && entry.field_id > field_id)) {
- break;
- }
+// gen_amalgamated expanded: #include "src/tracing/ipc/posix_shared_memory.h"
- // Message indexes are dense and we verified above that we are sorted
- // so this must be for the current message.
- PERFETTO_DCHECK(entry.msg_index == current_msg_index);
+#if PERFETTO_BUILDFLAG(PERFETTO_OS_LINUX) || \
+ PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID) || \
+ PERFETTO_BUILDFLAG(PERFETTO_OS_APPLE) || \
+ PERFETTO_BUILDFLAG(PERFETTO_OS_FUCHSIA) || \
+ PERFETTO_BUILDFLAG(PERFETTO_OS_FREEBSD) || \
+ PERFETTO_BUILDFLAG(PERFETTO_OS_WASM)
- // Exact match - this is an upgrade. Return the msg_id for the caller.
- if (entry.field_id == field_id) {
- ++overlay_idx;
- return entry.message_id;
- }
+#include <errno.h>
+#include <fcntl.h>
+#include <stdint.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <unistd.h>
- // entry_field < field_id: This is a new field to ADD.
- if (entry.field_id < kDirectlyIndexLimit) {
- add_directly_indexed_field(entry.field_id, entry.message_id);
- } else {
- add_range(entry.field_id, entry.field_id + 1, entry.message_id);
- }
- ++overlay_idx;
- }
- // No match found.
- return 0;
- };
+#include <cinttypes>
+#include <memory>
+#include <utility>
- bool is_eom = true;
- for (size_t i = 0; i < words.size(); ++i) {
- const uint32_t word = words[i];
- const bool has_next_word = i < words.size() - 1;
- const uint32_t opcode = word & kOpcodeMask;
- const uint32_t field_id = word >> kOpcodeShift;
+// gen_amalgamated expanded: #include "perfetto/base/logging.h"
+// gen_amalgamated expanded: #include "perfetto/ext/base/status_macros.h"
+// gen_amalgamated expanded: #include "perfetto/ext/base/temp_file.h"
+// gen_amalgamated expanded: #include "src/tracing/ipc/memfd.h"
- is_eom = opcode == kFilterOpcode_EndOfMessage;
- if (field_id == 0 && opcode != kFilterOpcode_EndOfMessage) {
- PERFETTO_DLOG("bytecode error @ word %zu, invalid field id (0)", i);
- return false;
- }
+namespace perfetto {
- if (opcode == kFilterOpcode_SimpleField ||
- opcode == kFilterOpcode_NestedField ||
- opcode == kFilterOpcode_FilterString ||
- opcode == kFilterOpcode_FilterStringWithType) {
- // Field words are organized as follow:
- // MSB: 1 if allowed, 0 if not allowed.
- // Remaining bits:
- // Message index in the case of nested (non-simple) messages.
- // 0x7fff0000-0x7ffffffe for string fields with semantic type.
- // 0x7ffffffe in the case of string fields which need filtering.
- // 0x7fffffff in the case of simple fields.
- uint32_t msg_id;
- if (opcode == kFilterOpcode_SimpleField) {
- msg_id = kSimpleField;
- } else if (opcode == kFilterOpcode_FilterString) {
- msg_id = kFilterStringField;
- } else if (opcode == kFilterOpcode_FilterStringWithType) {
- // The next word in the bytecode contains the semantic type.
- if (!has_next_word) {
- PERFETTO_DLOG(
- "bytecode error @ word %zu: unterminated filter string with type",
- i);
- return false;
- }
- uint32_t semantic_type = words[++i];
- msg_id =
- kFilterStringFieldWithType | (semantic_type & kSemanticTypeMask);
- } else { // FILTER_OPCODE_NESTED_FIELD
- // The next word in the bytecode contains the message index.
- if (!has_next_word) {
- PERFETTO_DLOG("bytecode error @ word %zu: unterminated nested field",
- i);
- return false;
- }
- msg_id = words[++i];
- max_msg_index = std::max(max_msg_index, msg_id);
- }
+namespace {
+int kFileSeals = F_SEAL_SHRINK | F_SEAL_GROW | F_SEAL_SEAL;
+} // namespace
- // Process overlay: add any fields that come before this one, and check
- // if this field should be upgraded.
- uint32_t overlay_msg_id = process_overlay(field_id);
- if (overlay_msg_id == kOverlayError) {
- return false;
- }
- if (overlay_msg_id != 0) {
- msg_id = overlay_msg_id;
- }
+// static
+base::StatusOr<std::unique_ptr<PosixSharedMemory>> PosixSharedMemory::Create(
+ size_t size) {
+ if (size == 0)
+ return base::ErrStatus("Invalid shmem size 0");
- if (field_id < kDirectlyIndexLimit) {
- add_directly_indexed_field(field_id, msg_id);
- } else {
- // In the case of a large field id (rare) we waste an extra word and
- // represent it as a range. Doesn't make sense to introduce extra
- // complexity to deal with rare cases like this.
- add_range(field_id, field_id + 1, msg_id);
- }
- } else if (opcode == kFilterOpcode_SimpleFieldRange) {
- if (!has_next_word) {
- PERFETTO_DLOG("bytecode error @ word %zu: unterminated range", i);
- return false;
- }
- const uint32_t range_len = words[++i];
- const uint32_t range_end = field_id + range_len; // STL-style, excl.
- uint32_t id = field_id;
+ base::ScopedFile fd =
+ CreateMemfd("perfetto_shmem", MFD_CLOEXEC | MFD_ALLOW_SEALING);
+ const bool is_memfd = !!fd;
+ if (!is_memfd) {
+#if PERFETTO_BUILDFLAG(PERFETTO_ANDROID_BUILD)
+ // In-tree builds only allow memfd, so the service can verify the seals.
+ // TODO: if this fails on Android we should fall back on ashmem.
+ return base::ErrStatus("memfd_create() failed: %s", strerror(errno));
+#else
+ ASSIGN_OR_RETURN(
+ base::TempFile temp_file,
+ base::TempFile::Create(base::TempFile::LinkMode::kUnlinked));
+ fd = temp_file.ReleaseFD();
+#endif
+ }
- // Here's the subtle complexity: at the bytecode level, we don't know
- // anything about the kDirectlyIndexLimit. It is legit to define a range
- // that spans across the direct-indexing threshold (e.g. 126-132). In that
- // case we want to add all the elements < the indexing to the O(1) bucket
- // and add only the remaining range as a non-indexed range.
- for (; id < range_end && id < kDirectlyIndexLimit; ++id)
- add_directly_indexed_field(id, kAllowed | kSimpleField);
- PERFETTO_DCHECK(id >= kDirectlyIndexLimit || id == range_end);
- if (id < range_end)
- add_range(id, range_end, kSimpleField);
- } else if (opcode == kFilterOpcode_EndOfMessage) {
- // Drain any remaining overlay entries for this message.
- if (process_overlay(std::numeric_limits<uint32_t>::max()) ==
- kOverlayError) {
- return false;
- }
+ if (ftruncate(fd.get(), static_cast<off_t>(size)) != 0)
+ return base::ErrStatus("Couldn't resize shmem FD: %s", strerror(errno));
- // Verify that the ranges are non-overlapping. Assumes that the ranges
- // are sorted (they are, because the bytecode is sorted).
- for (size_t r = 0; r + 3 < ranges.size(); r += 3) {
- const uint32_t prev_range_end = ranges[r + 1];
- const uint32_t curr_range_start = ranges[r + 3];
- if (curr_range_start < prev_range_end) {
- PERFETTO_DLOG(
- "bytecode error @ message %u: overlapping ranges [%u, %u) "
- "and [%u, ...)",
- current_msg_index, ranges[r], prev_range_end, curr_range_start);
- return false;
- }
- }
+ if (is_memfd && fcntl(fd.get(), F_ADD_SEALS, kFileSeals) != 0)
+ return base::ErrStatus("Couldn't seal shmem FD: %s", strerror(errno));
- // For each message append:
- // 1. The "header" word telling how many directly indexed fields there
- // are.
- // 2. The words for the directly indexed fields (id < 128).
- // 3. The rest of the fields, encoded as ranges.
- // Also update the |message_offset_| index to remember the word offset for
- // the current message.
- message_offset_.emplace_back(static_cast<uint32_t>(words_.size()));
- words_.emplace_back(static_cast<uint32_t>(direct_indexed_fields.size()));
- words_.insert(words_.end(), direct_indexed_fields.begin(),
- direct_indexed_fields.end());
- words_.insert(words_.end(), ranges.begin(), ranges.end());
- direct_indexed_fields.clear();
- ranges.clear();
- ++current_msg_index;
- } else {
- PERFETTO_DLOG("bytecode error @ word %zu: invalid opcode (%x)", i, word);
- return false;
- }
- } // (for word in bytecode).
+ return MapFD(std::move(fd), size);
+}
- if (!is_eom) {
- PERFETTO_DLOG(
- "bytecode error: end of message not the last word in the bytecode");
- return false;
- }
+// static
+std::unique_ptr<PosixSharedMemory> PosixSharedMemory::AttachToFd(
+ base::ScopedFile fd,
+ bool require_seals_if_supported,
+ size_t max_size) {
+ if (!fd)
+ return nullptr;
+ bool requires_seals = require_seals_if_supported;
- if (overlay_idx != overlay.size()) {
- PERFETTO_DLOG("bytecode error: overlay contains %zu unconsumed entries",
- overlay.size() - overlay_idx);
- return false;
+#if PERFETTO_BUILDFLAG(PERFETTO_ANDROID_BUILD)
+ // In-tree kernels all support memfd.
+ PERFETTO_CHECK(HasMemfdSupport());
+#else
+ // In out-of-tree builds, we only require seals if the kernel supports memfd.
+ if (requires_seals)
+ requires_seals = HasMemfdSupport();
+#endif
+
+ if (requires_seals) {
+ // If the system supports memfd, we require a sealed memfd.
+ int res = fcntl(*fd, F_GET_SEALS);
+ if (res == -1 || (res & kFileSeals) != kFileSeals) {
+ PERFETTO_PLOG("Couldn't verify file seals on shmem FD");
+ return nullptr;
+ }
}
- if (max_msg_index > 0 && max_msg_index >= message_offset_.size()) {
- PERFETTO_DLOG(
- "bytecode error: a message index (%u) is out of range "
- "(num_messages=%zu)",
- max_msg_index, message_offset_.size());
- return false;
+ struct stat stat_buf = {};
+ if (fstat(fd.get(), &stat_buf) != 0) {
+ PERFETTO_PLOG("Couldn't stat shmem FD");
+ return nullptr;
+ }
+ if (stat_buf.st_size <= 0 ||
+ static_cast<uint64_t>(stat_buf.st_size) > max_size) {
+ PERFETTO_ELOG("Invalid shmem FD size %" PRId64 " (max %zu)",
+ static_cast<int64_t>(stat_buf.st_size), max_size);
+ return nullptr;
+ }
+ auto memory = MapFD(std::move(fd), static_cast<size_t>(stat_buf.st_size));
+ if (!memory.ok()) {
+ PERFETTO_ELOG("%s", memory.status().c_message());
+ return nullptr;
}
+ return std::move(*memory);
+}
- // Add a final entry to |message_offset_| so we can tell where the last
- // message ends without an extra branch in the Query() hotpath.
- message_offset_.emplace_back(static_cast<uint32_t>(words_.size()));
+// static
+base::StatusOr<std::unique_ptr<PosixSharedMemory>> PosixSharedMemory::MapFD(
+ base::ScopedFile fd,
+ size_t size) {
+ PERFETTO_DCHECK(fd);
+ PERFETTO_DCHECK(size > 0);
+ void* start =
+ mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd.get(), 0);
+ if (start == MAP_FAILED)
+ return base::ErrStatus("Couldn't map shmem FD: %s", strerror(errno));
+ return std::unique_ptr<PosixSharedMemory>(
+ new PosixSharedMemory(start, size, std::move(fd)));
+}
- return true;
+PosixSharedMemory::PosixSharedMemory(void* start,
+ size_t size,
+ base::ScopedFile fd)
+ : start_(start), size_(size), fd_(std::move(fd)) {}
+
+PosixSharedMemory::~PosixSharedMemory() {
+ munmap(start(), size());
}
-FilterBytecodeParser::QueryResult FilterBytecodeParser::Query(
- uint32_t msg_index,
- uint32_t field_id) const {
- FilterBytecodeParser::QueryResult res{false, 0u, 0u};
- if (static_cast<uint64_t>(msg_index) + 1 >=
- static_cast<uint64_t>(message_offset_.size())) {
- return res;
- }
- const uint32_t start_offset = message_offset_[msg_index];
- // These are DCHECKs and not just CHECKS because the |words_| is populated
- // by the LoadInternal call above. These cannot be violated with a malformed
- // bytecode.
- PERFETTO_DCHECK(start_offset < words_.size());
- const uint32_t* word = &words_[start_offset];
- const uint32_t end_off = message_offset_[msg_index + 1];
- const uint32_t* const end = words_.data() + end_off;
- PERFETTO_DCHECK(end > word && end <= words_.data() + words_.size());
- const uint32_t num_directly_indexed = *(word++);
- PERFETTO_DCHECK(num_directly_indexed <= kDirectlyIndexLimit);
- PERFETTO_DCHECK(word + num_directly_indexed <= end);
- uint32_t field_state = 0;
- if (PERFETTO_LIKELY(field_id < num_directly_indexed)) {
- PERFETTO_DCHECK(&word[field_id] < end);
- field_state = word[field_id];
- } else {
- for (word = word + num_directly_indexed; word + 2 < end;) {
- const uint32_t range_start = *(word++);
- const uint32_t range_end = *(word++);
- const uint32_t range_state = *(word++);
- if (field_id >= range_start && field_id < range_end) {
- field_state = range_state;
- break;
- }
- } // for (word in ranges)
- } // if (field_id >= num_directly_indexed)
+PosixSharedMemory::Factory::~Factory() {}
- res.allowed = (field_state & kAllowed) != 0;
- res.nested_msg_index = field_state & ~kAllowed;
- // Extract semantic type if this is a FilterStringFieldWithType.
- // Exclude kFilterStringField (0x7ffffffe) which doesn't have semantic type.
- if ((res.nested_msg_index & kFilterStringFieldWithTypeMask) ==
- kFilterStringFieldWithType &&
- res.nested_msg_index != kFilterStringField) {
- res.semantic_type = res.nested_msg_index & kSemanticTypeMask;
- }
- PERFETTO_DCHECK(!res.nested_msg_field() ||
- res.nested_msg_index < message_offset_.size() - 1);
- return res;
+std::unique_ptr<SharedMemory> PosixSharedMemory::Factory::CreateSharedMemory(
+ size_t size) {
+ return PosixSharedMemory::Create(size).ValueOrDie();
}
-} // namespace protozero
-// gen_amalgamated begin source: src/protozero/filtering/string_filter.cc
-// gen_amalgamated begin header: src/protozero/filtering/string_filter.h
+} // namespace perfetto
+
+#endif // OS_LINUX || OS_ANDROID || OS_APPLE
+// gen_amalgamated begin source: src/tracing/ipc/shared_memory_windows.cc
+// gen_amalgamated begin header: src/tracing/ipc/shared_memory_windows.h
/*
- * Copyright (C) 2023 The Android Open Source Project
+ * Copyright (C) 2021 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.
@@ -58211,136 +63331,217 @@ FilterBytecodeParser::QueryResult FilterBytecodeParser::Query(
* limitations under the License.
*/
-#ifndef SRC_PROTOZERO_FILTERING_STRING_FILTER_H_
-#define SRC_PROTOZERO_FILTERING_STRING_FILTER_H_
+#ifndef SRC_TRACING_IPC_SHARED_MEMORY_WINDOWS_H_
+#define SRC_TRACING_IPC_SHARED_MEMORY_WINDOWS_H_
+
+// gen_amalgamated expanded: #include "perfetto/base/build_config.h"
+
+#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
-#include <array>
-#include <cstddef>
-#include <cstdint>
-#include <optional>
#include <string>
-#include <string_view>
-#include <vector>
-// gen_amalgamated expanded: #include "perfetto/base/logging.h"
-// gen_amalgamated expanded: #include "perfetto/ext/base/regex.h"
-// gen_amalgamated expanded: #include "perfetto/public/compiler.h"
+// gen_amalgamated expanded: #include "perfetto/base/build_config.h"
+// gen_amalgamated expanded: #include "perfetto/ext/base/scoped_file.h"
+// gen_amalgamated expanded: #include "perfetto/ext/tracing/core/shared_memory.h"
-namespace protozero {
+namespace perfetto {
-// Performs filtering of strings in an "iptables" style. See the comments in
-// |TraceConfig.TraceFilter| for information on how this class works.
-class StringFilter {
+// Implements the SharedMemory and its factory for the Windows IPC transport.
+// This used only for standalone builds and NOT in chromium, which instead uses
+// a custom Mojo wrapper (MojoSharedMemory in chromium's //services/tracing/).
+class SharedMemoryWindows : public SharedMemory {
public:
- // Bitmask for semantic types. Supports up to 128 semantic types.
- class SemanticTypeMask {
+ class Factory : public SharedMemory::Factory {
public:
- using Word = uint64_t;
- static constexpr size_t kBitsPerWord = sizeof(Word) * 8;
- static constexpr size_t kLimit = 128;
+ ~Factory() override;
+ std::unique_ptr<SharedMemory> CreateSharedMemory(size_t) override;
+ };
- // Returns a SemanticTypeMask with only bit 0 set (UNSPECIFIED only).
- // UNSPECIFIED is its own category and only matches if bit 0 is set.
- static constexpr SemanticTypeMask Unspecified() {
- return SemanticTypeMask(Word(1), Word(0));
- }
+ // Create a brand new SHM region.
+ enum Flags { kNone = 0, kInheritableHandles };
+ static std::unique_ptr<SharedMemoryWindows> Create(
+ size_t size,
+ Flags flags = Flags::kNone);
+ static std::unique_ptr<SharedMemoryWindows> Attach(const std::string& key);
+ static std::unique_ptr<SharedMemoryWindows> AttachToHandleWithKey(
+ base::ScopedPlatformHandle fd,
+ const std::string& key);
+ ~SharedMemoryWindows() override;
+ const std::string& key() const { return key_; }
+ const base::ScopedPlatformHandle& handle() const { return handle_; }
- // Creates a SemanticTypeMask from raw word values (for testing).
- static constexpr SemanticTypeMask FromWords(Word w0, Word w1) {
- return SemanticTypeMask(w0, w1);
- }
+ // SharedMemory implementation.
+ using SharedMemory::start; // Equal priority to const and non-const versions
+ const void* start() const override { return start_; }
+ size_t size() const override { return size_; }
- // Default constructor: no bits set.
- constexpr SemanticTypeMask() = default;
+ private:
+ SharedMemoryWindows(void* start,
+ size_t size,
+ std::string,
+ base::ScopedPlatformHandle);
+ SharedMemoryWindows(const SharedMemoryWindows&) = delete;
+ SharedMemoryWindows& operator=(const SharedMemoryWindows&) = delete;
- // Sets the bit for |semantic_type|.
- PERFETTO_ALWAYS_INLINE void Set(uint32_t semantic_type) {
- PERFETTO_DCHECK(semantic_type < kLimit);
- uint32_t word_index = semantic_type / kBitsPerWord;
- uint32_t bit_index = semantic_type % kBitsPerWord;
- words_[word_index] |= Word(1) << bit_index;
- }
+ void* const start_;
+ const size_t size_;
+ std::string key_;
+ base::ScopedPlatformHandle handle_;
+};
- // Returns true if the bit for |semantic_type| is set.
- PERFETTO_ALWAYS_INLINE bool IsSet(uint32_t semantic_type) const {
- // If beyond supported range, return true (safe default: apply rule).
- if (PERFETTO_UNLIKELY(semantic_type >= kLimit)) {
- return true;
- }
- uint32_t word_index = semantic_type / kBitsPerWord;
- uint32_t bit_index = semantic_type % kBitsPerWord;
- return (words_[word_index] & (Word(1) << bit_index)) != 0;
- }
+} // namespace perfetto
- private:
- constexpr SemanticTypeMask(Word w0, Word w1) : words_{w0, w1} {}
+#endif // OS_WIN
- std::array<Word, 2> words_ = {};
- };
+#endif // SRC_TRACING_IPC_SHARED_MEMORY_WINDOWS_H_
+/*
+ * Copyright (C) 2021 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.
+ */
- enum class Policy : uint8_t {
- kMatchRedactGroups = 1,
- kAtraceMatchRedactGroups = 2,
- kMatchBreak = 3,
- kAtraceMatchBreak = 4,
- kAtraceRepeatedSearchRedactGroups = 5,
- };
+// gen_amalgamated expanded: #include "src/tracing/ipc/shared_memory_windows.h"
- // Adds a new rule for filtering strings.
- //
- // If `name` is non-empty and a rule with the same name already exists, it
- // will be replaced; otherwise the rule is appended.
- //
- // `semantic_type_mask` is a bitmask indicating which semantic types this rule
- // applies to. UNSPECIFIED (0) is its own category and only matches if bit 0
- // is explicitly set. Defaults to matching only UNSPECIFIED.
- void AddRule(
- Policy policy,
- std::string_view pattern,
- std::string atrace_payload_starts_with,
- std::string name = {},
- SemanticTypeMask semantic_type_mask = SemanticTypeMask::Unspecified());
+#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
+
+#include <memory>
+#include <random>
+
+#include <windows.h>
+
+// gen_amalgamated expanded: #include "perfetto/base/logging.h"
+// gen_amalgamated expanded: #include "perfetto/ext/base/string_utils.h"
+
+namespace perfetto {
+
+// static
+std::unique_ptr<SharedMemoryWindows> SharedMemoryWindows::Create(size_t size,
+ Flags flags) {
+ base::ScopedPlatformHandle shmem_handle;
+ std::random_device rnd_dev;
+ uint64_t rnd_key = (static_cast<uint64_t>(rnd_dev()) << 32) | rnd_dev();
+ std::string key = "perfetto_shm_" + base::Uint64ToHexStringNoPrefix(rnd_key);
+
+ SECURITY_ATTRIBUTES security_attributes = {};
+ security_attributes.nLength = sizeof(SECURITY_ATTRIBUTES);
+ if (flags & Flags::kInheritableHandles)
+ security_attributes.bInheritHandle = TRUE;
+
+ shmem_handle.reset(CreateFileMappingA(
+ INVALID_HANDLE_VALUE, // Use paging file.
+ &security_attributes, PAGE_READWRITE,
+ static_cast<DWORD>(size >> 32), // maximum object size (high-order DWORD)
+ static_cast<DWORD>(size), // maximum object size (low-order DWORD)
+ key.c_str()));
+
+ if (!shmem_handle) {
+ PERFETTO_PLOG("CreateFileMapping() call failed");
+ return nullptr;
+ }
+ void* start =
+ MapViewOfFile(*shmem_handle, FILE_MAP_ALL_ACCESS, /*offsetHigh=*/0,
+ /*offsetLow=*/0, size);
+ if (!start) {
+ PERFETTO_PLOG("MapViewOfFile() failed");
+ return nullptr;
+ }
+
+ return std::unique_ptr<SharedMemoryWindows>(new SharedMemoryWindows(
+ start, size, std::move(key), std::move(shmem_handle)));
+}
+
+// static
+std::unique_ptr<SharedMemoryWindows> SharedMemoryWindows::Attach(
+ const std::string& key) {
+ base::ScopedPlatformHandle shmem_handle;
+ shmem_handle.reset(
+ OpenFileMappingA(FILE_MAP_ALL_ACCESS, /*inherit=*/false, key.c_str()));
+ if (!shmem_handle) {
+ PERFETTO_PLOG("Failed to OpenFileMapping()");
+ return nullptr;
+ }
+
+ void* start =
+ MapViewOfFile(*shmem_handle, FILE_MAP_ALL_ACCESS, /*offsetHigh=*/0,
+ /*offsetLow=*/0, /*dwNumberOfBytesToMap=*/0);
+ if (!start) {
+ PERFETTO_PLOG("MapViewOfFile() failed");
+ return nullptr;
+ }
- // Tries to filter the given string. Returns true if the string was modified
- // in any way, false otherwise. Uses semantic_type=0 (unspecified).
- bool MaybeFilter(char* ptr, size_t len) const {
- return MaybeFilter(ptr, len, /*semantic_type=*/0);
+ MEMORY_BASIC_INFORMATION info{};
+ if (!VirtualQuery(start, &info, sizeof(info))) {
+ PERFETTO_PLOG("VirtualQuery() failed");
+ return nullptr;
}
+ size_t size = info.RegionSize;
+ return std::unique_ptr<SharedMemoryWindows>(
+ new SharedMemoryWindows(start, size, key, std::move(shmem_handle)));
+}
- // Tries to filter the given string with a specific semantic type.
- // Only rules that match the semantic type (or have no type restriction)
- // are applied.
- bool MaybeFilter(char* ptr, size_t len, uint32_t semantic_type) const {
- if (len == 0 || rules_.empty()) {
- return false;
- }
- return MaybeFilterInternal(ptr, len, semantic_type);
+// static
+std::unique_ptr<SharedMemoryWindows> SharedMemoryWindows::AttachToHandleWithKey(
+ base::ScopedPlatformHandle shmem_handle,
+ const std::string& key) {
+ void* start =
+ MapViewOfFile(*shmem_handle, FILE_MAP_ALL_ACCESS, /*offsetHigh=*/0,
+ /*offsetLow=*/0, /*dwNumberOfBytesToMap=*/0);
+ if (!start) {
+ PERFETTO_PLOG("MapViewOfFile() failed");
+ return nullptr;
}
- private:
- struct Rule {
- Policy policy;
- std::optional<perfetto::base::CopyableRegex> pattern;
- std::string atrace_payload_starts_with;
- std::string name;
- SemanticTypeMask semantic_type_mask = SemanticTypeMask::Unspecified();
- };
+ MEMORY_BASIC_INFORMATION info{};
+ if (!VirtualQuery(start, &info, sizeof(info))) {
+ PERFETTO_PLOG("VirtualQuery() failed");
+ return nullptr;
+ }
+ size_t size = info.RegionSize;
- bool MaybeFilterInternal(char* ptr, size_t len, uint32_t semantic_type) const;
+ return std::unique_ptr<SharedMemoryWindows>(
+ new SharedMemoryWindows(start, size, key, std::move(shmem_handle)));
+}
- // All rules, in the order they were added.
- std::vector<Rule> rules_;
+SharedMemoryWindows::SharedMemoryWindows(void* start,
+ size_t size,
+ std::string key,
+ base::ScopedPlatformHandle handle)
+ : start_(start),
+ size_(size),
+ key_(std::move(key)),
+ handle_(std::move(handle)) {}
- // Reusable buffer for regex match groups, avoiding heap allocations on each
- // filter call.
- mutable std::vector<std::string_view> matches_;
-};
+SharedMemoryWindows::~SharedMemoryWindows() {
+ if (start_)
+ UnmapViewOfFile(start_);
+}
-} // namespace protozero
+SharedMemoryWindows::Factory::~Factory() = default;
-#endif // SRC_PROTOZERO_FILTERING_STRING_FILTER_H_
+std::unique_ptr<SharedMemory> SharedMemoryWindows::Factory::CreateSharedMemory(
+ size_t size) {
+ return SharedMemoryWindows::Create(size);
+}
+
+} // namespace perfetto
+
+#endif // !OS_WIN
+// gen_amalgamated begin source: src/tracing/v2/producer_ring_buffer_arbiter.cc
+// gen_amalgamated begin header: src/tracing/v2/producer_ring_buffer_arbiter.h
+// gen_amalgamated begin header: src/tracing/v2/shared_ring_buffer.h
+// gen_amalgamated begin header: src/tracing/v2/shared_ring_buffer_abi.h
/*
- * Copyright (C) 2023 The Android Open Source Project
+ * Copyright (C) 2026 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.
@@ -58355,398 +63556,870 @@ class StringFilter {
* limitations under the License.
*/
-// gen_amalgamated expanded: #include "src/protozero/filtering/string_filter.h"
+#ifndef SRC_TRACING_V2_SHARED_RING_BUFFER_ABI_H_
+#define SRC_TRACING_V2_SHARED_RING_BUFFER_ABI_H_
+
+#include <stddef.h>
+#include <stdint.h>
+#include <string.h>
#include <algorithm>
-#include <cstdint>
-#include <cstring>
-#include <string>
-#include <string_view>
-#include <utility>
-#include <vector>
+#include <atomic>
+#include <optional>
-// gen_amalgamated expanded: #include "perfetto/public/compiler.h"
+// gen_amalgamated expanded: #include "perfetto/base/logging.h"
+// gen_amalgamated expanded: #include "perfetto/base/status.h"
+// gen_amalgamated expanded: #include "perfetto/ext/base/bits.h"
+// gen_amalgamated expanded: #include "perfetto/ext/base/status_or.h"
+// gen_amalgamated expanded: #include "perfetto/ext/base/utils.h"
+// gen_amalgamated expanded: #include "perfetto/ext/tracing/core/basic_types.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/proto_utils.h"
+// gen_amalgamated expanded: #include "src/tracing/ipc/memfd.h"
-namespace protozero {
-namespace {
+namespace perfetto::tracing_v2 {
-constexpr std::string_view kRedacted = "P60REDACTED";
-constexpr char kRedactedDash = '-';
+// Shared-memory ABI for a tracing-v2 producer ring buffer.
+// Protocol: RFC 0046,
+// https://github.com/google/perfetto/discussions/7120.
+// Parent design: RFC 0014, https://github.com/google/perfetto/discussions/4508.
+//
+// Several trace writers can write at once. One reader drains their data in
+// reservation order. A relocated fragment gets a later reservation.
+//
+// The ring buffer has one header followed by fixed-size chunks:
+// - The header holds the read and write positions.
+// - Each chunk starts with an atomic state word. It records ownership and the
+// number of published fragments while the chunk belongs to a writer.
+//
+// The ABI assumes little-endian producer and service processes.
-// Returns a pointer to the first character after the tgid pipe character in
-// the atrace string given by [ptr, end). Returns null if no such character
-// exists.
+// Sharing over IPC
+// ----------------
//
-// Examples:
-// E|1024 -> nullptr
-// foobarbaz -> nullptr
-// B|1024|x -> pointer to x
-PERFETTO_ALWAYS_INLINE const char* FindAtracePayloadPtr(const char* ptr,
- const char* end) {
- // Don't even bother checking any strings which are so short that they could
- // not contain a post-tgid section. This filters out strings like "E|" which
- // emitted by Bionic.
- //
- // Also filter out any other strings starting with "E" as they never contain
- // anything past the tgid: this removes >half of the strings for ~zero cost.
- static constexpr size_t kEarliestSecondPipeIndex = 2;
- const char* search_start = ptr + kEarliestSecondPipeIndex;
- if (PERFETTO_UNLIKELY(search_start >= end || *ptr == 'E')) {
- return nullptr;
- }
+// A producer in another process shares the ring buffer with the service as a
+// sealed memfd. Without memfd, IPC producers and services use only v1.
+//
+// IPC code uses the two checks below, not memfd directly. If tracing v2 ever
+// needs more from the platform, only these checks change.
- // We skipped past the first '|' character by starting at the character at
- // index 2. Just find the next pipe character (i.e. the one after tgid) using
- // memchr.
- const char* pipe = static_cast<const char*>(
- memchr(search_start, '|', size_t(end - search_start)));
- return pipe ? pipe + 1 : nullptr;
+// Build-time check. True if the build has the memfd code.
+// It guards the code that shares the memfd. Part of that code, such as
+// PosixSharedMemory, does not build on Windows.
+#define PERFETTO_TRACING_V2_IPC() PERFETTO_MEMFD_ENABLED()
+
+// Runtime check. True if the kernel supports memfd.
+// Always false when PERFETTO_TRACING_V2_IPC() is false.
+//
+// Only IPC code may call this. HasMemfdSupport() is in src/tracing/ipc:common,
+// which only IPC builds have.
+inline bool IpcSupportsTracingV2() {
+ return HasMemfdSupport();
}
-PERFETTO_ALWAYS_INLINE bool StartsWith(const char* ptr,
- const char* end,
- const std::string& starts_with) {
- // Verify that the atrace string has enough characters to match against all
- // the characters in the "starts with" string.
- size_t len = starts_with.size();
- if (PERFETTO_UNLIKELY(ptr + len > end))
- return false;
+// Shared-memory layout
+// --------------------
+//
+// +------------------------+---------+---------+---------+-----+
+// | RingBufferHeader, 64 B | chunk 0 | chunk 1 | chunk 2 | ... |
+// +------------------------+---------+---------+---------+-----+
+// 0 64
- // Empty string matches everything.
- if (PERFETTO_UNLIKELY(len == 0))
- return true;
+// Chunks must hold several small fragments to amortize their header overhead.
+constexpr uint32_t kMinChunkSize = 256;
- // Quick rejection: check first character before expensive memcmp.
- // This is very effective since most strings don't match.
- if (PERFETTO_LIKELY(*ptr != *starts_with.data()))
- return false;
+// Maximum chunk size, including the header. The service copies a chunk
+// without its header (at least 4 bytes) into one TBChunk, which holds at most
+// 64 KiB - 1 bytes.
+constexpr uint32_t kMaxChunkSize = 64 * 1024;
- // If first char matches, do full memcmp for remaining characters.
- return memcmp(ptr + 1, starts_with.data() + 1, len - 1) == 0;
-}
+// Each chunk's atomic<uint32_t> requires four-byte alignment.
+constexpr uint32_t kChunkAlignmentBytes = 4;
-void RedactMatches(const std::vector<std::string_view>& matches) {
- // Go through every group in the matches.
- for (size_t i = 1; i < matches.size(); ++i) {
- const auto& match = matches[i];
- // Skip unmatched optional groups: empty string_view may have nullptr
- // data(), and passing nullptr to memcpy/memset is UB even with size 0.
- if (match.empty())
- continue;
+// Minimum supported chunk count.
+constexpr uint32_t kMinChunksPerRing = 2;
- // Overwrite the match with characters from |kRedacted|. If match is
- // smaller, we will not use all of |kRedacted| but that's fine (i.e. we
- // will overwrite with a truncated |kRedacted|).
- size_t match_len = match.size();
- size_t redacted_len = std::min(match_len, kRedacted.size());
- memcpy(const_cast<char*>(match.data()), kRedacted.data(), redacted_len);
+// Chunk area size (excluding the header) used when the SMB size hint is 0.
+constexpr size_t kDefaultChunkBudgetBytes = 128 * 1024;
- // Overwrite any characters after |kRedacted| with |kRedactedDash|.
- memset(const_cast<char*>(match.data()) + redacted_len, kRedactedDash,
- match_len - redacted_len);
+// Ring buffer header
+// ------------------
+//
+// byte offset
+// 0 4 8 12 64
+// +--------------+--------------+--------------+----------------+
+// | read_pos | write_pos | num_writers_ | reserved |
+// | | | waiting | |
+// +--------------+--------------+--------------+----------------+
+// |<------- rw_positions ------>|<- atomic32 ->|
+// atomic<uint64_t>
+//
+// Writers check capacity by loading rw_positions once. In memory:
+// - The first four bytes hold read_pos.
+// - The next four bytes hold write_pos.
+// Keeping both in one atomic avoids combining counters read at different times.
+//
+// The reader is the only one that moves read_pos. It publishes a new value once
+// per drain pass and then wakes any writer parked on a full ring buffer.
+// read_pos is also the first four bytes of rw_positions, which is the address
+// the futex waits on.
+//
+// num_writers_waiting lets the reader skip a futex wake when nobody is waiting
+// for space. It is only an optimization and never decides whether the ring
+// buffer is full or who owns a chunk.
+//
+// Bytes 12..63 pad the header to one cache line.
+//
+static_assert(sizeof(std::atomic<uint32_t>) == 4 &&
+ alignof(std::atomic<uint32_t>) <= 4,
+ "Chunk state must fit in a 4-byte-aligned ABI word");
+static_assert(sizeof(std::atomic<uint64_t>) == 8,
+ "The packed positions must occupy 8 bytes");
+static_assert(std::atomic<uint32_t>::is_always_lock_free &&
+ std::atomic<uint64_t>::is_always_lock_free,
+ "Shared-memory atomics must be lock-free");
+
+struct alignas(64) RingBufferHeader {
+ std::atomic<uint64_t> rw_positions;
+ std::atomic<uint32_t> num_writers_waiting;
+ uint8_t reserved[52];
+};
+
+static_assert(offsetof(RingBufferHeader, num_writers_waiting) == 8 &&
+ offsetof(RingBufferHeader, reserved) == 12 &&
+ sizeof(RingBufferHeader) == 64,
+ "RingBufferHeader does not match the shared-memory ABI");
+
+// Logical positions and chunk indexing
+// ------------------------------------
+//
+// write_pos is the next position a writer can reserve. read_pos is the next
+// position the reader must consume. These are logical positions:
+// - They keep advancing past num_chunks across successive traversals.
+// - As uint32_t counters, they roll over from UINT32_MAX to zero.
+// - Both reader and writer map a position to a physical chunk before access.
+// ChunkIndex::FromPosition() performs that mapping modulo num_chunks.
+//
+// A writer reserves a position by advancing write_pos, then tries to claim
+// its physical chunk.
+//
+// The number of reserved positions not yet handled by the reader is:
+//
+// outstanding = uint32_t(write_pos - read_pos) <= num_chunks < 2^31
+//
+// - If outstanding is zero, write_pos == read_pos and the ring buffer is empty.
+// - If outstanding equals num_chunks, the ring buffer is full:
+// write_pos == uint32_t(read_pos + num_chunks). Writers cannot advance
+// write_pos until the reader advances read_pos to make space.
+//
+// Unsigned subtraction also works when write_pos wraps back to zero. For
+// example:
+//
+// read_pos = UINT32_MAX - 3
+// write_pos = 2
+// uint32_t(write_pos - read_pos) = 6
+//
+// A legal result is at most num_chunks. A larger result means that the two
+// positions do not describe a valid ring buffer state.
+//
+// At most one outstanding reservation maps to each physical chunk. An exact
+// comparison of the chunk's state word therefore determines ownership.
+// A delayed claim can match a later traversal after the wrap count repeats.
+// See WrapCountForPosition() for this limit.
+
+// The unsigned subtraction above is unambiguous only while fewer than 2^31
+// positions are outstanding. num_chunks is a power of two, so 2^30 is the
+// largest legal chunk count.
+constexpr uint32_t kMaxChunksPerRing = 1u << 30;
+
+// True if |chunk_size| is in [kMinChunkSize, kMaxChunkSize] and a multiple of
+// kChunkAlignmentBytes.
+constexpr bool IsValidChunkSize(uint32_t chunk_size) {
+ return chunk_size >= kMinChunkSize && chunk_size <= kMaxChunkSize &&
+ chunk_size % kChunkAlignmentBytes == 0;
+}
+
+// Validates the layout of an untrusted ring buffer and returns its chunk
+// count, or an error describing why the layout is invalid.
+// The service calls it on the ring buffer that a producer attaches.
+//
+// - Any thread can call it. It reads no shared bytes.
+// - The transport limits the mapping size separately.
+// - The SharedRingBuffer constructor treats validation errors as fatal.
+// - RingBufferSizeForShmSizeHint() works the other way, it picks a size that
+// passes this check.
+inline base::StatusOr<uint32_t> NumChunksForRingBufferLayout(
+ const void* start,
+ size_t size,
+ uint32_t chunk_size) {
+ if (!start ||
+ reinterpret_cast<uintptr_t>(start) % alignof(RingBufferHeader) != 0) {
+ return base::ErrStatus("ring buffer start is null or misaligned");
+ }
+ if (!IsValidChunkSize(chunk_size))
+ return base::ErrStatus("invalid chunk size %u", chunk_size);
+ // Subtract the header after this check to avoid overflow on 32-bit builds.
+ if (size < sizeof(RingBufferHeader))
+ return base::ErrStatus("ring buffer size %zu is below the header", size);
+ const size_t chunks_size = size - sizeof(RingBufferHeader);
+ if (chunks_size % chunk_size != 0) {
+ return base::ErrStatus("ring buffer size %zu is not header + N * %u", size,
+ chunk_size);
+ }
+ const size_t count = chunks_size / chunk_size;
+ // Two chunks form the minimum useful configuration. One chunk satisfies
+ // the ABI: write_pos - read_pos is 0 when empty and 1 when full.
+ // The Free wrap count distinguishes successive uses of that chunk.
+ //
+ // The power-of-two rule permits chunk indexing with a mask. The maximum
+ // keeps outstanding positions below 2^31 for unambiguous unsigned
+ // subtraction.
+ if (count < kMinChunksPerRing || count > kMaxChunksPerRing ||
+ !base::IsPowerOfTwo(count)) {
+ return base::ErrStatus("invalid chunk count %zu", count);
}
+ return static_cast<uint32_t>(count);
}
-} // namespace
+// Picks the size of a new ring buffer.
+// The producer calls this before it allocates its ring buffer, to turn a byte
+// size hint into a size that NumChunksForRingBufferLayout() accepts.
+//
+// - Returns the size, header included, of the largest valid ring buffer
+// whose chunks fit in |shmem_size_hint_bytes| bytes.
+// - Uses kDefaultChunkBudgetBytes if |shmem_size_hint_bytes| is zero.
+// - The header comes on top of the hint.
+// The returned size is capped at |max_shmem_size_bytes|.
+// - Returns an error status if fewer than kMinChunksPerRing chunks fit, or if
+// |chunk_size| is invalid.
+// - Any thread can call it, because it reads no shared memory.
+inline base::StatusOr<size_t> RingBufferSizeForShmSizeHint(
+ size_t shmem_size_hint_bytes,
+ size_t max_shmem_size_bytes,
+ uint32_t chunk_size) {
+ if (!IsValidChunkSize(chunk_size))
+ return base::ErrStatus("invalid chunk size %u", chunk_size);
+ if (max_shmem_size_bytes < sizeof(RingBufferHeader)) {
+ return base::ErrStatus("maximum size %zu is below the header",
+ max_shmem_size_bytes);
+ }
+
+ const size_t available_chunk_bytes = std::min(
+ shmem_size_hint_bytes ? shmem_size_hint_bytes : kDefaultChunkBudgetBytes,
+ max_shmem_size_bytes - sizeof(RingBufferHeader));
+ const size_t max_count = available_chunk_bytes / chunk_size;
+
+ // Find the largest power of two that is at most |max_count|: start at
+ // kMaxChunksPerRing, a power of two, and halve it until it fits.
+ // Every value on the way is a power of two and at most the maximum, so only
+ // the minimum chunk count is left to check.
+ static_assert(base::IsPowerOfTwo(kMaxChunksPerRing));
+ size_t count = kMaxChunksPerRing;
+ while (count > max_count)
+ count /= 2;
+
+ if (count < kMinChunksPerRing) {
+ return base::ErrStatus("no ring buffer of %u-byte chunks fits in %zu bytes",
+ chunk_size, available_chunk_bytes);
+ }
+ const size_t size = sizeof(RingBufferHeader) + count * chunk_size;
+ PERFETTO_CHECK(size <= max_shmem_size_bytes);
+ return size;
+}
-void StringFilter::AddRule(Policy policy,
- std::string_view pattern_str,
- std::string atrace_payload_starts_with,
- std::string name,
- SemanticTypeMask semantic_type_mask) {
- perfetto::base::CopyableRegex re(
- perfetto::base::Regex::CreateOrCheck(std::string(pattern_str)));
- Rule new_rule{policy, std::move(re), std::move(atrace_payload_starts_with),
- std::move(name), semantic_type_mask};
- // If name is non-empty, look for existing rule with same name and replace.
- if (!new_rule.name.empty()) {
- for (Rule& existing : rules_) {
- if (existing.name == new_rule.name) {
- existing = std::move(new_rule);
- return;
- }
- }
- }
- rules_.push_back(std::move(new_rule));
+constexpr uint64_t PackRwPositions(uint32_t write_pos, uint32_t read_pos) {
+ return (static_cast<uint64_t>(write_pos) << 32) | read_pos;
}
-bool StringFilter::MaybeFilterInternal(char* ptr,
- size_t len,
- uint32_t semantic_type) const {
- bool atrace_find_tried = false;
- const char* atrace_payload_ptr = nullptr;
- std::string_view input(ptr, len);
+constexpr uint32_t WritePosOf(uint64_t rw_positions) {
+ return static_cast<uint32_t>(rw_positions >> 32);
+}
- for (const Rule& rule : rules_) {
- if (!rule.semantic_type_mask.IsSet(semantic_type)) {
- continue;
- }
- switch (rule.policy) {
- case Policy::kMatchBreak:
- if (PERFETTO_UNLIKELY(rule.pattern->FullMatch(input)))
- return false;
- break;
- case Policy::kMatchRedactGroups:
- if (PERFETTO_UNLIKELY(
- rule.pattern->FullMatchWithGroups(input, matches_))) {
- RedactMatches(matches_);
- return true;
- }
- break;
- case Policy::kAtraceMatchBreak:
- atrace_payload_ptr = atrace_find_tried
- ? atrace_payload_ptr
- : FindAtracePayloadPtr(ptr, ptr + len);
- atrace_find_tried = true;
- if (atrace_payload_ptr &&
- StartsWith(atrace_payload_ptr, ptr + len,
- rule.atrace_payload_starts_with) &&
- rule.pattern->FullMatch(input)) {
- return false;
- }
- break;
- case Policy::kAtraceMatchRedactGroups:
- atrace_payload_ptr = atrace_find_tried
- ? atrace_payload_ptr
- : FindAtracePayloadPtr(ptr, ptr + len);
- atrace_find_tried = true;
- if (atrace_payload_ptr &&
- StartsWith(atrace_payload_ptr, ptr + len,
- rule.atrace_payload_starts_with) &&
- PERFETTO_UNLIKELY(
- rule.pattern->FullMatchWithGroups(input, matches_))) {
- RedactMatches(matches_);
- return true;
- }
- break;
- case Policy::kAtraceRepeatedSearchRedactGroups:
- atrace_payload_ptr = atrace_find_tried
- ? atrace_payload_ptr
- : FindAtracePayloadPtr(ptr, ptr + len);
- atrace_find_tried = true;
- if (atrace_payload_ptr && StartsWith(atrace_payload_ptr, ptr + len,
- rule.atrace_payload_starts_with)) {
- bool has_any_matches = false;
- for (auto iter = rule.pattern->PartialMatchAll(input);
- iter.NextWithGroups(matches_);) {
- RedactMatches(matches_);
- has_any_matches = true;
- }
- if (has_any_matches) {
- return true;
- }
- }
- break;
- }
- }
- return false;
+constexpr uint32_t ReadPosOf(uint64_t rw_positions) {
+ return static_cast<uint32_t>(rw_positions);
}
-} // namespace protozero
-// gen_amalgamated begin source: src/protozero/filtering/message_filter.cc
-// gen_amalgamated begin header: src/protozero/filtering/message_filter.h
-// gen_amalgamated begin header: src/protozero/filtering/message_tokenizer.h
-/*
- * Copyright (C) 2021 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.
- */
+// Replaces the read half of a previously loaded rw_positions value, leaving
+// write_pos unchanged. The reader publishes read_pos this way.
+constexpr uint64_t ReplaceReadPos(uint64_t rw_positions, uint32_t read_pos) {
+ return PackRwPositions(WritePosOf(rw_positions), read_pos);
+}
-#ifndef SRC_PROTOZERO_FILTERING_MESSAGE_TOKENIZER_H_
-#define SRC_PROTOZERO_FILTERING_MESSAGE_TOKENIZER_H_
+constexpr uint32_t NumOutstandingPositions(uint32_t write_pos,
+ uint32_t read_pos) {
+ return write_pos - read_pos;
+}
-#include <stdint.h>
+// A physical chunk index. Variable names distinguish indices from positions:
+// - *_idx selects a chunk in memory, from 0 to num_chunks - 1.
+// Successive positions cycle through these indices, then return to zero.
+// - *_pos identifies a reservation in logical order.
+// It keeps advancing across traversals, past num_chunks.
+// It rolls over from UINT32_MAX to zero.
+//
+// For a ring buffer with four chunks:
+//
+// chunk_pos: 0 1 2 3 4 5 6 7 8
+// chunk_idx: 0 1 2 3 0 1 2 3 0
+class ChunkIndex {
+ public:
+ // Maps a logical position to its physical chunk in a validated ring buffer.
+ //
+ // num_chunks = 2^k, so the low k bits of a position select the physical chunk
+ // and the remaining bits count completed traversals:
+ //
+ // bits 0..k-1 bits k..31
+ // +----------------------------+----------------------------+
+ // | physical chunk index | traversal number |
+ // +----------------------------+----------------------------+
+ // k bits 32 - k bits
+ //
+ // For example, an eight-chunk ring buffer has three chunk-index bits. The low
+ // three bits select chunks 0 through 7. The remaining 29 bits count completed
+ // traversals.
+ static constexpr ChunkIndex FromPosition(uint32_t chunk_pos,
+ uint32_t num_chunks) {
+ return ChunkIndex{chunk_pos & (num_chunks - 1)};
+ }
-// gen_amalgamated expanded: #include "perfetto/base/compiler.h"
-// gen_amalgamated expanded: #include "perfetto/base/logging.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/proto_utils.h"
+ // Builds from an existing physical chunk index.
+ // Uses |chunk_idx| unchanged, without applying modulo num_chunks.
+ static constexpr ChunkIndex FromIndex(uint32_t chunk_idx) {
+ return ChunkIndex{chunk_idx};
+ }
-namespace protozero {
+ constexpr uint32_t value() const { return chunk_idx_; }
-// A helper class for schema-less tokenizing of protobuf messages.
-// This class takes a stream of proto-encoded bytes, pushed one by one in input
-// via Push(octet), and returns a stream of tokens (each Push() call can return
-// 0 or 1 token).
-// A "token" contains metadata about a field, specifically: its ID, its wire
-// type and:
-// - For varint and fixed32/64 fields: its payload.
-// - For string and bytes fields: the length of its payload.
-// In this case the caller is supposed to "eat" those N bytes before calling
-// Push() again.
-// Note that this class cannot differentiate between a string/bytes field or
-// a submessage, because they are encoded in the same way. The caller is
-// supposed to know whether a field can be recursed into by just keep calling
-// Push() or is a string that should be skipped.
-// This is inline to allow the compiler to see through the Push method and
-// avoid a function call for each byte.
-class MessageTokenizer {
- public:
- struct Token {
- uint32_t field_id; // 0 == not valid.
- proto_utils::ProtoWireType type;
+ private:
+ explicit constexpr ChunkIndex(uint32_t chunk_idx) : chunk_idx_(chunk_idx) {}
- // For kLengthDelimited, |value| represent the length of the payload.
- uint64_t value;
+ uint32_t chunk_idx_;
+};
- inline bool valid() const { return field_id != 0; }
- bool operator==(const Token& o) const {
- return field_id == o.field_id && type == o.type && value == o.value;
- }
- };
+// Chunk state word
+// ----------------
+//
+// Each chunk starts with a 32-bit atomic state word (std::atomic<uint32_t>).
+//
+// There are five states:
+// 1. kFree
+// 2. kBeingWritten
+// 3. kComplete
+// 4. kRewriteRequested
+// 5. kRewriteAcknowledged
+//
+// The low control byte (8 bits) determines how to interpret the upper 24 bits:
+// - Free has 8 unused bits that must be zero, followed by wrap_count (16 bits).
+// - BeingWritten, Complete and RewriteRequested carry num_fragments (8 bits)
+// and WriterID (16 bits).
+// - RewriteAcknowledged has no other fields so its upper bits are all zero.
+//
+// A Free word contains:
+//
+// +------------------+------------------+------------------+
+// | byte 0 | byte 1 | bytes 2-3 |
+// +------------------+------------------+------------------+
+// | control = 0 | num_fragments = 0| wrap_count |
+// | (Free, format 0, | | |
+// | no flags) | | |
+// +------------------+------------------+------------------+
+//
+// On the first traversal, wrap_count is zero and every chunk's Free word is
+// zero. A zero-filled ring buffer therefore starts with all chunks Free and
+// read_pos == write_pos == 0. Later traversals use wrap_count << 16 as the
+// Free word.
+//
+// BeingWritten, Complete and RewriteRequested contain:
+//
+// +------------------+------------------+------------------+
+// | byte 0 | byte 1 | bytes 2-3 |
+// +------------------+------------------+------------------+
+// | control byte | num_fragments | WriterID |
+// +------------------+------------------+------------------+
+//
+// The control byte is:
+//
+// +---------+---------+---------+---------+---------+
+// |bits 0-2 |bits 3-4 | bit 5 | bit 6 | bit 7 |
+// +---------+---------+---------+---------+---------+
+// | state | format | data |continues|continues|
+// | | | loss | on next |from prev|
+// +---------+---------+---------+---------+---------+
+//
+// RewriteAcknowledged carries no other fields so every other bit is zero.
+
+enum class ChunkState : uint32_t {
+ // No writer owns this chunk:
+ // - A writer whose reserved position selects this chunk and has the same
+ // wrap count can change Free to BeingWritten before writing.
+ // - To consume an unclaimed reservation, the reader must first advance the
+ // wrap count atomically. The delayed writer's claim then fails.
+ kFree = 0,
+
+ // One writer owns the chunk:
+ // - The first N = num_fragments fragments are published and can be read.
+ // - The writer may be appending fragment N + 1 after those published bytes.
+ //
+ // The writer publishes by changing BeingWritten to Complete. The reader
+ // can instead copy the first N fragments and request a rewrite, without
+ // waiting for the writer to finish.
+ kBeingWritten = 1,
+
+ // The writer has published all num_fragments fragments and stopped writing.
+ // The reader and writer can now race to change the state:
+ // - The reader consumes the fragments and changes Complete to Free.
+ // - The same writer changes Complete back to BeingWritten to append more.
+ // If the reader wins, the writer drops its cached handle to the chunk.
+ kComplete = 2,
+
+ // A partial chunk read won the race against the writer's publication:
+ // - The reader consumed N = num_fragments and can move on.
+ // - The writer still owns the chunk and may be writing fragment N + 1.
+ //
+ // The writer notices the request when it tries to publish. It must save
+ // any unpublished fragment before acknowledging. The reader cannot free
+ // the chunk until that acknowledgement.
+ kRewriteRequested = 3,
+
+ // The writer notices RewriteRequested when it next tries to publish:
+ // - It saves any unpublished fragment in private memory.
+ // - It changes the old chunk to RewriteAcknowledged and stops touching it.
+ //
+ // Acknowledgement happens before waiting for a replacement chunk.
+ // Only the reader changes RewriteAcknowledged to Free, when it next visits
+ // this chunk on a later traversal.
+ kRewriteAcknowledged = 4,
+
+ // A reader that does not know a state cannot tell who owns the chunk. It
+ // stops rather than reclaiming it.
+ kReserved5 = 5,
+ kReserved6 = 6,
+ kReserved7 = 7,
+};
- // Pushes a byte in input and returns a token, only when getting to the last
- // byte of each field. Specifically:
- // - For varint and fixed32 fields, the Token is returned after the last byte
- // of the numeric payload is pushed.
- // - For length-delimited fields, this returns after the last byte of the
- // length is pushed (i.e. right before the payload starts). The caller is
- // expected to either skip the next |value| bytes (in the case of a string
- // or bytes fields) or keep calling Push, in the case of a submessage.
- inline Token Push(uint8_t octet) {
- using protozero::proto_utils::ProtoWireType;
+enum class ChunkFormat : uint32_t {
+ // Bytes 4..5 contain a little-endian target BufferID. Payload starts at 6.
+ kTargetBuffer = 0,
- // Parsing a fixed32/64 field is the only case where we don't have to do
- // any varint decoding. This is why this block is before the remaining
- // switch statement below (all the rest is a varint).
- if (PERFETTO_UNLIKELY(state_ == kFixedIntValue)) {
- PERFETTO_DCHECK(fixed_int_bits_ == 32 || fixed_int_bits_ == 64);
- fixed_int_value_ |= static_cast<uint64_t>(octet) << fixed_int_shift_;
- fixed_int_shift_ += 8;
- if (fixed_int_shift_ < fixed_int_bits_)
- return Token{}; // Intermediate byte of a fixed32/64.
- auto wire_type = fixed_int_bits_ == 32 ? ProtoWireType::kFixed32
- : ProtoWireType::kFixed64;
- uint64_t fixed_int_value = fixed_int_value_;
- fixed_int_value_ = fixed_int_shift_ = fixed_int_bits_ = 0;
- state_ = kFieldPreamble;
- return Token{field_id_, wire_type, fixed_int_value};
- }
+ // Reserved for a format carrying per-packet routing information.
+ kReservedRouting = 1,
+ kReserved2 = 2,
+ kReserved3 = 3,
+};
- // At this point either we are: (i) parsing a field preamble; (ii) parsing a
- // varint field paylod; (iii) parsing the length of a length-delimited
- // field. In all cases, we need to decode a varint before proceeding.
- varint_ |= static_cast<uint64_t>(octet & 0x7F) << varint_shift_;
- if (octet & 0x80) {
- varint_shift_ += 7;
- if (PERFETTO_UNLIKELY(varint_shift_ >= 64)) {
- varint_shift_ = 0;
- state_ = kInvalidVarInt;
- }
- return Token{}; // Still parsing a varint.
- }
+// Field widths and positions in the 32-bit word. The low byte is the control
+// byte, followed by the fragment count and WriterID.
+constexpr uint32_t kPayloadFlagsBits = 3;
+constexpr uint32_t kChunkFormatBits = 2;
+constexpr uint32_t kChunkStateBits = 3;
+constexpr uint32_t kNumFragmentsBits = 8;
+constexpr uint32_t kWriterIDBits = 16;
+
+constexpr uint32_t kChunkStateShift = 0;
+constexpr uint32_t kChunkFormatShift = kChunkStateShift + kChunkStateBits;
+constexpr uint32_t kPayloadFlagsShift = kChunkFormatShift + kChunkFormatBits;
+constexpr uint32_t kNumFragmentsShift = kPayloadFlagsShift + kPayloadFlagsBits;
+constexpr uint32_t kWriterIDShift = kNumFragmentsShift + kNumFragmentsBits;
+
+constexpr uint32_t kChunkStateMask = (1u << kChunkStateBits) - 1;
+constexpr uint32_t kChunkFormatMask = ((1u << kChunkFormatBits) - 1)
+ << kChunkFormatShift;
+constexpr uint32_t kPayloadFlagsMask = ((1u << kPayloadFlagsBits) - 1)
+ << kPayloadFlagsShift;
+constexpr uint32_t kNumFragmentsMask = ((1u << kNumFragmentsBits) - 1)
+ << kNumFragmentsShift;
+constexpr uint32_t kWriterIDMask = ((1u << kWriterIDBits) - 1)
+ << kWriterIDShift;
+
+constexpr uint32_t kMaxFragmentsPerChunk = (1u << kNumFragmentsBits) - 1;
+
+// Free uses the WriterID field for the wrap count. Its other data bits must be
+// zero.
+constexpr uint32_t kWrapCountShift = kWriterIDShift;
+
+enum PayloadFlags : uint32_t {
+ // The writer lost data before or while filling this chunk.
+ // - The flag does not identify where data was lost within the chunk.
+ // - The reader discards all published fragments and reports loss.
+ // This includes complete, good packets before or after the gap.
+ // - A writer may keep appending. The flag stays set for that reservation.
+ // Fragments appended to this chunk are also discarded once published.
+ // This allows cached reuse after loss without forcing a new reservation.
+ //
+ // TODO(sashwinbalaji): Carry the cause of the loss. TBv2 reports this flag
+ // as DATA_LOSS_READ_GAP. v1 reports a full buffer as DATA_LOSS_SMB_FULL.
+ kFlagDataLoss = 1u << kPayloadFlagsShift,
+
+ // The last fragment is not the end of its packet. The packet continues in
+ // this writer's next chunk. Only Complete may carry this flag, and the
+ // writer must not reuse a chunk carrying it.
+ kFlagContinuesOnNextChunk = 1u << (kPayloadFlagsShift + 1),
+
+ // The first fragment contains the next part of a packet that started in this
+ // writer's previous chunk.
+ kFlagContinuesFromPrevChunk = 1u << (kPayloadFlagsShift + 2),
+};
- uint64_t varint = varint_;
- varint_ = 0;
- varint_shift_ = 0;
+// Chunk ownership and wrap identity
+// ---------------------------------
+//
+// Only the reader writes Free. The writer publishes each closed fragment and
+// may reuse its Complete chunk to append another.
+//
+// The reader can make progress even when a writer is descheduled:
+//
+// 1. The writer pauses before claiming the chunk.
+// - The position is reserved. The chunk has not been claimed.
+// - The reader atomically changes Free(wrap) to Free(next wrap).
+// Only the wrap count changes. The state stays Free.
+// - The reader advances read_pos without delivering fragments.
+// - The chunk is ready for chunk_pos + num_chunks. That position's writer
+// can claim it by changing the state to BeingWritten.
+// - The original writer resumes with the old wrap count. Its claim fails
+// without changing the chunk. It tries a new reservation.
+// - If the writer claims first, the reader's update fails instead.
+// The reader leaves read_pos unchanged and retries the position.
+//
+// 2. The writer pauses after claiming the chunk.
+// - The reader copies the published fragments.
+// - The reader changes BeingWritten to RewriteRequested, then advances
+// read_pos. The writer still owns the chunk.
+// - Later reservations cannot claim this chunk while it awaits
+// acknowledgement. The reader advances past those reservations without
+// changing the chunk's state word or delivering fragments.
+// - The owning writer resumes and saves any unpublished fragment.
+// Only that writer can change RewriteRequested to RewriteAcknowledged.
+// - On a later traversal, the reader changes RewriteAcknowledged to
+// Free(next wrap). It then advances read_pos without delivering fragments.
+// - The chunk is now available for a subsequent reservation.
+//
+// An unclaimed reservation that the reader skips is called a hole. Skipping
+// means advancing read_pos without delivering fragments for that reservation.
+// It can also require a state word update, as in the Free and
+// RewriteAcknowledged cases above.
+//
+// writer claims writer publishes
+// Free(wrap) ------------> BeingWritten(N) -----------> Complete(M)
+// | | |
+// | reader | reader | reader
+// v v v
+// Free(next wrap) RewriteRequested(N) Free(next wrap)
+// |
+// | writer finishes with old chunk
+// v
+// RewriteAcknowledged
+// |
+// | reader, on a later traversal
+// v
+// Free(next wrap)
+//
+// N and M count published fragments. A claim starts at N = 0. Reuse takes
+// Complete(M) back to BeingWritten(M).
+//
+// The writer's publication and the reader's rewrite request compare the entire
+// BeingWritten word, including format, flags, num_fragments and WriterID.
+// Only one CAS can succeed against that word. No second atomic is needed.
+// If scraping wins, the writer relocates only the unpublished fragment after
+// the N published fragments.
+//
+// A reservation allows one claim against Free(wrap_count(chunk_pos)).
+// On failure, the writer must reserve a new position. The returned word can
+// belong to another writer or a position beyond the one the reader consumed.
+// A retry against that word can overwrite another reservation's chunk.
+//
+// Actor From Action To
+// ------ --------------------- ----------------------- -------------------
+// writer Free(wrap) claim BeingWritten(0)
+// writer Free(wrap) gone reserve a new position unchanged
+// reader Free(wrap) consume unclaimed Free(next wrap)
+// reader Free(other wrap) protocol error, stop unchanged
+// writer BeingWritten(N) publish Complete(M)
+// reader BeingWritten(N) read N fragments RewriteRequested(N)
+// writer Complete(N) reuse BeingWritten(N)
+// writer Complete gone drop cached handle unchanged
+// reader Complete consume Free(next wrap)
+// writer RewriteRequested copy fragment, release RewriteAcknowledged
+// reader RewriteRequested advance read_pos unchanged
+// reader RewriteAcknowledged reclaim Free(next wrap)
+// reader reserved state 5..7 unknown owner, stop unchanged
+// reader Free CAS lost retry immediately unchanged
+// reader BeingWritten CAS lost discard copy, retry unchanged
+// reader Complete CAS lost discard copy, retry unchanged
+// reader acknowledgement lost protocol error, stop unchanged
+// writer publication CAS lost handle rewrite or abort unchanged
+// writer any other lost CAS bug, abort unchanged
+//
+// Lost-CAS rows describe a failed attempt. It does not change the shared word.
+// The reader retries within Drain(), subject to its per-position attempt limit.
+// A failed publication must find RewriteRequested(N), or the writer aborts.
+// The reader also stops on reserved bits in Free or RewriteAcknowledged.
+//
+// Free stores the low 16 bits of the traversal number:
+//
+// wrap_count = uint16_t(chunk_pos / num_chunks)
+//
+// For the same chunk, that value repeats after:
+//
+// min(num_chunks * 65536, 2^32) reservations
+//
+// A writer delayed between reservation and claim for that long can match a
+// later Free word. Its data is delivered at that later position, whose writer
+// loses the claim. Chunk ownership holds, but reservation order is lost for
+// the delayed writer. This is the limit of the 16-bit wrap count.
+//
+// Computes the wrap from a position. It does not inspect the chunk's state.
+inline uint16_t WrapCountForPosition(uint32_t chunk_pos, uint32_t num_chunks) {
+ PERFETTO_DCHECK(base::IsPowerOfTwo(num_chunks));
+ return static_cast<uint16_t>(chunk_pos >> base::CountTrailZeros(num_chunks));
+}
- switch (state_) {
- case kFieldPreamble: {
- auto field_type = static_cast<uint32_t>(varint & 7u); // 7 = 0..0111
- field_id_ = static_cast<uint32_t>(varint >> 3);
+constexpr ChunkState ChunkStateOf(uint32_t state_word) {
+ return static_cast<ChunkState>((state_word & kChunkStateMask) >>
+ kChunkStateShift);
+}
- // The field type is legit, now check it's well formed and within
- // boundaries.
- if (field_type == static_cast<uint32_t>(ProtoWireType::kVarInt)) {
- state_ = kVarIntValue;
- } else if (field_type ==
- static_cast<uint32_t>(ProtoWireType::kFixed32) ||
- field_type ==
- static_cast<uint32_t>(ProtoWireType::kFixed64)) {
- state_ = kFixedIntValue;
- fixed_int_shift_ = 0;
- fixed_int_value_ = 0;
- fixed_int_bits_ =
- field_type == static_cast<uint32_t>(ProtoWireType::kFixed32) ? 32
- : 64;
- } else if (field_type ==
- static_cast<uint32_t>(ProtoWireType::kLengthDelimited)) {
- state_ = kLenDelimited;
- } else {
- state_ = kInvalidFieldType;
- }
- return Token{};
- }
+constexpr bool HasDataFields(ChunkState state) {
+ return state == ChunkState::kBeingWritten || state == ChunkState::kComplete ||
+ state == ChunkState::kRewriteRequested;
+}
- case kVarIntValue: {
- // Return the varint field payload and go back to the next field.
- state_ = kFieldPreamble;
- return Token{field_id_, ProtoWireType::kVarInt, varint};
- }
+constexpr uint32_t MakeFreeStateWord(uint16_t wrap_count) {
+ return static_cast<uint32_t>(wrap_count) << kWrapCountShift;
+}
- case kLenDelimited: {
- const auto payload_len = varint;
- if (payload_len > protozero::proto_utils::kMaxMessageLength) {
- state_ = kMessageTooBig;
- return Token{};
- }
- state_ = kFieldPreamble;
- // At this point the caller is expected to consume the next
- // |payload_len| bytes.
- return Token{field_id_, ProtoWireType::kLengthDelimited, payload_len};
- }
+// The Free word a reservation at |chunk_pos| must find, and the word the
+// reader leaves for the next traversal when called with chunk_pos + num_chunks.
+inline uint32_t MakeFreeStateWordForPosition(uint32_t chunk_pos,
+ uint32_t num_chunks) {
+ return MakeFreeStateWord(WrapCountForPosition(chunk_pos, num_chunks));
+}
- case kFixedIntValue:
- // Unreachable because of the if before the switch.
- PERFETTO_DCHECK(false);
- break;
+// These accessors apply to BeingWritten, Complete and RewriteRequested.
+// PayloadFlagsOf() leaves the flags in their encoded bit positions, so its
+// result can be passed to MakeDataStateWord().
+constexpr ChunkFormat ChunkFormatOf(uint32_t state_word) {
+ return static_cast<ChunkFormat>((state_word & kChunkFormatMask) >>
+ kChunkFormatShift);
+}
- // Unrecoverable error states.
- case kInvalidFieldType:
- case kMessageTooBig:
- case kInvalidVarInt:
- break;
- } // switch(state_)
+constexpr uint32_t PayloadFlagsOf(uint32_t state_word) {
+ return state_word & kPayloadFlagsMask;
+}
+
+constexpr uint32_t NumFragmentsOf(uint32_t state_word) {
+ return (state_word & kNumFragmentsMask) >> kNumFragmentsShift;
+}
+
+constexpr WriterID WriterIDOf(uint32_t state_word) {
+ return static_cast<WriterID>((state_word & kWriterIDMask) >> kWriterIDShift);
+}
+
+inline uint32_t MakeDataStateWord(ChunkState state,
+ ChunkFormat format,
+ uint32_t payload_flags,
+ uint32_t num_fragments,
+ WriterID writer_id) {
+ PERFETTO_DCHECK(HasDataFields(state));
+ PERFETTO_DCHECK(static_cast<uint32_t>(format) < (1u << kChunkFormatBits));
+ PERFETTO_DCHECK((payload_flags & ~kPayloadFlagsMask) == 0);
+ PERFETTO_DCHECK(num_fragments <= kMaxFragmentsPerChunk);
+ return (static_cast<uint32_t>(state) << kChunkStateShift) |
+ (static_cast<uint32_t>(format) << kChunkFormatShift) |
+ (payload_flags & kPayloadFlagsMask) |
+ ((num_fragments << kNumFragmentsShift) & kNumFragmentsMask) |
+ (static_cast<uint32_t>(writer_id) << kWriterIDShift);
+}
+
+constexpr uint32_t kRewriteAcknowledgedStateWord =
+ static_cast<uint32_t>(ChunkState::kRewriteAcknowledged) << kChunkStateShift;
+
+// Replaces only the state bits, preserving format, flags, count and WriterID.
+// The reader uses this to request a rewrite without understanding the chunk
+// format. The writer uses it to take a Complete chunk back to BeingWritten
+// while the word keeps describing the fragments it already published.
+constexpr uint32_t ReplaceChunkState(uint32_t state_word, ChunkState state) {
+ return (state_word & ~kChunkStateMask) |
+ (static_cast<uint32_t>(state) << kChunkStateShift);
+}
+
+// Target-buffer chunk format
+// --------------------------
+//
+// A data-bearing format-0 chunk begins with this six-byte header. The remaining
+// chunk_size - 6 bytes hold payload and size entries:
+//
+// +---------+---------+-------------------+-------------------+
+// | byte 0 | byte 1 | bytes 2-3 | bytes 4-5 |
+// +---------+---------+-------------------+-------------------+
+// | control | num | WriterID | target BufferID |
+// | byte |fragments| | |
+// +---------+---------+-------------------+-------------------+
+// \_____________ atomic state word _______/
+//
+// The rest of a format-0 chunk is laid out as follows:
+//
+// low address high address
+// 0 4 6 chunk_size
+// +-----------------+----------+-----------+------+--------------+
+// | atomic state | BufferID | payloads | free | size varints |
+// | word | | grow ---> | | <--- grow |
+// +-----------------+----------+-----------+------+--------------+
+// ... N-1 1 0
+//
+// Fragment 0's size is at the end of the chunk. num_fragments specifies the
+// number of published payload fragments and size varints.
+//
+// Publication and access:
+// - The writer fills each fragment and its size entry before the release
+// transition from BeingWritten to Complete.
+// - The reader acquire-loads the state word. It decodes and validates each size
+// before it copies the payload.
+//
+// BufferID becomes visible with the first fragment publication.
+// If num_fragments is zero, the reader must not load BufferID.
+//
+// If kFlagDataLoss is set, the reader discards the chunk's published fragments
+// without access to their payload.
- return Token{}; // Keep GCC happy.
- }
+constexpr uint32_t kTargetBufferIdOffset = 4;
+constexpr uint32_t kTargetBufferPayloadOffset = 6;
- // Returns true if the tokenizer FSM has reached quiescence (i.e. if we are
- // NOT in the middle of parsing a field).
- bool idle() const {
- return state_ == kFieldPreamble && varint_shift_ == 0 &&
- fixed_int_shift_ == 0;
- }
+inline void StoreTargetBufferId(uint8_t* chunk, BufferID buffer_id) {
+ memcpy(&chunk[kTargetBufferIdOffset], &buffer_id, sizeof(buffer_id));
+}
- // Only for reporting parser errors in the trace.
- uint32_t state() const { return static_cast<uint32_t>(state_); }
+inline BufferID LoadTargetBufferId(const uint8_t* chunk) {
+ BufferID buffer_id;
+ memcpy(&buffer_id, &chunk[kTargetBufferIdOffset], sizeof(buffer_id));
+ return buffer_id;
+}
- private:
- enum State {
- kFieldPreamble = 0, // Parsing the varint for the field preamble.
- kVarIntValue = 1, // Parsing the payload of a varint field.
- kFixedIntValue = 2, // Parsing the payload of a fixed32/64 field.
- kLenDelimited = 3, // Parsing the length of a length-delimited field.
+// Fragment size directory
+// -----------------------
+//
+// The fragment sizes are reversed varints at the end of the chunk.
+// - Fragment 0's size ends at chunk_size.
+// - Each later size is prepended at a lower address.
+//
+// low address high address
+// +----------+----------+----------+----------+----------+
+// | size N-1 | ... | size 2 | size 1 | size 0 |
+// +----------+----------+----------+----------+----------+
+//
+// Within each size entry:
+// - Each byte carries seven value bits and a continuation bit (0x80).
+// - The least significant group is at the highest address.
+// - The reader moves towards lower addresses until the continuation bit is
+// clear. It does not read the next, unpublished entry.
+
+// Fragment sizes share Protozero's message-length limit: four varint bytes.
+constexpr uint32_t kMaxFragmentSizeVarIntBytes = 4;
+
+// Returns the largest supported n with n + varint_size(n) <= available_bytes.
+// Returns zero if no payload byte fits.
+// |available_bytes| includes both the payload and its size entry. Each size
+// byte carries seven bits, so the limits below include the corresponding
+// number of size bytes.
+inline uint32_t MaxFragmentSizeForAvailableBytes(uint32_t available_bytes) {
+ if (available_bytes <= 1)
+ return 0;
- // Unrecoverable error states:
- kInvalidFieldType = 4, // Encountered an invalid field type.
- kMessageTooBig = 5, // Size of the length delimited message was too big.
- kInvalidVarInt = 6, // Varint larger than 64 bits.
- };
+ // One size byte: (2^7 - 1) + 1 = 2^7 total. Subtract one size byte.
+ if (available_bytes <= (1u << 7))
+ return available_bytes - 1;
+ // Two size bytes: (2^14 - 1) + 2 = 2^14 + 1 total. Subtract two.
+ if (available_bytes <= (1u << 14) + 1)
+ return available_bytes - 2;
+ // Three size bytes: (2^21 - 1) + 3 = 2^21 + 2 total. Subtract three.
+ if (available_bytes <= (1u << 21) + 2)
+ return available_bytes - 3;
+ return std::min(
+ available_bytes - 4,
+ static_cast<uint32_t>(protozero::proto_utils::kMaxMessageLength));
+}
+
+inline uint32_t MaxFragmentSizeForEmptyChunk(uint32_t chunk_size) {
+ // Callers use a validated ring buffer, so a size below 256 is a caller error.
+ PERFETTO_CHECK(chunk_size >= kMinChunkSize);
+ const uint32_t available_bytes = chunk_size - kTargetBufferPayloadOffset;
+ return MaxFragmentSizeForAvailableBytes(available_bytes);
+}
+
+// Writes the size into the directory immediately before |sizes_begin| and
+// returns the new directory start.
+// Requires varint_size(size) writable bytes before |sizes_begin|.
+// |size| must be at most protozero::proto_utils::kMaxMessageLength.
+inline uint8_t* WriteFragmentSizeReversed(uint8_t* sizes_begin, uint32_t size) {
+ PERFETTO_DCHECK(size <= protozero::proto_utils::kMaxMessageLength);
+ // TODO(sashwinbalaji): Add proto_utils::WriteVarIntReversed to write directly
+ // into the directory. This would avoid the temporary buffer and copy below.
+ uint8_t encoded[kMaxFragmentSizeVarIntBytes];
+ const uint8_t* const encoded_end =
+ protozero::proto_utils::WriteVarInt(size, encoded);
+ const size_t encoded_size = static_cast<size_t>(encoded_end - encoded);
+ // Put the first varint byte at the highest address: the reader starts
+ // there and reads towards lower addresses (see ReadFragmentSizeReversed()).
+ for (size_t i = 0; i < encoded_size; ++i) {
+ --sizes_begin;
+ *sizes_begin = encoded[i];
+ }
+ return sizes_begin;
+}
+
+// Decodes one reversed size varint, starting just below |*sizes_cursor|.
+//
+// For example, 300 is stored as 02 AC from low to high address.
+// The reader visits AC first, then 02:
+//
+// ... | 02 | AC | <- chunk_size
+// ^ ^
+// | first byte read: AC, continuation bit set
+// second byte read: 02, no continuation bit, stop
+//
+// The reader validates the chunk in two steps:
+// 1. Decode the sizes with |lower_bound| set to the payload start.
+// This keeps reads out of the header. The payload end is not yet known.
+// 2. Add up the decoded sizes. The payload must end at or before the directory
+// start. Reject the chunk on overlap, without copying payload.
+//
+// Rejects truncated entries and entries needing more than four bytes.
+// Four bytes limit the decoded size to Protozero's kMaxMessageLength.
+//
+// - Success returns the size, which may be zero. |*sizes_cursor| moves to the
+// last byte read, just above the next entry.
+// - Failure returns std::nullopt and leaves |*sizes_cursor| unchanged.
+inline std::optional<uint32_t> ReadFragmentSizeReversed(
+ const uint8_t* lower_bound,
+ const uint8_t** sizes_cursor) {
+ PERFETTO_DCHECK(lower_bound <= *sizes_cursor);
+ const uint8_t* cursor = *sizes_cursor;
+ uint32_t value = 0;
+ uint32_t num_bytes = 0;
+ // TODO(sashwinbalaji): Benchmark alternatives:
+ // - Increment a running shift by seven instead of multiplying each time.
+ // - Find the terminator first, then decode forwards with shift-and-or.
+ for (;;) {
+ if (cursor == lower_bound || num_bytes == kMaxFragmentSizeVarIntBytes)
+ return std::nullopt;
+ --cursor;
+ const uint8_t cur = *cursor;
+ // Reading down the directory yields the least significant group first.
+ const uint32_t data_bits = cur & 0x7f;
+ const uint32_t shift = 7 * num_bytes;
+ value |= data_bits << shift;
+ ++num_bytes;
+ if ((cur & 0x80) == 0)
+ break;
+ }
- State state_ = kFieldPreamble;
- uint32_t field_id_ = 0;
- uint64_t varint_ = 0;
- uint32_t varint_shift_ = 0;
- uint32_t fixed_int_shift_ = 0;
- uint32_t fixed_int_bits_ = 0;
- uint64_t fixed_int_value_ = 0;
-};
+ *sizes_cursor = cursor;
+ return value;
+}
-} // namespace protozero
+} // namespace perfetto::tracing_v2
-#endif // SRC_PROTOZERO_FILTERING_MESSAGE_TOKENIZER_H_
+#endif // SRC_TRACING_V2_SHARED_RING_BUFFER_ABI_H_
/*
- * Copyright (C) 2021 The Android Open Source Project
+ * Copyright (C) 2026 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.
@@ -58761,249 +64434,294 @@ class MessageTokenizer {
* limitations under the License.
*/
-#ifndef SRC_PROTOZERO_FILTERING_MESSAGE_FILTER_H_
-#define SRC_PROTOZERO_FILTERING_MESSAGE_FILTER_H_
+#ifndef SRC_TRACING_V2_SHARED_RING_BUFFER_H_
+#define SRC_TRACING_V2_SHARED_RING_BUFFER_H_
+#include <stddef.h>
#include <stdint.h>
-#include <memory>
-#include <string>
-#include <unordered_map>
+#include <atomic>
-// gen_amalgamated expanded: #include "src/protozero/filtering/filter_bytecode_parser.h"
-// gen_amalgamated expanded: #include "src/protozero/filtering/message_tokenizer.h"
-// gen_amalgamated expanded: #include "src/protozero/filtering/string_filter.h"
+// gen_amalgamated expanded: #include "perfetto/base/logging.h"
+// gen_amalgamated expanded: #include "perfetto/ext/base/futex.h"
+// gen_amalgamated expanded: #include "src/tracing/v2/shared_ring_buffer_abi.h"
-namespace protozero {
+namespace perfetto::tracing_v2 {
-// A class to filter binary-encoded proto messages using an allow-list of field
-// ids, also known as "filter bytecode". The filter determines which fields are
-// allowed to be passed through in output and strips all the other fields.
-// See go/trace-filtering for full design.
-// This class takes in input:
-// 1) The filter bytecode, loaded once via the LoadFilterBytecode() method.
-// 2) A proto-encoded binary message. The message doesn't have to be contiguous,
-// it can be passed as an array of arbitrarily chunked fragments.
-// The FilterMessage*() method returns in output a proto message, stripping out
-// all unknown fields. If the input is malformed (e.g., unknown proto field wire
-// types, lengths out of bound) the whole filtering failed and the |error| flag
-// of the FilteredMessage object is set to true.
-// The filtering operation is based on rewriting a copy of the message into a
-// self-allocated buffer, which is then returned in the output. The input buffer
-// is NOT altered.
-// Note also that the process of rewriting the protos gets rid of most redundant
-// varint encoding (if present). So even if all fields are allow-listed, the
-// output might NOT be bitwise identical to the input (but it will be
-// semantically equivalent).
-// Furthermore the enable_field_usage_tracking() method allows to keep track of
-// a histogram of allowed / denied fields. It slows down filtering and is
-// intended only on host tools.
-class MessageFilter {
- public:
- class Config {
- public:
- // Loads filter bytecode. If a filter is already loaded, it is replaced.
- // Optionally accepts an overlay (pass nullptr/0 if not needed).
- // See FilterBytecodeParser::Load() for overlay format details.
- bool LoadFilterBytecode(const void* filter_data,
- size_t len,
- const void* overlay_data = nullptr,
- size_t overlay_len = 0);
+namespace test {
+class SharedRingBufferInternalsForTest;
+}
- bool SetFilterRoot(std::initializer_list<uint32_t> field_ids);
+// Provides the atomic operations on a shared ring buffer.
+//
+// Like SharedMemoryABI in v1, this class interprets memory from its owner.
+// The owner must keep the region mapped until this view, its reader and its
+// writers are destroyed.
+//
+// The ring buffer is lock-free, with multiple writers and a single reader:
+// - Writers reserve positions concurrently. When the ring buffer is full,
+// each writer applies its BufferExhaustedPolicy and records any data it
+// drops.
+// - The reader consumes positions in order and is the only actor that makes a
+// chunk Free again.
+// - All updates to rw_positions and the chunk state words go through this
+// class.
+//
+// Chunk transitions use compare-and-exchange (CAS):
+// - Each CAS compares the entire state word, including all fields.
+// - For BeingWritten, Complete and RewriteRequested, those fields are format,
+// flags, num_fragments and WriterID. Free contains the wrap count instead.
+// - In transition comments, N and M are published fragment counts.
+//
+// TODO(sashwinbalaji): CAS operations currently use the default seq_cst order.
+// Their implementation comments propose weaker orders for a later optimization
+// pass. Audit the synchronization guarantees and measure the benefit before
+// replacing seq_cst.
+class SharedRingBuffer {
+ public:
+ // Attaches to a ring buffer at |start|. Its layout is:
+ //
+ // size = sizeof(RingBufferHeader) + num_chunks * chunk_size
+ //
+ // - sizeof(RingBufferHeader) is 64 bytes. |start| must be 64-byte aligned.
+ // - num_chunks must be a power of two, from 2 to 2^30.
+ // - |chunk_size| must be in [256 B, 64 KiB] and a multiple of four.
+ // It does not need to be a power of two.
+ // - |size| must match the equation exactly, with no trailing bytes.
+ // It does not need to be a power of two.
+ //
+ // A newly created ring buffer must be zero-filled.
+ SharedRingBuffer(uint8_t* start, size_t size, uint32_t chunk_size);
+ ~SharedRingBuffer() = default;
- const FilterBytecodeParser& filter() const { return filter_; }
- const StringFilter& string_filter() const { return string_filter_; }
- StringFilter& string_filter() { return string_filter_; }
- uint32_t root_msg_index() const { return root_msg_index_; }
+ SharedRingBuffer(const SharedRingBuffer&) = delete;
+ SharedRingBuffer& operator=(const SharedRingBuffer&) = delete;
+ SharedRingBuffer(SharedRingBuffer&&) = delete;
+ SharedRingBuffer& operator=(SharedRingBuffer&&) = delete;
- private:
- FilterBytecodeParser filter_;
- StringFilter string_filter_;
- uint32_t root_msg_index_ = 0;
- };
+ // Immutable for the life of the ring buffer.
+ uint32_t num_chunks() const { return num_chunks_; }
+ uint32_t chunk_size() const { return chunk_size_; }
- MessageFilter();
- explicit MessageFilter(Config);
- ~MessageFilter();
+ uint8_t* chunk_at(ChunkIndex chunk_idx) {
+ PERFETTO_DCHECK(chunk_idx.value() < num_chunks_);
+ return start_ + sizeof(RingBufferHeader) +
+ static_cast<size_t>(chunk_idx.value()) * chunk_size_;
+ }
+ const uint8_t* chunk_at(ChunkIndex chunk_idx) const {
+ PERFETTO_DCHECK(chunk_idx.value() < num_chunks_);
+ return start_ + sizeof(RingBufferHeader) +
+ static_cast<size_t>(chunk_idx.value()) * chunk_size_;
+ }
- struct InputSlice {
- const void* data;
- size_t len;
+ // Writer-side reservation.
+ //
+ // A writer reserves a position and acquires its physical chunk in separate
+ // operations:
+ // 1. TryReserveWritePos() advances write_pos.
+ // 2. TryAcquireChunkForWriting() changes Free(wrap_count(chunk_pos)) to
+ // BeingWritten.
+ //
+ // If the reader reaches the reservation before step 2, it must atomically
+ // advance the chunk's wrap count before it advances read_pos.
+ // The delayed writer's claim then fails because its expected wrap count no
+ // longer matches. This prevents publication at a consumed position.
+
+ enum class ReserveResult {
+ kReserved,
+ // num_chunks positions are already outstanding. Nothing was reserved,
+ // so a stalling policy may wait and try again.
+ kFull,
};
- struct FilteredMessage {
- FilteredMessage(std::unique_ptr<uint8_t[]> d, size_t s)
- : data(std::move(d)), size(s) {}
- std::unique_ptr<uint8_t[]> data;
- size_t size; // The used bytes in |data|. This is <= sizeof(data).
- bool error = false;
+ struct Reservation {
+ ReserveResult result = ReserveResult::kFull;
+ // Valid only for kReserved. This is a position in the reservation order,
+ // not a physical chunk index.
+ uint32_t chunk_pos = 0;
+ // The read_pos sampled by the last reservation attempt. If the writer has
+ // to wait, the futex sleeps only while read_pos still has this value.
+ uint32_t read_pos_for_wait = 0;
};
- // Loads the filter bytecode that will be used to filter any subsequent
- // message. Must be called before the first call to FilterMessage*().
- // |filter_data| must point to a byte buffer for a proto-encoded ProtoFilter
- // message (see proto_filter.proto).
- // Optionally accepts an overlay (pass nullptr/0 if not needed).
- bool LoadFilterBytecode(const void* filter_data,
- size_t len,
- const void* overlay_data = nullptr,
- size_t overlay_len = 0) {
- return config_.LoadFilterBytecode(filter_data, len, overlay_data,
- overlay_len);
- }
-
- // This affects the filter starting point of the subsequent FilterMessage*()
- // calls. By default the filtering process starts from the message @ index 0,
- // the root message passed to proto_filter when generating the bytecode
- // (in typical tracing use-cases, this is perfetto.protos.Trace). However, the
- // caller (TracingServiceImpl) might want to filter packets from the 2nd level
- // (perfetto.protos.TracePacket) because the root level is prepended after
- // the fact. This call allows to change the root message for the filter.
- // The argument |field_ids| is an array of proto field ids and determines the
- // path to the new root. For instance, in the case of [1,2,3] SetFilterRoot
- // will identify the sub-message for the field "root.1.2.3" and use that.
- // In order for this to succeed all the fields in the path must be allowed
- // in the filter and must be a nested message type.
- bool SetFilterRoot(std::initializer_list<uint32_t> field_ids) {
- return config_.SetFilterRoot(field_ids);
- }
-
- // Takes an input message, fragmented in arbitrary slices, and returns a
- // filtered message in output.
- FilteredMessage FilterMessageFragments(const InputSlice*, size_t num_slices);
-
- // Helper for tests, where the input is a contiguous buffer.
- FilteredMessage FilterMessage(const void* data, size_t len) {
- InputSlice slice{data, len};
- return FilterMessageFragments(&slice, 1);
- }
+ // Reserves the next position if the ring buffer has room.
+ // If another writer or the reader updates rw_positions first, it rechecks
+ // capacity with the updated positions before another reservation attempt.
+ Reservation TryReserveWritePos();
- // When enabled returns a map of "field path" to "usage counter".
- // The key (std::string) is a binary buffer (i.e. NOT an ASCII/UTF-8 string)
- // which contains a varint for each field. Consider the following:
- // message Root { Sub1 f1 = 1; };
- // message Sub1 { Sub2 f2 = 7;}
- // message Sub2 { string f3 = 5; }
- // The field .f1.f2.f3 will be encoded as \x01\0x07\x05.
- // The value is the number of times that field has been encountered. If the
- // field is not allow-listed in the bytecode (the field is stripped in output)
- // the count will be negative.
- void enable_field_usage_tracking(bool x) { track_field_usage_ = x; }
- const std::unordered_map<std::string, int32_t>& field_usage() const {
- return field_usage_;
- }
+ // Writer-side chunk transitions.
- const Config& config() const { return config_; }
- Config& config() { return config_; }
+ // Free(wrap_count(chunk_pos)) -> BeingWritten(0).
+ // |being_written_word| supplies this writer's WriterID, format and initial
+ // flags. Its fragment count must be zero because the chunk has no published
+ // payload for this reservation.
+ //
+ // On failure, reserve a later position. The reader can consume this position
+ // before the claim, or a writer from an earlier reservation can still own
+ // the chunk. A retry against the returned word can overwrite that writer's
+ // chunk or claim a position the reader already consumed.
+ bool TryAcquireChunkForWriting(uint32_t chunk_pos,
+ uint32_t being_written_word);
+
+ // BeingWritten(N) -> Complete(M). |*expected| is the last BeingWritten word.
+ //
+ // On failure, |*expected| receives the reader's RewriteRequested(N) word,
+ // which must preserve the format, flags, fragment count and WriterID.
+ // Only the reader's rewrite request can change the word while this writer
+ // owns the chunk. The caller must relocate any unpublished fragment.
+ bool TryReleaseChunkAsComplete(ChunkIndex chunk_idx,
+ uint32_t complete_word,
+ uint32_t* expected);
+
+ // Complete(N) -> BeingWritten(N), so the writer can append fragments to its
+ // cached chunk. |observed| is the Complete word this writer published.
+ //
+ // On failure, the reader reclaimed the chunk first. The writer must discard
+ // its cached handle and acquire another chunk.
+ bool TryReacquireChunkForWriting(ChunkIndex chunk_idx, uint32_t observed);
- // Returns the helper class used to perform string filtering.
- StringFilter& string_filter() { return config_.string_filter(); }
+ // RewriteRequested -> RewriteAcknowledged after the writer saves any
+ // unpublished fragment and stops access to the old chunk.
+ //
+ // On failure, report a protocol error. Only this writer can change
+ // RewriteRequested, so |observed| must still match the shared word.
+ bool TryAcknowledgeRewrite(ChunkIndex chunk_idx, uint32_t observed);
+
+ // Reader side.
+
+ // Returns the current chunk state word with acquire ordering. For a data
+ // state, the reader can access the published fragments and their sizes.
+ // BufferID is visible only when the published fragment count is nonzero.
+ uint32_t LoadChunkStateWordAcquire(ChunkIndex chunk_idx) const;
+
+ // Returns the next logical position a writer can reserve.
+ // - This bounds the reservations the reader can consume.
+ // - It does not say which chunks have published fragments.
+ // The reader checks each chunk's state word for that.
+ // - An older position can shorten a drain pass. A later pass can consume
+ // the remaining reservations.
+ uint32_t LoadWritePosRelaxed() const;
+
+ // Returns write_pos - read_pos from one relaxed load of both positions.
+ // - Includes chunks that writers have not published yet.
+ // - Includes positions reserved but left unclaimed when a chunk claim failed.
+ // They still count until the reader advances past them.
+ //
+ // Concurrent updates can make this snapshot out of date, but that only
+ // affects when a drain is requested. Space reservation and chunk access use
+ // separate checks.
+ uint32_t LoadNumOutstandingPositionsRelaxed() const;
- private:
- // This is called by FilterMessageFragments().
- // Inlining allows the compiler turn the per-byte call/return into a for loop,
- // while, at the same time, keeping the code easy to read and reason about.
- // It gives a 20-25% speedup (265ms vs 215ms for a 25MB trace).
- void FilterOneByte(uint8_t octet) PERFETTO_ALWAYS_INLINE;
+ // BeingWritten(N) -> RewriteRequested(N), with all other fields unchanged.
+ // |*expected| must be the word the reader used to copy the fragments.
+ //
+ // On failure, the writer published first and |*expected| receives the current
+ // word. The reader must discard its copy and retry this position in Drain().
+ bool TryRequestRewrite(ChunkIndex chunk_idx, uint32_t* expected);
- // No-inline because this is a slowpath (only when usage tracking is enabled).
- void IncrementCurrentFieldUsage(uint32_t field_id,
- bool allowed) PERFETTO_NO_INLINE;
+ // The following transitions are the only ones that expose a chunk to the
+ // next pass around the ring buffer. The new wrap count comes from
+ // |chunk_pos|, not from the old state word.
- // Gets into an error state which swallows all the input and emits no output.
- void SetUnrecoverableErrorState();
+ // Free(wrap_count(chunk_pos)) -> Free(next_wrap(chunk_pos)).
+ // Consumes an unclaimed position and prepares the chunk for
+ // chunk_pos + num_chunks. |*expected| must be this position's Free word.
+ //
+ // On failure, the delayed writer claimed the chunk first and |*expected|
+ // receives the current word. The reader must retry this position in Drain().
+ bool TryMoveFreeChunkToNextWrap(uint32_t chunk_pos, uint32_t* expected);
- // We keep track of the nest of messages in a stack. Each StackState
- // object corresponds to a level of nesting in the proto message structure.
- // Every time a new field of type len-delimited that has a corresponding
- // sub-message in the bytecode is encountered, a new StackState is pushed in
- // |stack_|. stack_[0] is a sentinel to prevent over-popping without adding
- // extra branches in the fastpath.
- // |stack_|. stack_[1] is the state of the root message.
- struct StackState {
- uint32_t in_bytes = 0; // Number of input bytes processed.
+ // Complete(N) -> Free(next_wrap(chunk_pos)).
+ // |*expected| must be the word the reader used to copy the fragments.
+ //
+ // On failure, the writer reused the chunk first and |*expected| receives the
+ // current word. The reader must discard its copy and retry this position in
+ // Drain(). If the chunk is now BeingWritten, that retry requests a rewrite.
+ bool TryReleaseCompleteChunkAsFree(uint32_t chunk_pos, uint32_t* expected);
- // When |in_bytes| reaches this value, the current state should be popped.
- // This is set when recursing into nested submessages. This is 0 only for
- // stack_[0] (we don't know the size of the root message upfront).
- uint32_t in_bytes_limit = 0;
+ // RewriteAcknowledged -> Free(next_wrap(chunk_pos)).
+ //
+ // On failure, |*observed| receives the unexpected word. This is a protocol
+ // error because only this reader can change an acknowledged chunk.
+ bool TryReleaseRewriteAcknowledgedChunkAsFree(uint32_t chunk_pos,
+ uint32_t* observed);
- // This is set when a len-delimited message is encountered, either a string
- // or a nested submessage that is NOT allow-listed in the bytecode.
- // This causes input bytes to be consumed without being parsed from the
- // input stream. If |passthrough_eaten_bytes| == true, they will be copied
- // as-is in output (e.g. in the case of an allowed string/bytes field).
- uint32_t eat_next_bytes = 0;
+ // Backpressure: the writer's path when the ring buffer is full.
+ //
+ // Writers wait on read_pos. The reader publishes a new value and wakes them.
+ // The waiter count only avoids an unnecessary wake syscall. Capacity is
+ // always decided from rw_positions.
+
+ enum class WriterWaitResult {
+ // The writer must recheck capacity after a wake, timeout, interruption or
+ // spurious return. The writer's deadline determines when it stops retries.
+ kRetry,
+ // This build or kernel cannot provide the wait. Do not retry the syscall.
+ // The writer can sleep and retry acquisition instead.
+ kUnavailable,
+ };
- // Keeps tracks of the stream_writer output counter (out_.written()) then
- // the StackState is pushed. This is used to work out, when popping, how
- // many bytes have been written for the current submessage.
- uint32_t out_bytes_written_at_start = 0;
+ // Whether WaitForReadPosChange() is implemented on this platform.
+ static constexpr bool SupportsWriterWait() { return PERFETTO_HAS_FUTEX(); }
- uint32_t field_id = 0; // The proto field id for the current message.
- uint32_t msg_index = 0; // The index of the message filter in the bytecode.
+ // Blocks until read_pos differs from |read_pos_for_wait| or |timeout_ms|
+ // elapses. |read_pos_for_wait| comes from the last Reservation, whether it
+ // reported kFull or a position whose claim failed.
+ WriterWaitResult WaitForReadPosChange(uint32_t read_pos_for_wait,
+ uint32_t timeout_ms);
- // This is a pointer to the proto preamble for the current submessage
- // (it's nullptr for stack_[0] and non-null elsewhere). This will be filled
- // with the actual size of the message (out_.written() -
- // |out_bytes_written_at_start|) when finishing (popping) the message.
- // This must be filled using WriteRedundantVarint(). Note that the
- // |size_field_len| is variable and depends on the actual length of the
- // input message. If the output message has roughly the same size of the
- // input message, the length will not be redundant.
- // In other words: the length of the field is reserved when the submessage
- // starts. At that point we know the upper-bound for the output message
- // (a filtered submessage can be <= the original one, but not >). So we
- // reserve as many bytes it takes to write the input length in varint.
- // Then, when the message is finalized and we know the actual output size
- // we backfill the field.
- // Consider the example of a submessage where the input size = 130 (>127,
- // 2 varint bytes) and the output is 120 bytes. The length will be 2 bytes
- // wide even though could have been encoded with just one byte.
- uint8_t* size_field = nullptr;
- uint32_t size_field_len = 0;
+ // Publishes read_pos without overwriting a concurrent write_pos update, then
+ // wakes waiting writers. Called once per drain pass, so the shared read_pos
+ // can lag the reader's local value. The lag only under-reports free capacity.
+ void PublishReadPos(uint32_t read_pos);
- // The pointer to the start of the string to update the string if it is
- // filtered.
- uint8_t* filter_string_ptr = nullptr;
+ private:
+ friend class test::SharedRingBufferInternalsForTest;
- // The semantic type of the string field being filtered (0 = unspecified).
- uint32_t filter_string_semantic_type = 0;
+ // The production entry points load the initial expected value themselves.
+ // Tests supply an older value to exercise the CAS retry path
+ // deterministically.
+ Reservation TryReserveWritePosFromSnapshot(uint64_t rw_positions);
+ void PublishReadPosFromSnapshot(uint64_t rw_positions, uint32_t read_pos);
- // How |eat_next_bytes| should be handled. It seems that keeping this field
- // at the end rather than next to |eat_next_bytes| makes the filter a little
- // (but measurably) faster. (likely something related with struct layout vs
- // cache sizes).
- enum FilterAction {
- kDrop,
- kPassthrough,
- kFilterString,
- };
- FilterAction action = FilterAction::kDrop;
- };
+ // Shared-memory address and wrap-count helpers.
- uint32_t out_written() { return static_cast<uint32_t>(out_ - &out_buf_[0]); }
+ std::atomic<uint32_t>* chunk_state_word_at(ChunkIndex chunk_idx) {
+ return reinterpret_cast<std::atomic<uint32_t>*>(chunk_at(chunk_idx));
+ }
+ const std::atomic<uint32_t>* chunk_state_word_at(ChunkIndex chunk_idx) const {
+ return reinterpret_cast<const std::atomic<uint32_t>*>(chunk_at(chunk_idx));
+ }
- Config config_;
+ std::atomic<uint32_t>* chunk_state_word_for_position(uint32_t chunk_pos) {
+ return chunk_state_word_at(
+ ChunkIndex::FromPosition(chunk_pos, num_chunks_));
+ }
- std::unique_ptr<uint8_t[]> out_buf_;
- uint8_t* out_ = nullptr;
- uint8_t* out_end_ = nullptr;
+ // Returns the Free word for the next position that uses the same chunk.
+ uint32_t MakeFreeWordForNextWrap(uint32_t chunk_pos) const {
+ // Deriving the value from the next position also handles uint32_t rollover.
+ const uint32_t next_pos = chunk_pos + num_chunks_;
+ return MakeFreeStateWordForPosition(next_pos, num_chunks_);
+ }
- MessageTokenizer tokenizer_;
- std::vector<StackState> stack_;
+ RingBufferHeader* header() {
+ return reinterpret_cast<RingBufferHeader*>(start_);
+ }
+ const RingBufferHeader* header() const {
+ return reinterpret_cast<const RingBufferHeader*>(start_);
+ }
- bool error_ = false;
- bool track_field_usage_ = false;
- std::unordered_map<std::string, int32_t> field_usage_;
+ uint8_t* const start_;
+ const uint32_t num_chunks_;
+ const uint32_t chunk_size_;
};
-} // namespace protozero
+} // namespace perfetto::tracing_v2
-#endif // SRC_PROTOZERO_FILTERING_MESSAGE_FILTER_H_
+#endif // SRC_TRACING_V2_SHARED_RING_BUFFER_H_
/*
- * Copyright (C) 2021 The Android Open Source Project
+ * Copyright (C) 2026 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.
@@ -59018,325 +64736,353 @@ class MessageFilter {
* limitations under the License.
*/
-// gen_amalgamated expanded: #include "src/protozero/filtering/message_filter.h"
-
-// gen_amalgamated expanded: #include "perfetto/base/logging.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/proto_utils.h"
-// gen_amalgamated expanded: #include "src/protozero/filtering/string_filter.h"
-
-namespace protozero {
-
-namespace {
-
-// Inline helpers to append proto fields in output. They are the equivalent of
-// the protozero::Message::AppendXXX() fields but don't require building and
-// maintaining a full protozero::Message object or dealing with scattered
-// output slices.
-// All these functions assume there is enough space in the output buffer, which
-// should be always the case assuming that we don't end up generating more
-// output than input.
-
-inline void AppendVarInt(uint32_t field_id, uint64_t value, uint8_t** out) {
- *out = proto_utils::WriteVarInt(proto_utils::MakeTagVarInt(field_id), *out);
- *out = proto_utils::WriteVarInt(value, *out);
-}
-
-// For fixed32 / fixed64.
-template <typename INT_T /* uint32_t | uint64_t*/>
-inline void AppendFixed(uint32_t field_id, INT_T value, uint8_t** out) {
- *out = proto_utils::WriteVarInt(proto_utils::MakeTagFixed<INT_T>(field_id),
- *out);
- memcpy(*out, &value, sizeof(value));
- *out += sizeof(value);
-}
-
-// For length-delimited (string, bytes) fields. Note: this function appends only
-// the proto preamble and the varint field that states the length of the payload
-// not the payload itself.
-// In the case of submessages, the caller needs to re-write the length at the
-// end in the in the returned memory area.
-// The problem here is that, because of filtering, the length of a submessage
-// might be < original length (the original length is still an upper-bound).
-// Returns a pair with: (1) the pointer where the final length should be written
-// into, (2) the length of the size field.
-// The caller must write a redundant varint to match the original size (i.e.
-// needs to use WriteRedundantVarInt()).
-inline std::pair<uint8_t*, uint32_t> AppendLenDelim(uint32_t field_id,
- uint32_t len,
- uint8_t** out) {
- *out = proto_utils::WriteVarInt(proto_utils::MakeTagLengthDelimited(field_id),
- *out);
- uint8_t* size_field_start = *out;
- *out = proto_utils::WriteVarInt(len, *out);
- const size_t size_field_len = static_cast<size_t>(*out - size_field_start);
- return std::make_pair(size_field_start, size_field_len);
-}
-} // namespace
-
-MessageFilter::MessageFilter(Config config) : config_(std::move(config)) {
- // Push a state on the stack for the implicit root message.
- stack_.emplace_back();
-}
+#ifndef SRC_TRACING_V2_PRODUCER_RING_BUFFER_ARBITER_H_
+#define SRC_TRACING_V2_PRODUCER_RING_BUFFER_ARBITER_H_
-MessageFilter::MessageFilter() : MessageFilter(Config()) {}
+#include <stddef.h>
+#include <stdint.h>
-MessageFilter::~MessageFilter() = default;
+#include <atomic>
+#include <functional>
+#include <memory>
-bool MessageFilter::Config::LoadFilterBytecode(const void* filter_data,
- size_t len,
- const void* overlay_data,
- size_t overlay_len) {
- return filter_.Load(filter_data, len, overlay_data, overlay_len);
-}
+// gen_amalgamated expanded: #include "perfetto/ext/base/status_or.h"
+// gen_amalgamated expanded: #include "perfetto/ext/base/thread_checker.h"
+// gen_amalgamated expanded: #include "perfetto/ext/base/weak_ptr.h"
+// gen_amalgamated expanded: #include "perfetto/ext/tracing/core/basic_types.h"
+// gen_amalgamated expanded: #include "perfetto/tracing/buffer_exhausted_policy.h"
+// gen_amalgamated expanded: #include "perfetto/tracing/core/forward_decls.h"
+// gen_amalgamated expanded: #include "src/tracing/v2/shared_ring_buffer.h"
-bool MessageFilter::Config::SetFilterRoot(
- std::initializer_list<uint32_t> field_ids) {
- uint32_t root_msg_idx = 0;
- for (uint32_t field_id : field_ids) {
- auto res = filter_.Query(root_msg_idx, field_id);
- if (!res.allowed || !res.nested_msg_field())
- return false;
- root_msg_idx = res.nested_msg_index;
- }
- root_msg_index_ = root_msg_idx;
- return true;
-}
+namespace perfetto {
-MessageFilter::FilteredMessage MessageFilter::FilterMessageFragments(
- const InputSlice* slices,
- size_t num_slices) {
- // First compute the upper bound for the output. The filtered message cannot
- // be > the original message.
- uint32_t total_len = 0;
- for (size_t i = 0; i < num_slices; ++i)
- total_len += slices[i].len;
- out_buf_.reset(new uint8_t[total_len]);
- out_ = out_buf_.get();
- out_end_ = out_ + total_len;
+namespace base {
+class TaskRunner;
+} // namespace base
- // Reset the parser state.
- tokenizer_ = MessageTokenizer();
- error_ = false;
- stack_.clear();
- stack_.resize(2);
- // stack_[0] is a sentinel and should never be hit in nominal cases. If we
- // end up there we will just keep consuming the input stream and detecting
- // at the end, without hurting the fastpath.
- stack_[0].in_bytes_limit = UINT32_MAX;
- stack_[0].eat_next_bytes = UINT32_MAX;
- // stack_[1] is the actual root message.
- stack_[1].in_bytes_limit = total_len;
- stack_[1].msg_index = config_.root_msg_index();
+class ProducerEndpoint;
+class SharedMemory;
+class SharedMemoryArbiter;
+class TraceWriter;
- // Process the input data and write the output.
- for (size_t slice_idx = 0; slice_idx < num_slices; ++slice_idx) {
- const InputSlice& slice = slices[slice_idx];
- const uint8_t* data = static_cast<const uint8_t*>(slice.data);
- for (size_t i = 0; i < slice.len; ++i)
- FilterOneByte(data[i]);
- }
+namespace tracing_v2 {
- // Construct the output object.
- PERFETTO_CHECK(out_ >= out_buf_.get() && out_ <= out_end_);
- auto used_size = static_cast<size_t>(out_ - out_buf_.get());
- FilteredMessage res{std::move(out_buf_), used_size};
- res.error = error_;
- if (stack_.size() != 1 || !tokenizer_.idle() ||
- stack_[0].in_bytes != total_len) {
- res.error = true;
- }
- return res;
-}
+namespace test {
+class ProducerRingBufferArbiterTestPeer;
+} // namespace test
-void MessageFilter::FilterOneByte(uint8_t octet) {
- PERFETTO_DCHECK(!stack_.empty());
+// The producer side of one tracing v2 ring buffer.
+//
+// The producer's ProducerEndpoint (for example ProducerIPCClientImpl) creates
+// one arbiter for each ring buffer that it shares with the service. In this
+// file:
+// - "endpoint" means that ProducerEndpoint.
+// - "SMB arbiter" means the SharedMemoryArbiter used for v1 tracing.
+// - "writer" means TraceWriterV2Impl.
+//
+// This class:
+// - Keeps the ring buffer mapping alive and owns the SharedRingBuffer view.
+// - Creates writers. Their WriterIDs come from the SMB arbiter, because v1
+// and v2 writers of one producer share one ID pool.
+// - Tracks the service reader. See ReaderState.
+// - Delivers drain requests to the endpoint thread, which sends
+// DrainV2RingBuffer to the service. See DrainUrgency.
+// - Runs each Flush() callback after its drain request.
+//
+// Threads:
+// - Writers call ring_buffer(), RequestDrain(), IsReaderAttached(), Flush()
+// and OnWriterDestroyed() from any thread. CreateTraceWriter() can also run
+// on any thread.
+// - Creation, state changes, posted tasks, flush callbacks and service
+// requests run on the endpoint thread.
+//
+// The caller selects v2, then calls InitializeV2RingBuffer() on the endpoint
+// thread before it lets writers use the ring buffer.
+// Time goes down.
+// "--->" is a direct call, and "===>" is an IPC message.
+//
+// endpoint this class service
+// | | |
+// | Create() | |
+// |-------------------------->| kPending |
+// |== AttachV2RingBuffer, with the memfd ================>| maps, checks,
+// |<== reply =============================================| attaches
+// | OnReaderAttachReply() | |
+// |-------------------------->| kAttached, or |
+// | | kDetached if rejected |
+//
+// - Later instances reuse the ring buffer.
+// - If Create() fails, the endpoint has no arbiter and returns
+// NullTraceWriters for v2 requests.
+//
+// Flush(callback) posts its own drain task, then the callback. Time goes
+// down. "===>" is a posted task, or an IPC request to the service.
+//
+// writer thread endpoint thread service
+// | | |
+// | Flush(callback) | |
+// |==== drain task ======>| |
+// |==== callback ========>| |
+// | |== DrainV2RingBuffer =>| copies chunks
+// | | callback() |
+//
+// A message that the callback sends reaches the service after the drain
+// request. The service handles them in order.
+//
+// Ownership:
+//
+// - "owns": the owner destroys it, as a member or through a unique_ptr.
+// - "shares": a shared_ptr keeps it alive while any owner holds it.
+// - "uses": a raw pointer. The object must outlive the user.
+// - "holds": an allocated ID. The holder must release it.
+//
+// endpoint (for example ProducerIPCClientImpl)
+// |-- owns --> SharedMemoryArbiterImpl: the WriterID pool
+// |-- owns --> ProducerRingBufferArbiter (this class)
+// |-- shares-> SharedMemory: the ring buffer mapping
+// |-- owns --> SharedRingBuffer: the view
+// |-- uses --> endpoint, SharedMemoryArbiterImpl
+//
+// data source (SDK)
+// |-- owns --> TraceWriterV2Impl
+// |-- uses --> ProducerRingBufferArbiter
+// |-- holds -> a WriterID from SharedMemoryArbiterImpl
+// |-- owns --> SharedRingBufferWriter
+// |-- uses --> SharedRingBuffer
+//
+// Writers use raw pointers into objects that the endpoint owns. The WriterID
+// keeps these pointers valid:
+// - While a writer holds a WriterID, TryShutdown() of the SMB arbiter fails.
+// - So the endpoint keeps the SMB arbiter, this object and the mapping.
+// - The writer releases its WriterID last, in OnWriterDestroyed().
+class ProducerRingBufferArbiter {
+ public:
+ // Whether writers can rely on a service reader to free space.
+ // - Only the endpoint thread changes the state, but writers can read it
+ // from any thread.
+ // - This class sends drain requests in every state. The service handles
+ // attach and drain requests in order. It ignores a drain for a ring
+ // buffer that it did not accept.
+ //
+ // Create() OnReaderAttachReply(true)
+ // ----------> [ kPending ] --------------------------> [ kAttached ]
+ // | |
+ // +-------------------+--------------------+
+ // | Disconnect() or
+ // | OnReaderAttachReply(false)
+ // v
+ // [ kDetached ]
+ // (terminal)
+ enum class ReaderState {
+ // The endpoint has not received an attach reply yet.
+ // - Writers can already publish.
+ // - The service can still reject the ring buffer.
+ // - A writer does not wait for space in a full ring buffer. It drops the
+ // packet instead, also under kStall.
+ kPending,
+
+ // The service accepted the ring buffer. Its reader drains it.
+ // - A writer can wait for space in a full ring buffer.
+ kAttached,
+
+ // Terminal. No reader now or later. Disconnect() enters it after
+ // rejection, disconnect or destruction of this class.
+ // - New writers are NullTraceWriters.
+ // - Existing writers keep the mapping. They drop packets when the ring
+ // buffer is full.
+ kDetached,
+ };
- auto* state = &stack_.back();
- StackState next_state{};
- bool push_next_state = false;
+ // How soon RequestDrain() must send the drain request.
+ //
+ // Only the endpoint thread sends requests. Normally RequestDrain() posts a
+ // task there, and all requests made before the task runs share it. This
+ // saves IPC traffic. But if the caller is on the endpoint thread and blocks
+ // it right after RequestDrain(), the task cannot run until the caller
+ // unblocks, and the caller waits for that drain. The urgency tells
+ // RequestDrain() whether the request can wait for a task.
+ //
+ // It changes only when the request is sent. The service handles every
+ // request the same way, and RequestDrain() never waits for the drain.
+ enum class DrainUrgency {
+ // Set it when the caller does not block after RequestDrain().
+ // A task on the endpoint thread sends the request. Requests made before
+ // that task runs share it, so a burst of calls costs one request.
+ kRoutine,
+
+ // Set it when the caller blocks right after RequestDrain(), until the
+ // service reads the ring buffer.
+ // - On the endpoint thread, sends the request at once, before
+ // RequestDrain() returns.
+ // - On other threads, the same as kRoutine. The endpoint thread is free
+ // to run the task.
+ kUrgent,
+ };
- if (state->eat_next_bytes > 0) {
- // This is the case where the previous tokenizer_.Push() call returned a
- // length delimited message which is NOT a submessage (a string or a bytes
- // field). We just want to consume it, and pass it through/filter strings
- // if the field was allowed.
- --state->eat_next_bytes;
- if (state->action == StackState::kPassthrough) {
- *(out_++) = octet;
- } else if (state->action == StackState::kFilterString) {
- *(out_++) = octet;
- if (state->eat_next_bytes == 0) {
- config_.string_filter().MaybeFilter(
- reinterpret_cast<char*>(state->filter_string_ptr),
- static_cast<size_t>(out_ - state->filter_string_ptr),
- state->filter_string_semantic_type);
- }
- }
- } else {
- MessageTokenizer::Token token = tokenizer_.Push(octet);
- // |token| will not be valid() in most cases and this is WAI. When pushing
- // a varint field, only the last byte yields a token, all the other bytes
- // return an invalid token, they just update the internal tokenizer state.
- if (token.valid()) {
- auto filter = config_.filter().Query(state->msg_index, token.field_id);
- switch (token.type) {
- case proto_utils::ProtoWireType::kVarInt:
- if (filter.allowed && filter.simple_field())
- AppendVarInt(token.field_id, token.value, &out_);
- break;
- case proto_utils::ProtoWireType::kFixed32:
- if (filter.allowed && filter.simple_field())
- AppendFixed(token.field_id, static_cast<uint32_t>(token.value),
- &out_);
- break;
- case proto_utils::ProtoWireType::kFixed64:
- if (filter.allowed && filter.simple_field())
- AppendFixed(token.field_id, static_cast<uint64_t>(token.value),
- &out_);
- break;
- case proto_utils::ProtoWireType::kLengthDelimited:
- // Here we have two cases:
- // A. A simple string/bytes field: we just want to consume the next
- // bytes (the string payload), optionally passing them through in
- // output if the field is allowed.
- // B. This is a nested submessage. In this case we want to recurse and
- // push a new state on the stack.
- // Note that we can't tell the difference between a
- // "non-allowed string" and a "non-allowed submessage". But it doesn't
- // matter because in both cases we just want to skip the next N bytes.
- const auto submessage_len = static_cast<uint32_t>(token.value);
- auto in_bytes_left = state->in_bytes_limit - state->in_bytes - 1;
- if (PERFETTO_UNLIKELY(submessage_len > in_bytes_left)) {
- // This is a malicious / malformed string/bytes/submessage that
- // claims to be larger than the outer message that contains it.
- return SetUnrecoverableErrorState();
- }
+ // Allocates the shared memory for a ring buffer of |size| bytes, header
+ // included, or returns an error status on failure.
+ using AllocateSharedMemoryFn =
+ base::StatusOr<std::shared_ptr<SharedMemory>> (*)(size_t size);
+
+ // Sizes and allocates a ring buffer from |config|, then creates its arbiter
+ // in kPending.
+ // - The chunk size and the drain occupancy threshold come from |config|.
+ // - |task_runner| and |endpoint| must outlive the arbiter.
+ // - |allocate_shared_memory| must return a mapping of the size it is given.
+ // - Returns an error status if sizing or allocation fails.
+ // - The endpoint then attaches memory() to the service, and passes the reply
+ // to OnReaderAttachReply().
+ static base::StatusOr<std::unique_ptr<ProducerRingBufferArbiter>> Create(
+ base::TaskRunner* task_runner,
+ ProducerEndpoint* endpoint,
+ const DataSourceConfig& config,
+ size_t shmem_size_hint_bytes,
+ AllocateSharedMemoryFn allocate_shared_memory);
+
+ // The endpoint destroys this on its thread after all writers release their
+ // IDs. Calls Disconnect().
+ ~ProducerRingBufferArbiter();
+
+ // Writers keep a pointer to this object.
+ ProducerRingBufferArbiter(const ProducerRingBufferArbiter&) = delete;
+ ProducerRingBufferArbiter& operator=(const ProducerRingBufferArbiter&) =
+ delete;
- if (filter.allowed && filter.nested_msg_field() &&
- submessage_len > 0) {
- // submessage_len == 0 is the edge case of a message with a 0-len
- // (but present) submessage. In this case, if allowed, we don't want
- // to push any further state (doing so would desync the FSM) but we
- // still want to emit it.
- // At this point |submessage_len| is only an upper bound. The
- // final message written in output can be <= the one in input,
- // only some of its fields might be allowed (also remember that
- // this class implicitly removes redundancy varint encoding of
- // len-delimited field lengths). The final length varint (the
- // return value of AppendLenDelim()) will be filled when popping
- // from |stack_|.
- auto size_field =
- AppendLenDelim(token.field_id, submessage_len, &out_);
- push_next_state = true;
- next_state.field_id = token.field_id;
- next_state.msg_index = filter.nested_msg_index;
- next_state.in_bytes_limit = submessage_len;
- next_state.size_field = size_field.first;
- next_state.size_field_len = size_field.second;
- next_state.out_bytes_written_at_start = out_written();
- } else {
- // A string or bytes field, or a 0 length submessage.
- state->eat_next_bytes = submessage_len;
- if (filter.allowed && filter.filter_string_field()) {
- state->action = StackState::kFilterString;
- AppendLenDelim(token.field_id, submessage_len, &out_);
- state->filter_string_ptr = out_;
- state->filter_string_semantic_type = filter.semantic_type;
- } else if (filter.allowed) {
- state->action = StackState::kPassthrough;
- AppendLenDelim(token.field_id, submessage_len, &out_);
- } else {
- state->action = StackState::kDrop;
- }
- }
- break;
- } // switch(type)
+ // The mapping that holds the ring buffer, which the endpoint attaches to the
+ // service.
+ // Fixed for the life of this object.
+ const std::shared_ptr<SharedMemory>& memory() const { return memory_; }
- if (PERFETTO_UNLIKELY(track_field_usage_)) {
- IncrementCurrentFieldUsage(token.field_id, filter.allowed);
- }
- } // if (token.valid)
- } // if (eat_next_bytes == 0)
+ // Reader state:
- ++state->in_bytes;
- while (state->in_bytes >= state->in_bytes_limit) {
- PERFETTO_DCHECK(state->in_bytes == state->in_bytes_limit);
- push_next_state = false;
+ // Called by the endpoint with the attach reply, on the endpoint thread.
+ // Enters kAttached on acceptance or kDetached on rejection. Does nothing
+ // after Disconnect(), because the reply can arrive after it.
+ void OnReaderAttachReply(bool reader_attached);
- // We can't possibly write more than we read.
- const uint32_t msg_bytes_written = static_cast<uint32_t>(
- out_written() - state->out_bytes_written_at_start);
- PERFETTO_DCHECK(msg_bytes_written <= state->in_bytes_limit);
+ // True in kAttached only. If false, nothing frees space in a full ring
+ // buffer. Writers call it on their own thread.
+ bool IsReaderAttached() const;
- // Backfill the length field of the
- proto_utils::WriteRedundantVarInt(msg_bytes_written, state->size_field,
- state->size_field_len);
+ // Enters kDetached after rejection or disconnect, on the endpoint thread.
+ // Repeated calls are safe.
+ void Disconnect();
- const uint32_t in_bytes_processes_for_last_msg = state->in_bytes;
- stack_.pop_back();
- PERFETTO_CHECK(!stack_.empty());
- state = &stack_.back();
- state->in_bytes += in_bytes_processes_for_last_msg;
- if (PERFETTO_UNLIKELY(!tokenizer_.idle())) {
- // If we hit this case, it means that we got to the end of a submessage
- // while decoding a field. We can't recover from this and we don't want to
- // propagate a broken sub-message.
- return SetUnrecoverableErrorState();
- }
+ // Writers:
+
+ // Creates a writer for |target_buffer|, on any thread. The caller owns the
+ // writer.
+ //
+ // Never returns null. Returns a NullTraceWriter, which discards all
+ // packets, if:
+ // - the state is kDetached, or
+ // - the SMB arbiter has no free WriterID (exhaustion or shutdown).
+ std::unique_ptr<TraceWriter> CreateTraceWriter(BufferID target_buffer,
+ BufferExhaustedPolicy);
+
+ // The writer calls this on its thread after its final publication.
+ // - Releases its WriterID in the SMB arbiter.
+ // - The release can let the endpoint destroy this object. So the call must
+ // be the writer's last access to it.
+ void OnWriterDestroyed(WriterID);
+
+ // The view that writers borrow. Fixed for the life of this object.
+ SharedRingBuffer* ring_buffer() { return &ring_buffer_; }
+
+ uint32_t drain_occupancy_threshold() const {
+ return drain_occupancy_threshold_;
}
- if (push_next_state) {
- PERFETTO_DCHECK(tokenizer_.idle());
- stack_.emplace_back(std::move(next_state));
- state = &stack_.back();
+ // Drain requests, from writers on their own thread:
+
+ // Asks the service to read the ring buffer. See DrainUrgency.
+ void RequestDrain(DrainUrgency);
+
+ // Requests a drain after the writer publishes its data. Then runs |callback|
+ // on the endpoint thread. See the class comment for the order.
+ // - Does not wait for a service ack.
+ // - If the endpoint destroys this object before the drain task runs, the
+ // task sends nothing. The endpoint thread still runs |callback|.
+ void Flush(std::function<void()>);
+
+ // The returned pointer can only be dereferenced on the endpoint thread.
+ base::WeakPtr<ProducerRingBufferArbiter> GetWeakPtr() const {
+ return weak_factory_.GetWeakPtr();
}
-}
-void MessageFilter::SetUnrecoverableErrorState() {
- error_ = true;
- stack_.clear();
- stack_.resize(1);
- auto& state = stack_[0];
- state.eat_next_bytes = UINT32_MAX;
- state.in_bytes_limit = UINT32_MAX;
- state.action = StackState::kDrop;
- out_ = out_buf_.get(); // Reset the write pointer.
-}
+ private:
+ friend class test::ProducerRingBufferArbiterTestPeer;
+
+ // Only Create() calls this.
+ // |memory| must be non-null and satisfy NumChunksForRingBufferLayout().
+ // |drain_occupancy_threshold| is the number of outstanding positions at
+ // which a publication requests a drain, from 1 to the ring's chunk count.
+ ProducerRingBufferArbiter(base::TaskRunner* task_runner,
+ ProducerEndpoint* endpoint,
+ std::shared_ptr<SharedMemory> memory,
+ uint32_t chunk_size,
+ uint32_t drain_occupancy_threshold);
+
+ // Runs on the endpoint thread. CHECKs that the transition is valid.
+ void SetReaderState(ReaderState);
+
+ // Posts a drain task to the endpoint thread. Callable from any thread.
+ // - Without |force|, requests share a pending task.
+ // - |force| posts a new task so Flush() can place its callback after it.
+ // - The task clears |drain_task_pending_|, then sends DrainV2RingBuffer.
+ void PostDrainTask(bool force);
+
+ // --- Borrowed. They must outlive this object. ---
+
+ // Runs tasks on the endpoint thread. Writers post drain and flush
+ // requests here.
+ base::TaskRunner* const task_runner_;
+ // Sends drain requests to the service, on the endpoint thread only.
+ ProducerEndpoint* const endpoint_;
+ // The SMB arbiter. Any thread allocates and releases WriterIDs here.
+ SharedMemoryArbiter* const shared_memory_arbiter_;
-void MessageFilter::IncrementCurrentFieldUsage(uint32_t field_id,
- bool allowed) {
- // Slowpath. Used mainly in offline tools and tests to workout used fields in
- // a proto.
- PERFETTO_DCHECK(track_field_usage_);
+ // --- Ring buffer mapping and view. Fixed after construction. ---
- // Field path contains a concatenation of varints, one for each nesting level.
- // e.g. y in message Root { Sub x = 2; }; message Sub { SubSub y = 7; }
- // is encoded as [varint(2) + varint(7)].
- // We use varint to take the most out of SSO (small string opt). In most cases
- // the path will fit in the on-stack 22 bytes, requiring no heap.
- std::string field_path;
+ // The shared memory that holds the ring buffer. Declared before
+ // |ring_buffer_|, which points into it.
+ //
+ // Mapping ownership depends on the transport:
+ // - In-process, producer and service share this pointer. The mapping stays
+ // alive until both release it.
+ // - Over IPC, the service maps the fd separately and owns that mapping.
+ const std::shared_ptr<SharedMemory> memory_;
+ // The view that writers borrow.
+ SharedRingBuffer ring_buffer_;
+ // A publication asks for a drain when the ring buffer has at least this many
+ // outstanding positions.
+ // - The count covers the positions of all writers.
+ // - It includes reservations whose chunks are not published yet.
+ // - Fixed at construction and shared by all writers.
+ const uint32_t drain_occupancy_threshold_;
+
+ // --- Shared with writer threads. ---
+
+ // Writers read it from any thread. Only SetReaderState() writes it.
+ std::atomic<ReaderState> reader_state_{ReaderState::kPending};
+ // Nonzero while a shared drain task is pending. A request without |force|
+ // sets it before it posts that task. The task clears it before it sends
+ // DrainV2RingBuffer.
+ std::atomic<uint32_t> drain_task_pending_{0};
- auto append_field_id = [&field_path](uint32_t id) {
- uint8_t buf[10];
- uint8_t* end = proto_utils::WriteVarInt(id, buf);
- field_path.append(reinterpret_cast<char*>(buf),
- static_cast<size_t>(end - buf));
- };
+ PERFETTO_THREAD_CHECKER(thread_checker_)
- // Append all the ancestors IDs from the state stack.
- // The first entry of the stack has always ID 0 and we skip it (we don't know
- // the ID of the root message itself).
- PERFETTO_DCHECK(stack_.size() >= 2 && stack_[1].field_id == 0);
- for (size_t i = 2; i < stack_.size(); ++i)
- append_field_id(stack_[i].field_id);
- // Append the id of the field in the current message.
- append_field_id(field_id);
- field_usage_[field_path] += allowed ? 1 : -1;
-}
+ // Any thread can call GetWeakPtr(). Only the endpoint thread dereferences
+ // the weak pointers.
+ base::WeakPtrFactory<ProducerRingBufferArbiter> weak_factory_{this};
+};
-} // namespace protozero
-// gen_amalgamated begin source: src/protozero/filtering/message_filter_config.cc
-// gen_amalgamated begin header: src/protozero/filtering/message_filter_config.h
+} // namespace tracing_v2
+} // namespace perfetto
+
+#endif // SRC_TRACING_V2_PRODUCER_RING_BUFFER_ARBITER_H_
+// gen_amalgamated begin header: src/tracing/v2/trace_writer_v2_impl.h
+// gen_amalgamated begin header: src/tracing/v2/shared_ring_buffer_writer.h
/*
* Copyright (C) 2026 The Android Open Source Project
*
@@ -59353,28 +65099,347 @@ void MessageFilter::IncrementCurrentFieldUsage(uint32_t field_id,
* limitations under the License.
*/
-#ifndef SRC_PROTOZERO_FILTERING_MESSAGE_FILTER_CONFIG_H_
-#define SRC_PROTOZERO_FILTERING_MESSAGE_FILTER_CONFIG_H_
+#ifndef SRC_TRACING_V2_SHARED_RING_BUFFER_WRITER_H_
+#define SRC_TRACING_V2_SHARED_RING_BUFFER_WRITER_H_
-// gen_amalgamated expanded: #include "perfetto/base/status.h"
-// gen_amalgamated expanded: #include "protos/perfetto/config/trace_config.gen.h"
-// gen_amalgamated expanded: #include "src/protozero/filtering/message_filter.h"
+#include <stdint.h>
-namespace protozero {
+#include <functional>
+#include <optional>
+#include <vector>
-// Loads a MessageFilter from the trace_filter field of a TraceConfig.
-// This sets up the string filter rules (both base and v54 chains) and loads
-// the bytecode (v1/v2 + v54 overlay).
-// On failure, returns a non-ok status with a descriptive error message.
-// On success, the caller may optionally call SetFilterRoot() to adjust the
-// root message (e.g. for per-packet filtering in the tracing service).
-perfetto::base::Status LoadMessageFilterConfig(
- const perfetto::protos::gen::TraceConfig::TraceFilter& filt,
- MessageFilter* filter);
+// gen_amalgamated expanded: #include "perfetto/ext/tracing/core/basic_types.h"
+// gen_amalgamated expanded: #include "src/tracing/v2/shared_ring_buffer.h"
+// gen_amalgamated expanded: #include "src/tracing/v2/shared_ring_buffer_abi.h"
-} // namespace protozero
+namespace perfetto::tracing_v2 {
-#endif // SRC_PROTOZERO_FILTERING_MESSAGE_FILTER_CONFIG_H_
+// Writes the packet fragments produced by one TraceWriter into a
+// SharedRingBuffer.
+//
+// - A fragment is one packet, or part of a packet that crosses a chunk
+// boundary. A chunk can hold several fragments. The writer handles their
+// byte ranges and sizes without interpreting their contents.
+// - Use each instance from one thread at a time. Several instances can write
+// to the same ring buffer concurrently.
+// - Keep the ring buffer's memory and SharedRingBuffer view alive until
+// every writer is destroyed. The destructor still publishes its chunk.
+// - The writer gets a chunk in two steps:
+// 1. Reserve a write position. This moves write_pos.
+// 2. Claim the chunk at that position: change its state from Free to
+// BeingWritten.
+// Step 2 can fail, for example if an older writer still holds the chunk.
+// The reserved position then stays unused, and only the reader can move
+// past it.
+// - The writer only accesses the ring buffer. It does not contact the reader,
+// and it does not apply a BufferExhaustedPolicy. TraceWriterV2Impl does
+// both.
+// - A call that needs a new chunk makes at most num_chunks attempts to
+// reserve and claim one. If none succeeds, the call returns at once with
+// kFull or kClaimFailed. Only WaitForReadPosChange() blocks.
+//
+// The writer is in one of three states:
+// - Ready: no fragment is open. The writer can still hold the chunk that it
+// published last. It appends the next fragment there if the fragment fits,
+// without a new reservation.
+// - Fragment open: BeginFragment() returned a range. The caller writes the
+// fragment's bytes into it.
+// - Relocation pending: the reader took the chunk before EndFragment()
+// published the fragment, and the writer could not claim a replacement
+// chunk. The writer keeps a copy of the fragment. See EndFragment().
+//
+// The calls and the states that allow them:
+// - BeginFragment(): Ready. On success, opens a fragment.
+// - EndFragment(): Fragment open. Publishes the fragment and returns to
+// Ready, or enters Relocation pending.
+// - RetryRelocation(): Relocation pending. Publishes the saved copy and
+// returns to Ready, or stays in Relocation pending.
+// - DropRelocation(): Relocation pending. Drops the saved copy and returns to
+// Ready.
+// - FinishCurrentChunk(): Ready or Fragment open. Releases the held chunk, so
+// the next fragment needs a new one. TraceWriterV2Impl::Flush() uses it.
+// - In Fragment open, it abandons the open fragment and publishes the
+// earlier fragments of the chunk.
+// - WaitForReadPosChange(): after a call returned kFull or kClaimFailed.
+// - RecordDataLoss(), has_pending_data_loss(), accessors and GetStats(): any
+// state.
+class SharedRingBufferWriter {
+ public:
+ // Result of BeginFragment(), which may need a new chunk.
+ enum class BeginFragmentResult {
+ kSuccess,
+ // The ring buffer is structurally full: num_chunks positions are
+ // outstanding and the reader is behind. The call reserved nothing.
+ kFull,
+ // The call reserved a position, but could not claim its chunk, for example
+ // because an older writer still holds it.
+ //
+ // The reserved position stays unused until the reader moves past it.
+ // Chunks pinned by a stalled writer produce this without the ring buffer
+ // being full.
+ kClaimFailed,
+ // The request is larger than a freshly claimed chunk could hold. This is a
+ // caller bug, not backpressure.
+ kTooLarge,
+ };
+
+ // Result of EndFragment(), RetryRelocation() and FinishCurrentChunk(), which
+ // publish.
+ enum class EndFragmentResult {
+ kSuccess,
+ // The reader took the chunk before the publication, and the writer could
+ // not claim a replacement chunk. The reasons are the same as in
+ // BeginFragmentResult. The writer is then in Relocation pending.
+ kFull,
+ kClaimFailed,
+ };
+
+ // Result of RetryRelocation().
+ struct RetryRelocationResult {
+ EndFragmentResult result = EndFragmentResult::kFull;
+ // True if the call claimed at least one replacement chunk.
+ // - A successful claim ends one acquisition. A caller that limits each
+ // acquisition, such as TraceWriterV2Impl, then starts a new limit.
+ // - With kFull or kClaimFailed, the reader also took the last replacement
+ // before its publication, and the next claim attempts failed.
+ bool acquired_replacement = false;
+ };
+
+ // A contiguous range for the caller to fill. Valid until the next call on
+ // this SharedRingBufferWriter.
+ struct FragmentRange {
+ BeginFragmentResult result = BeginFragmentResult::kFull;
+ uint8_t* begin = nullptr;
+ uint8_t* end = nullptr;
+ };
+
+ SharedRingBufferWriter(SharedRingBuffer* ring,
+ WriterID writer_id,
+ BufferID target_buffer);
+ ~SharedRingBufferWriter();
+
+ SharedRingBufferWriter(const SharedRingBufferWriter&) = delete;
+ SharedRingBufferWriter& operator=(const SharedRingBufferWriter&) = delete;
+ SharedRingBufferWriter(SharedRingBufferWriter&&) = delete;
+ SharedRingBufferWriter& operator=(SharedRingBufferWriter&&) = delete;
+
+ // Starts a fragment for the caller to fill.
+ // - On success, returns a writable range of at least |min_size| bytes.
+ // - Reuses space in the current chunk when possible. Otherwise, tries to
+ // claim a new chunk. See the class comment.
+ // - Call EndFragment() after writing the bytes.
+ // - Only one fragment can be open at a time.
+ //
+ // |continues_from_prev| describes the packet this fragment belongs to:
+ // - true: continues the packet from this writer's previous chunk.
+ // - false: starts a new packet.
+ // The flag describes the first fragment of a chunk.
+ //
+ // If BeginFragment(..., true) cannot acquire space, the caller can abandon
+ // the rest of the packet. The next packet must start with
+ // BeginFragment(..., false), even though the previous chunk still marks a
+ // continuation. Only the caller knows that a new packet starts. The writer
+ // cannot infer |continues_from_prev| from the previous chunk's flag.
+ FragmentRange BeginFragment(uint32_t min_size, bool continues_from_prev);
+
+ // Ends the open fragment at |size| bytes and publishes it, so the reader
+ // can copy it. |size| must fit the range from BeginFragment().
+ //
+ // Set |continues_on_next| if the packet continues in the next chunk, which
+ // then starts with BeginFragment(..., true). The flag marks the chunk's last
+ // fragment, so the writer appends nothing more to this chunk.
+ //
+ // The reader can take a chunk while its last fragment is still open: it
+ // copies the published fragments and asks the writer to move the open one.
+ // EndFragment() then relocates the fragment:
+ // 1. It saves a copy and acknowledges the request, so the reader can reuse
+ // the old chunk.
+ // 2. It claims a new chunk, copies the fragment there and publishes it. If
+ // the reader takes this chunk too, it repeats.
+ // If step 2 cannot claim a chunk, returns kFull or kClaimFailed. The
+ // relocation is then pending: call RetryRelocation() or DropRelocation().
+ EndFragmentResult EndFragment(uint32_t size, bool continues_on_next);
+
+ // Tries again to claim a chunk for the saved fragment, and publishes it
+ // there, as EndFragment() does. Only in Relocation pending.
+ RetryRelocationResult RetryRelocation();
+
+ // Drops the saved fragment. The next publication sets kFlagDataLoss. Only in
+ // Relocation pending.
+ void DropRelocation();
+
+ // Blocks the calling thread. The wait requests at most |timeout_ms|.
+ // Scheduling can make the elapsed time longer.
+ //
+ // Call it after kFull or kClaimFailed. A return does not reserve space. Call
+ // again to try for a chunk.
+ // - With a futex: returns when read_pos differs from the value that the
+ // last reservation attempt saw, at the timeout, or on a spurious wake. So
+ // if the reader moved read_pos after that attempt, it returns at once.
+ // - Without a futex: sleeps for the next step of v1's backoff, 0, 8, 72, ...
+ // microseconds, at most 100 ms per step. No sleep requests more than
+ // |timeout_ms|. It does not check read_pos.
+ void WaitForReadPosChange(uint32_t timeout_ms);
+
+ // Publishes whatever is held and lets go of the chunk. Any open fragment is
+ // abandoned: its bytes were never counted, so nothing is published for it.
+ // Safe to call with nothing held. The destructor calls it.
+ EndFragmentResult FinishCurrentChunk();
+
+ // Records loss for the next chunk publication.
+ // - A cached chunk can still be reused, even when the ring buffer is full.
+ // - The publication sets kFlagDataLoss. The reader discards all published
+ // fragments in that chunk. Even complete packets before or after the gap
+ // are discarded. The flag cannot identify which packets are safe.
+ // - Data already delivered by the reader cannot be retracted.
+ void RecordDataLoss() { data_loss_pending_ = true; }
+
+ // True until a claimed or published chunk carries the recorded loss. This
+ // includes a loss flag that a pending relocation inherited from the
+ // rewritten chunk.
+ //
+ // TraceWriterV2Impl uses it so that kStallThenDrop does not stall again for
+ // each dropped packet.
+ bool has_pending_data_loss() const {
+ return data_loss_pending_ ||
+ (pending_relocation_ &&
+ (pending_relocation_->chunk_flags & kFlagDataLoss));
+ }
+
+ WriterID writer_id() const { return writer_id_; }
+ // Largest range that BeginFragment() can return.
+ uint32_t max_fragment_size() const { return max_fragment_size_; }
+
+ // For diagnostics only. The protocol never reads these counters.
+ // TODO(sashwinbalaji): Wire these counters into service statistics.
+ struct Stats {
+ uint64_t failed_claims = 0;
+ uint64_t fragments_dropped = 0;
+ uint64_t relocations = 0;
+ };
+ Stats GetStats() const { return stats_; }
+
+ private:
+ friend class test::SharedRingBufferInternalsForTest;
+
+ static constexpr uint32_t kNoFragmentOpen = UINT32_MAX;
+
+ // A saved fragment that waits for a replacement chunk. Its bytes are in
+ // |relocation_payload_|.
+ struct PendingRelocation {
+ // Flags for the replacement chunk's BeingWritten word. Only
+ // kFlagContinuesFromPrevChunk and kFlagDataLoss, inherited from the
+ // rewritten chunk.
+ uint32_t chunk_flags = 0;
+ // Sets kFlagContinuesOnNextChunk on the replacement's publication.
+ bool continues_on_next = false;
+ };
+
+ // Maximum payload available to one more fragment in the cached chunk, which
+ // must exist.
+ uint32_t MaxFragmentSizeInCurrentChunk() const;
+ ChunkState cur_chunk_state() const {
+ return ChunkStateOf(expected_state_word_);
+ }
+ bool has_open_fragment() const {
+ return cur_fragment_begin_ != kNoFragmentOpen;
+ }
+
+ FragmentRange BeginFragmentInCurrentChunk(uint32_t available);
+ BeginFragmentResult AcquireNewChunk(uint32_t continuation_flags);
+ // Only the just-ended fragment can be complete but unpublished:
+ // - A size of zero is a valid empty fragment.
+ // - nullopt means FinishCurrentChunk() has no fragment to publish.
+ EndFragmentResult ReleaseCurrentChunkAsComplete(
+ std::optional<uint32_t> fragment_size,
+ bool continues_on_next);
+ // Writes the saved fragment into the newly claimed chunk, as its only
+ // fragment.
+ void CopyRelocatedFragment(uint32_t fragment_size);
+ // Clears only this writer's cached chunk state. It does not modify the ring
+ // buffer.
+ void ResetCurrentChunk();
+
+ SharedRingBuffer* const ring_;
+ const WriterID writer_id_;
+ const BufferID target_buffer_;
+ const uint32_t chunk_size_;
+ // MaxFragmentSizeForEmptyChunk(chunk_size_), computed once.
+ const uint32_t max_fragment_size_;
+
+ // State cached for the chunk this writer currently owns.
+ uint8_t* cur_chunk_ = nullptr;
+ ChunkIndex cur_chunk_idx_ = ChunkIndex::FromIndex(0);
+ // The exact word this writer's next compare-and-swap expects. It can differ
+ // from the shared word once the reader has requested a rewrite.
+ uint32_t expected_state_word_ = 0;
+ // Payload grows from the header. Size entries grow backwards from the end.
+ // - payload_end_ is measured from the chunk start.
+ // - size_directory_bytes_ counts bytes used from the chunk end.
+ //
+ // Example: a 256-byte chunk with 200 payload bytes and 4 directory bytes.
+ //
+ // 0 6 206 252 256
+ // +--------+---------------------+------------------+-----------+
+ // | header | payload grows ---> | free space | <-- sizes |
+ // +--------+---------------------+------------------+-----------+
+ //
+ // Here: chunk_size_ = 256, payload_end_ = 206, size_directory_bytes_ = 4.
+ // Directory start = chunk_size_ - size_directory_bytes_ = 252.
+ // Free bytes = chunk_size_ - payload_end_ - size_directory_bytes_ = 46.
+ //
+ // Byte offset from the chunk start to the end of finalized payload.
+ uint32_t payload_end_ = 0;
+ // Size-directory bytes used from the chunk end. Zero means no entries.
+ uint32_t size_directory_bytes_ = 0;
+ // Finalized fragments, published or not. expected_state_word_ contains the
+ // count already visible to the reader.
+ uint32_t num_fragments_ = 0;
+ // Byte offset from the chunk start to the open fragment, or kNoFragmentOpen.
+ uint32_t cur_fragment_begin_ = kNoFragmentOpen;
+
+ // Whether kFlagDataLoss still needs to be set in a chunk's state word.
+ // - Cleared after successfully claiming or publishing a chunk with the flag.
+ // - Kept pending if the reader requests a rewrite before publication.
+ // AcquireNewChunk() then sets the flag in the replacement chunk.
+ // - A rewrite of BeingWritten(0) can move the chunk's loss flag into
+ // |pending_relocation_|, not back into this flag. has_pending_data_loss()
+ // checks both.
+ bool data_loss_pending_ = false;
+
+ // The read_pos that the last reservation attempt saw.
+ // WaitForReadPosChange() waits while read_pos keeps this value.
+ uint32_t read_pos_for_wait_ = 0;
+
+ // Stop trying the syscall if the build or kernel cannot provide it.
+ // Once false, this writer uses sleep backoff for later waits too.
+ bool use_futex_ = SharedRingBuffer::SupportsWriterWait();
+
+ // The next sleep of the backoff without futex. It grows with each sleep, up
+ // to 100 ms, across calls. It resets when the writer claims a chunk.
+ uint32_t fallback_sleep_us_ = 0;
+
+ // Set when a relocation cannot claim a replacement chunk. RetryRelocation()
+ // clears it after a claim. DropRelocation() also clears it.
+ std::optional<PendingRelocation> pending_relocation_;
+
+ // Unpublished fragment saved while changing chunks. Allocated on demand and
+ // reused. Writers that never relocate need no payload storage here.
+ std::vector<uint8_t> relocation_payload_;
+
+ // Test callback, called after each replacement claim, before the
+ // publication.
+ // - The callback requests a rewrite of the replacement, as the reader can.
+ // The publication then fails, and the writer relocates again.
+ // Empty in production. Tests force the race without scheduling threads.
+ std::function<void()> after_replacement_claim_for_testing_;
+
+ Stats stats_;
+};
+
+} // namespace perfetto::tracing_v2
+
+#endif // SRC_TRACING_V2_SHARED_RING_BUFFER_WRITER_H_
/*
* Copyright (C) 2026 The Android Open Source Project
*
@@ -59391,118 +65456,537 @@ perfetto::base::Status LoadMessageFilterConfig(
* limitations under the License.
*/
-// gen_amalgamated expanded: #include "src/protozero/filtering/message_filter_config.h"
+#ifndef SRC_TRACING_V2_TRACE_WRITER_V2_IMPL_H_
+#define SRC_TRACING_V2_TRACE_WRITER_V2_IMPL_H_
#include <cstdint>
+#include <functional>
+#include <memory>
#include <optional>
-#include <string>
-// gen_amalgamated expanded: #include "perfetto/base/status.h"
-// gen_amalgamated expanded: #include "protos/perfetto/config/trace_config.gen.h"
-// gen_amalgamated expanded: #include "src/protozero/filtering/message_filter.h"
-// gen_amalgamated expanded: #include "src/protozero/filtering/string_filter.h"
+// gen_amalgamated expanded: #include "perfetto/base/proc_utils.h"
+// gen_amalgamated expanded: #include "perfetto/base/time.h"
+// gen_amalgamated expanded: #include "perfetto/ext/tracing/core/basic_types.h"
+// gen_amalgamated expanded: #include "perfetto/ext/tracing/core/trace_writer.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/message_handle.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/root_message.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/scattered_stream_writer.h"
+// gen_amalgamated expanded: #include "perfetto/tracing/buffer_exhausted_policy.h"
+// gen_amalgamated expanded: #include "src/tracing/v2/shared_ring_buffer_writer.h"
-namespace protozero {
+namespace perfetto::tracing_v2 {
-namespace {
+class ProducerRingBufferArbiter;
-using TraceFilter = perfetto::protos::gen::TraceConfig::TraceFilter;
-using StringFilterRule = TraceFilter::StringFilterRule;
+namespace test {
+class TraceWriterV2ImplTestPeer;
+} // namespace test
-std::optional<StringFilter::Policy> ConvertPolicy(
- TraceFilter::StringFilterPolicy policy) {
- switch (policy) {
- case TraceFilter::SFP_UNSPECIFIED:
- return std::nullopt;
- case TraceFilter::SFP_MATCH_REDACT_GROUPS:
- return StringFilter::Policy::kMatchRedactGroups;
- case TraceFilter::SFP_ATRACE_MATCH_REDACT_GROUPS:
- return StringFilter::Policy::kAtraceMatchRedactGroups;
- case TraceFilter::SFP_MATCH_BREAK:
- return StringFilter::Policy::kMatchBreak;
- case TraceFilter::SFP_ATRACE_MATCH_BREAK:
- return StringFilter::Policy::kAtraceMatchBreak;
- case TraceFilter::SFP_ATRACE_REPEATED_SEARCH_REDACT_GROUPS:
- return StringFilter::Policy::kAtraceRepeatedSearchRedactGroups;
+// TraceWriter implementation backed by a tracing v2 shared ring buffer.
+//
+// Data path from the SDK to the service. "v" is a call or a write. "^" is a
+// read by the service. "<--" is an IPC request.
+//
+// v1: SMB v2: ring buffer
+//
+// data source (SDK) data source (SDK)
+// | NewTracePacket() | NewTracePacket()
+// v v
+// TraceWriterImpl TraceWriterV2Impl (this class)
+// | |
+// | GetNewChunk() | BeginFragment(), EndFragment()
+// v v
+// SharedMemoryArbiterImpl SharedRingBufferWriter
+// | picks a free chunk, | claims and publishes chunks
+// | batches completed chunks | lock-free. The bytes do not
+// | | go through
+// | | ProducerRingBufferArbiter.
+// v v
+// [ SMB ] [ ring buffer ]
+// ^ ^
+// | copies the listed chunks | copies all published chunks
+// | |
+// service <-- CommitData IPC service <-- DrainV2RingBuffer IPC
+// from the arbiter: from the ring buffer arbiter:
+// "chunks N, M are "read what is
+// complete" published"
+//
+// The ring buffer arbiter is ProducerRingBufferArbiter. It sends the drain
+// requests of all writers of the ring buffer.
+//
+// Only this class calls both SharedRingBufferWriter and
+// ProducerRingBufferArbiter:
+// - SharedRingBufferWriter claims chunks, and publishes and relocates
+// fragments.
+// - The arbiter delivers drain requests to the endpoint thread.
+//
+// This class decides:
+// - When to ask for a drain:
+// - After a publication, if the ring buffer's outstanding positions reach
+// the arbiter's drain occupancy threshold.
+// - After failed claims, if the writer drops the data. Only the reader can
+// move past those positions.
+// - Before each wait for space.
+// - What to do when no chunk is free: wait for the reader and try again, or
+// drop the packet. See TryStallForSpace().
+//
+// A nested message can span chunks, and the reader can copy an earlier
+// fragment while the message is still open. So this writer cannot patch
+// length fields later, as v1 does. It uses proto group encoding instead:
+// - The format: proto_utils::kProtoGroupEndByte.
+// - The service converts each packet back to length-delimited protobuf: see
+// ProtoGroupRewriter.
+//
+// If the writer drops any part of a packet:
+// - Its remaining bytes go to the drop buffer.
+// - The next publication sets kFlagDataLoss. The reader discards all
+// published fragments in that chunk and reports the gap.
+// - The service discards orphan continuations. It still delivers later
+// complete packets from chunks without the flag.
+//
+// Threads:
+// - As with TraceWriterImpl, use each instance from one thread at a time.
+class TraceWriterV2Impl : public TraceWriter,
+ public protozero::MessageFinalizationListener,
+ public protozero::ScatteredStreamWriter::Delegate {
+ public:
+ // ProducerRingBufferArbiter::CreateTraceWriter() creates each writer.
+ //
+ // |ring_buffer_arbiter| supplies the ring buffer. Packet bytes go directly
+ // into it. The arbiter also receives drain requests and flushes. The
+ // destructor releases |id| through it.
+ //
+ // - |id|: the arbiter allocates it from the shared WriterID pool. See the
+ // ownership diagram in ProducerRingBufferArbiter.
+ // - |target_buffer|: the service buffer for the packets. Each chunk header
+ // stores it.
+ // - |policy|: what the writer does when the ring buffer is full. See
+ // BufferExhaustedPolicy.
+ TraceWriterV2Impl(ProducerRingBufferArbiter* ring_buffer_arbiter,
+ WriterID id,
+ BufferID target_buffer,
+ BufferExhaustedPolicy policy);
+ ~TraceWriterV2Impl() override;
+
+ TraceWriterV2Impl(const TraceWriterV2Impl&) = delete;
+ TraceWriterV2Impl& operator=(const TraceWriterV2Impl&) = delete;
+ TraceWriterV2Impl(TraceWriterV2Impl&&) = delete;
+ TraceWriterV2Impl& operator=(TraceWriterV2Impl&&) = delete;
+
+ // TraceWriter:
+ TracePacketHandle NewTracePacket() override;
+ void FinishTracePacket() override;
+ // Unlike v1, |callback| does not wait for a service ack. See
+ // ProducerRingBufferArbiter::Flush().
+ void Flush(std::function<void()> callback = {}) override;
+ WriterID writer_id() const override {
+ return ring_buffer_writer_.writer_id();
}
- return std::nullopt;
-}
+ uint64_t written() const override { return stream_writer_.written(); }
+ uint64_t drop_count() const override { return drop_count_; }
-std::optional<StringFilter::SemanticTypeMask> ConvertSemanticTypeMask(
- const StringFilterRule& rule) {
- // UNSPECIFIED (0) is treated as its own category - it only matches rules
- // that explicitly include bit 0 in their mask. If no semantic types are
- // specified, default to matching only UNSPECIFIED (bit 0).
- if (rule.semantic_type().empty()) {
- return StringFilter::SemanticTypeMask::Unspecified();
- }
- StringFilter::SemanticTypeMask mask;
- for (const auto& type : rule.semantic_type()) {
- auto semantic_type = static_cast<uint32_t>(type);
- if (semantic_type >= StringFilter::SemanticTypeMask::kLimit) {
- return std::nullopt;
- }
- mask.Set(semantic_type);
- }
- return mask;
+ private:
+ friend class test::TraceWriterV2ImplTestPeer;
+
+ using ClockFunction = base::TimeMillis (*)();
+
+ // protozero::MessageFinalizationListener:
+ void OnMessageFinalized(protozero::Message*) override;
+
+ // protozero::ScatteredStreamWriter::Delegate:
+ protozero::ContiguousMemoryRange GetNewBuffer() override;
+ uint8_t* AnnotatePatch(uint8_t*) override;
+
+ // Checks that no packet is open, before a new packet or a flush.
+ // - A caller can call Message::Finalize() directly, without the handle.
+ // The message is then closed, but its last fragment stays unpublished.
+ // This publishes it.
+ // - Raw stream callers skip finalization. They must call
+ // FinishTracePacket() first, or the CHECK fails.
+ void EnsurePacketClosed();
+
+ // Obtains storage for the next fragment of the current packet: a new
+ // fragment in the ring buffer, or the drop buffer. NewTracePacket() calls it
+ // for the first fragment, GetNewBuffer() for each continuation.
+ // - On success, returns the fragment's range and ends drop mode.
+ // - If no chunk is free, applies the policy through TryStallForSpace(). If
+ // the policy drops the packet, enters drop mode and returns the drop
+ // buffer.
+ protozero::ContiguousMemoryRange BeginPacketFragment(
+ bool continues_from_prev);
+
+ // Publishes the open fragment, if any.
+ // - |continues_on_next| sets kFlagContinuesOnNextChunk.
+ // - After the publication, asks for a drain at the threshold.
+ // - If a relocation needs a new chunk, applies the policy through
+ // TryStallForSpace(), with one stall deadline for each replacement
+ // acquisition.
+ // - If the policy drops the fragment, enters drop mode for the rest of the
+ // packet.
+ // - Returns with no relocation pending in |ring_buffer_writer_|.
+ void EndPacketFragment(bool continues_on_next);
+
+ // Decides what to do after |ring_buffer_writer_| found no free chunk: wait
+ // for the reader, or drop the data.
+ //
+ // Returns true after a wait. The caller then tries again to get a chunk.
+ // Returns false, without a wait, if the writer must drop the data:
+ // - The policy is kDrop.
+ // - The policy is kStallThenDrop, and an earlier loss is still unreported.
+ // - No reader is attached, so nothing frees space.
+ // - The stall deadline passed. Under kStall, this aborts instead.
+ //
+ // |claim_failed|: the failed call returned kClaimFailed. Its reserved
+ // positions stay unused until the reader moves past them. So a drop also
+ // asks for a drain.
+ //
+ // |stall_deadline|: the deadline of the current chunk acquisition. Pass an
+ // unset value on the first call for an acquisition, and the same value on
+ // each retry. The first wait sets it.
+ bool TryStallForSpace(bool claim_failed,
+ std::optional<base::TimeMillis>* stall_deadline);
+
+ // Drops the rest of the open packet: its bytes go to GetDropBuffer() from now
+ // on.
+ // - If drop mode is not active yet, counts one drop and records the loss
+ // for the next publication.
+ // - Drop mode lasts until a later packet gets a fragment in the ring buffer.
+ void EnterDropMode();
+
+ // Returns the process-wide drop buffer as a writable range. Only in drop
+ // mode.
+ protozero::ContiguousMemoryRange GetDropBuffer();
+
+ // Receives drain requests, Flush() and OnWriterDestroyed(). See the
+ // constructor.
+ ProducerRingBufferArbiter* const ring_buffer_arbiter_;
+
+ // Claims chunks and publishes fragments in the ring buffer.
+ SharedRingBufferWriter ring_buffer_writer_;
+
+ // What this writer does when the ring buffer has no free chunk.
+ const BufferExhaustedPolicy buffer_exhausted_policy_;
+
+ // Time source for stall deadlines. Tests replace it to advance time
+ // deterministically across acquisition attempts.
+ ClockFunction get_time_ms_ = &base::GetWallTimeMs;
+
+ // PID of the process that created this writer. A DCHECK uses it to detect
+ // a process fork during tracing, which this writer does not support.
+ const base::PlatformProcessId process_id_;
+
+ // Protozero writes packet bytes through this. It points into the open
+ // fragment, or into the drop buffer in drop mode.
+ protozero::ScatteredStreamWriter stream_writer_;
+
+ // A pointer, so this header does not need the generated TracePacket header.
+ // NewTracePacket() resets and reuses the same root message for every packet.
+ //
+ // TODO(sashwinbalaji): Consider std::optional<RootMessage<TracePacket>>.
+ // - It saves one heap allocation per writer, but needs the generated
+ // TracePacket header here.
+ // - It waits because TraceWriterImpl makes the same choice. One decision
+ // must cover both writers.
+ // - Revisit if a profile shows this allocation at writer creation.
+ std::unique_ptr<protozero::RootMessage<protos::pbzero::TracePacket>>
+ cur_packet_;
+
+ // Start of the open fragment in shared memory.
+ // Null after the fragment closes, and in drop mode.
+ uint8_t* fragment_begin_ = nullptr;
+
+ // True from NewTracePacket() until FinishTracePacket().
+ bool packet_open_ = false;
+
+ // True while writes go to the drop buffer. Stays true until a later
+ // NewTracePacket() gets a fragment in the ring buffer.
+ bool in_drop_mode_ = false;
+
+ // Sets first_packet_on_sequence on the first packet of this writer.
+ bool first_packet_on_sequence_ = true;
+
+ // Number of times this writer entered drop mode. Consecutive dropped
+ // packets count once, as in TraceWriterImpl.
+ uint64_t drop_count_ = 0;
+};
+
+} // namespace perfetto::tracing_v2
+
+#endif // SRC_TRACING_V2_TRACE_WRITER_V2_IMPL_H_
+/*
+ * Copyright (C) 2026 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.
+ */
+
+// gen_amalgamated expanded: #include "src/tracing/v2/producer_ring_buffer_arbiter.h"
+
+#include <algorithm>
+#include <utility>
+
+// gen_amalgamated expanded: #include "perfetto/base/logging.h"
+// gen_amalgamated expanded: #include "perfetto/base/task_runner.h"
+// gen_amalgamated expanded: #include "perfetto/ext/base/status_macros.h"
+// gen_amalgamated expanded: #include "perfetto/ext/base/uuid.h"
+// gen_amalgamated expanded: #include "perfetto/ext/tracing/core/shared_memory.h"
+// gen_amalgamated expanded: #include "perfetto/ext/tracing/core/shared_memory_arbiter.h"
+// gen_amalgamated expanded: #include "perfetto/ext/tracing/core/trace_writer.h"
+// gen_amalgamated expanded: #include "perfetto/ext/tracing/core/tracing_service.h"
+// gen_amalgamated expanded: #include "perfetto/tracing/core/data_source_config.h"
+// gen_amalgamated expanded: #include "src/tracing/core/null_trace_writer.h"
+// gen_amalgamated expanded: #include "src/tracing/v2/shared_ring_buffer_abi.h"
+// gen_amalgamated expanded: #include "src/tracing/v2/trace_writer_v2_impl.h"
+
+namespace perfetto::tracing_v2 {
+namespace {
+
+// Chooses a chunk size by weight, defaulting to kMinChunkSize.
+uint32_t ChooseChunkSize(const DataSourceConfig& config) {
+ using ChunkSizeOption =
+ DataSourceConfig::ExperimentalTracingV2Config::ChunkSizeOption;
+
+ const auto& options = config.experimental_tracing_v2().chunk_size_options();
+ auto weight_of = [](const ChunkSizeOption& option) -> uint64_t {
+ if (!IsValidChunkSize(option.size_bytes()))
+ return 0;
+ return option.has_weight() ? option.weight() : 1;
+ };
+
+ uint64_t total_weight = 0;
+ for (const ChunkSizeOption& option : options)
+ total_weight += weight_of(option);
+
+ if (total_weight == 0)
+ return kMinChunkSize;
+
+ // Walk the options until their cumulative weight passes |target|.
+ const uint64_t target =
+ static_cast<uint64_t>(base::Uuidv4().lsb()) % total_weight;
+ uint64_t cumulative_weight = 0;
+ for (const ChunkSizeOption& option : options) {
+ cumulative_weight += weight_of(option);
+ if (target < cumulative_weight)
+ return option.size_bytes();
+ }
+
+ // Not reached: the last cumulative weight is the total, which is above
+ // |target|, so the loop returns.
+ PERFETTO_DFATAL("ChooseChunkSize: no option for the target");
+ return kMinChunkSize;
+}
+
+// Returns the drain threshold, in positions, for a ring buffer of
+// |num_chunks| chunks.
+// |drain_occupancy_percent| must be -1 to 100, as validated by the service:
+// - -1: 1, so a writer asks for a drain after every publication.
+// - 0: |kDefaultDrainOccupancyPercent|% of |num_chunks|.
+// - 1 to 100: that percent of |num_chunks|.
+// The result is at least 1.
+uint32_t ComputeDrainOccupancyThreshold(uint32_t num_chunks,
+ int32_t drain_occupancy_percent) {
+ constexpr uint32_t kDefaultDrainOccupancyPercent = 25;
+
+ PERFETTO_DCHECK(drain_occupancy_percent >= -1 &&
+ drain_occupancy_percent <= 100);
+ if (drain_occupancy_percent == -1)
+ return 1;
+ const uint32_t percent = drain_occupancy_percent == 0
+ ? kDefaultDrainOccupancyPercent
+ : static_cast<uint32_t>(drain_occupancy_percent);
+ const uint64_t threshold = uint64_t{num_chunks} * percent / 100;
+ return std::max(1u, static_cast<uint32_t>(threshold));
}
} // namespace
-perfetto::base::Status LoadMessageFilterConfig(const TraceFilter& filt,
- MessageFilter* filter) {
- StringFilter& string_filter = filter->string_filter();
+// static
+base::StatusOr<std::unique_ptr<ProducerRingBufferArbiter>>
+ProducerRingBufferArbiter::Create(
+ base::TaskRunner* task_runner,
+ ProducerEndpoint* endpoint,
+ const DataSourceConfig& config,
+ size_t shmem_size_hint_bytes,
+ AllocateSharedMemoryFn allocate_shared_memory) {
+ const uint32_t chunk_size_bytes = ChooseChunkSize(config);
- auto add_rule = [&](const auto& rule) -> perfetto::base::Status {
- auto policy = ConvertPolicy(rule.policy());
- if (!policy.has_value()) {
- return perfetto::base::ErrStatus(
- "Trace filter has invalid string filtering rules");
- }
- auto semantic_type = ConvertSemanticTypeMask(rule);
- if (!semantic_type.has_value()) {
- return perfetto::base::ErrStatus(
- "Trace filter has invalid semantic types in string filtering rules");
- }
- string_filter.AddRule(*policy, rule.regex_pattern(),
- rule.atrace_payload_starts_with(), rule.name(),
- *semantic_type);
- return perfetto::base::OkStatus();
- };
+ ASSIGN_OR_RETURN(const size_t shmem_size_bytes,
+ RingBufferSizeForShmSizeHint(shmem_size_hint_bytes,
+ TracingService::kMaxShmSize,
+ chunk_size_bytes));
- // Load base string filter chain.
- for (const auto& rule : filt.string_filter_chain().rules()) {
- auto status = add_rule(rule);
- if (!status.ok())
- return status;
- }
+ ASSIGN_OR_RETURN(std::shared_ptr<SharedMemory> memory,
+ allocate_shared_memory(shmem_size_bytes));
- // Load v54 string filter chain. Rules with matching names will replace
- // existing rules; others will be appended.
- for (const auto& rule : filt.string_filter_chain_v54().rules()) {
- auto status = add_rule(rule);
- if (!status.ok())
- return status;
+ const uint32_t num_chunks = static_cast<uint32_t>(
+ (shmem_size_bytes - sizeof(RingBufferHeader)) / chunk_size_bytes);
+ const uint32_t drain_occupancy_threshold = ComputeDrainOccupancyThreshold(
+ num_chunks, config.experimental_tracing_v2().drain_occupancy_percent());
+
+ return std::unique_ptr<ProducerRingBufferArbiter>(
+ new ProducerRingBufferArbiter(task_runner, endpoint, std::move(memory),
+ chunk_size_bytes,
+ drain_occupancy_threshold));
+}
+
+ProducerRingBufferArbiter::ProducerRingBufferArbiter(
+ base::TaskRunner* task_runner,
+ ProducerEndpoint* endpoint,
+ std::shared_ptr<SharedMemory> memory,
+ uint32_t chunk_size,
+ uint32_t drain_occupancy_threshold)
+ : task_runner_(task_runner),
+ endpoint_(endpoint),
+ shared_memory_arbiter_(endpoint->MaybeSharedMemoryArbiter()),
+ memory_(std::move(memory)),
+ ring_buffer_(static_cast<uint8_t*>(memory_->start()),
+ memory_->size(),
+ chunk_size),
+ drain_occupancy_threshold_(drain_occupancy_threshold) {
+ PERFETTO_CHECK(shared_memory_arbiter_);
+}
+
+ProducerRingBufferArbiter::~ProducerRingBufferArbiter() {
+ Disconnect();
+}
+
+void ProducerRingBufferArbiter::OnReaderAttachReply(bool reader_attached) {
+ PERFETTO_DCHECK_THREAD(thread_checker_);
+ // The attach reply can arrive after Disconnect().
+ if (reader_state_.load() == ReaderState::kDetached)
+ return;
+ if (!reader_attached) {
+ PERFETTO_ELOG("tracing v2: ring buffer attachment failed");
+ Disconnect();
+ return;
}
+ SetReaderState(ReaderState::kAttached);
+}
- const std::string& bytecode_v1 = filt.bytecode();
- const std::string& bytecode_v2 = filt.bytecode_v2();
- const std::string& bytecode = bytecode_v2.empty() ? bytecode_v1 : bytecode_v2;
- const std::string& overlay = filt.bytecode_overlay_v54();
- if (!filter->LoadFilterBytecode(bytecode.data(), bytecode.size(),
- overlay.empty() ? nullptr : overlay.data(),
- overlay.size())) {
- return perfetto::base::ErrStatus("Trace filter bytecode invalid");
+bool ProducerRingBufferArbiter::IsReaderAttached() const {
+ return reader_state_.load() == ReaderState::kAttached;
+}
+
+void ProducerRingBufferArbiter::Disconnect() {
+ PERFETTO_DCHECK_THREAD(thread_checker_);
+ SetReaderState(ReaderState::kDetached);
+}
+
+void ProducerRingBufferArbiter::SetReaderState(ReaderState next) {
+ PERFETTO_DCHECK_THREAD(thread_checker_);
+ const ReaderState current = reader_state_.load();
+ PERFETTO_CHECK(
+ next == ReaderState::kDetached ||
+ (current == ReaderState::kPending && next == ReaderState::kAttached));
+ reader_state_.store(next);
+}
+
+std::unique_ptr<TraceWriter> ProducerRingBufferArbiter::CreateTraceWriter(
+ BufferID target_buffer,
+ BufferExhaustedPolicy policy) {
+ if (PERFETTO_UNLIKELY(reader_state_.load() == ReaderState::kDetached))
+ return std::make_unique<NullTraceWriter>();
+
+ const WriterID writer_id =
+ shared_memory_arbiter_->AllocateTracingV2WriterID();
+ if (PERFETTO_UNLIKELY(!writer_id))
+ return std::make_unique<NullTraceWriter>();
+
+ return std::make_unique<TraceWriterV2Impl>(this, writer_id, target_buffer,
+ policy);
+}
+
+void ProducerRingBufferArbiter::OnWriterDestroyed(WriterID id) {
+ // TODO(sashwinbalaji): Make WriterID reuse safe between v2 and v1 writers.
+ // The problem:
+ // - The SMB arbiter can give this ID to a v1 writer at once.
+ // - The last ring buffer chunk of this writer can still wait for a drain.
+ // - TraceBufferV2 accepts one input format for each (producer, writer)
+ // sequence. While it keeps the sequence, it rejects chunks of the other
+ // format as ABI violations. So one of the two writers loses data.
+
+ // After this release, the endpoint can destroy this object. Do not access
+ // members after it.
+ shared_memory_arbiter_->ReleaseTracingV2WriterID(id);
+}
+
+void ProducerRingBufferArbiter::RequestDrain(DrainUrgency urgency) {
+ // See DrainUrgency::kUrgent.
+ if (urgency == DrainUrgency::kUrgent &&
+ task_runner_->RunsTasksOnCurrentThread()) {
+ endpoint_->DrainV2RingBuffer();
+ return;
}
+ PostDrainTask(/*force=*/false);
+}
- return perfetto::base::OkStatus();
+void ProducerRingBufferArbiter::Flush(std::function<void()> callback) {
+ // Set force=true to queue our own drain task before the callback. The
+ // endpoint thread then sends the drain request before it runs the callback.
+ //
+ // A shared drain task would leave a race:
+ // 1. Another writer sets the flag, then pauses before PostTask().
+ // 2. Flush() sees the flag and queues only its callback.
+ // 3. The callback runs before the other writer queues the drain task.
+ PostDrainTask(/*force=*/true);
+
+ if (callback)
+ task_runner_->PostTask(std::move(callback));
}
-} // namespace protozero
-// gen_amalgamated begin source: src/tracing/service/zlib_compressor.cc
-// gen_amalgamated begin header: src/tracing/service/zlib_compressor.h
+void ProducerRingBufferArbiter::PostDrainTask(bool force) {
+ // When |force| is false, requests share a pending drain task. The writer
+ // sets |drain_task_pending_| after it changes the ring buffer, so that task
+ // covers the change. The atomic operations below act on
+ // |drain_task_pending_|:
+ //
+ // writer thread endpoint thread (the pending task)
+ // ------------- ----------------------------------
+ // W1. publish a chunk, or E1. exchange(0)
+ // leave a failed claim E2. send DrainV2RingBuffer
+ // W2. fetch_or(1)
+ // - was set: post nothing
+ // - was clear: post a task
+ //
+ // If W2 finds |drain_task_pending_| already set, a drain is still due after
+ // W1. That request covers this change too, so this writer needs no extra
+ // task. E1 must be a read-modify-write for this:
+ // - Only W2 and E1 write the flag, and both are read-modify-writes.
+ // - If W2 reads 1, an earlier W2 posted the pending task. In the
+ // modification order of the flag, no E1 comes between those two W2s.
+ // - So the next E1 comes after this W2. It reads the value of this W2 or
+ // of a later W2.
+ // - So this W2 synchronizes with that E1, and W1 happens before the E2
+ // after it.
+ //
+ // Flush() sets |force|. See Flush() for why it cannot share a pending task.
+ if (!force && drain_task_pending_.fetch_or(1))
+ return;
+
+ task_runner_->PostTask([weak_this = weak_factory_.GetWeakPtr()] {
+ if (!weak_this)
+ return;
+ PERFETTO_DCHECK_THREAD(weak_this->thread_checker_);
+ // E1, then E2. Clearing the flag first lets a later request post another
+ // task. E1 must be a read-modify-write: see above.
+ weak_this->drain_task_pending_.exchange(0);
+ weak_this->endpoint_->DrainV2RingBuffer();
+ });
+}
+
+} // namespace perfetto::tracing_v2
+// gen_amalgamated begin source: src/tracing/v2/shared_ring_buffer.cc
/*
- * Copyright (C) 2023 The Android Open Source Project
+ * Copyright (C) 2026 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.
@@ -59517,25 +66001,411 @@ perfetto::base::Status LoadMessageFilterConfig(const TraceFilter& filt,
* limitations under the License.
*/
-#ifndef SRC_TRACING_SERVICE_ZLIB_COMPRESSOR_H_
-#define SRC_TRACING_SERVICE_ZLIB_COMPRESSOR_H_
+// gen_amalgamated expanded: #include "src/tracing/v2/shared_ring_buffer.h"
-#include <vector>
+#include <limits.h>
+#include <stdint.h>
-// gen_amalgamated expanded: #include "perfetto/base/build_config.h"
-// gen_amalgamated expanded: #include "perfetto/ext/tracing/core/trace_packet.h"
+#include <atomic>
-namespace perfetto {
+// gen_amalgamated expanded: #include "perfetto/base/compiler.h"
+// gen_amalgamated expanded: #include "perfetto/base/logging.h"
+// gen_amalgamated expanded: #include "perfetto/ext/base/futex.h"
+// gen_amalgamated expanded: #include "perfetto/ext/base/utils.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/proto_utils.h"
+// gen_amalgamated expanded: #include "src/tracing/v2/shared_ring_buffer_abi.h"
-#if PERFETTO_BUILDFLAG(PERFETTO_ZLIB)
-void ZlibCompressFn(std::vector<TracePacket>*);
-#endif
+namespace perfetto::tracing_v2 {
+namespace {
+
+static_assert(kMaxFragmentSizeVarIntBytes ==
+ protozero::proto_utils::kMessageLengthFieldSize,
+ "Ring buffer fragment sizes must use the same varint byte limit "
+ "as Protozero message lengths");
+
+// The buffer stores read_pos in the low 32 bits of rw_positions. Pass its
+// address to the futex API, but keep all C++ accesses on the containing
+// atomic<uint64_t>.
+//
+// The supported CPU/ABI set provides atomic observation of that 32-bit half
+// during the 64-bit CAS.
+const uint32_t* ReadPosFutexAddress(const std::atomic<uint64_t>* rw_positions) {
+ static_assert(PERFETTO_IS_LITTLE_ENDIAN(),
+ "The low-word futex requires read_pos to be the first four "
+ "bytes of rw_positions");
+ return reinterpret_cast<const uint32_t*>(rw_positions);
+}
+
+// Callers validate untrusted layouts with NumChunksForRingBufferLayout()
+// first. An invalid layout here is a bug.
+uint32_t CheckedNumChunks(const void* start, size_t size, uint32_t chunk_size) {
+ base::StatusOr<uint32_t> num_chunks =
+ NumChunksForRingBufferLayout(start, size, chunk_size);
+ if (!num_chunks.ok())
+ PERFETTO_FATAL("tracing v2: %s", num_chunks.status().c_message());
+ return *num_chunks;
+}
+
+} // namespace
+
+// --- Construction. ---
+
+SharedRingBuffer::SharedRingBuffer(uint8_t* start,
+ size_t size,
+ uint32_t chunk_size)
+ : start_(start),
+ num_chunks_(CheckedNumChunks(start, size, chunk_size)),
+ chunk_size_(chunk_size) {}
+
+// --- Writer-side reservation. ---
+
+SharedRingBuffer::Reservation SharedRingBuffer::TryReserveWritePos() {
+ // The reader marks chunks Free before publishing read_pos.
+ // A writer that sees the new read_pos also sees those Free state words.
+ return TryReserveWritePosFromSnapshot(
+ header()->rw_positions.load(std::memory_order_acquire));
+}
+
+SharedRingBuffer::Reservation SharedRingBuffer::TryReserveWritePosFromSnapshot(
+ uint64_t rw_positions) {
+ RingBufferHeader* ring_header = header();
+ Reservation reservation{};
+ for (;;) {
+ const uint32_t write_pos = WritePosOf(rw_positions);
+ const uint32_t read_pos = ReadPosOf(rw_positions);
+ reservation.read_pos_for_wait = read_pos;
+
+ if (NumOutstandingPositions(write_pos, read_pos) >= num_chunks_) {
+ reservation.result = ReserveResult::kFull;
+ return reservation;
+ }
+
+ // (write_pos, read_pos) -> (write_pos + 1, read_pos).
+ //
+ // On failure, no position is reserved. The CAS stores the current write_pos
+ // and read_pos in the local rw_positions value. The loop rechecks capacity
+ // before another attempt. A competing update can come from:
+ // - Another writer that advances write_pos.
+ // - The reader that publishes read_pos.
+ //
+ // compare_exchange_weak can also fail spuriously.
+ //
+ // Proposed memory ordering:
+ // - Success: acquire to observe the Free words published with read_pos.
+ // - Failure: acquire for the same reason. The refreshed read_pos feeds
+ // the next capacity check.
+ if (ring_header->rw_positions.compare_exchange_weak(
+ rw_positions, PackRwPositions(write_pos + 1, read_pos))) {
+ reservation.result = ReserveResult::kReserved;
+ reservation.chunk_pos = write_pos;
+ return reservation;
+ }
+ }
+}
+
+// --- Writer-side chunk transitions. ---
+
+bool SharedRingBuffer::TryAcquireChunkForWriting(uint32_t chunk_pos,
+ uint32_t being_written_word) {
+ PERFETTO_DCHECK(ChunkStateOf(being_written_word) ==
+ ChunkState::kBeingWritten);
+ PERFETTO_DCHECK(NumFragmentsOf(being_written_word) == 0);
+
+ // Free(wrap_count(chunk_pos)) -> BeingWritten(0).
+ //
+ // On failure, the chunk does not match this reservation's Free word:
+ // - The reader advanced the wrap count before this writer claimed the chunk.
+ // - A writer from an earlier reservation still owns the physical chunk, or
+ // the reader has not reclaimed its RewriteAcknowledged state yet.
+ //
+ // The caller must reserve a new position. A retry against the returned word
+ // can claim a consumed position or overwrite another writer's chunk.
+ //
+ // Proposed memory ordering:
+ // - Success: acquire to observe the reader's release of Free.
+ // The reader must finish copying before this writer overwrites the chunk.
+ // - Failure: relaxed because the returned word is ignored.
+ uint32_t expected = MakeFreeStateWordForPosition(chunk_pos, num_chunks_);
+ std::atomic<uint32_t>* state_word = chunk_state_word_for_position(chunk_pos);
+ return state_word->compare_exchange_strong(expected, being_written_word);
+}
+
+bool SharedRingBuffer::TryReleaseChunkAsComplete(ChunkIndex chunk_idx,
+ uint32_t complete_word,
+ uint32_t* expected) {
+ PERFETTO_DCHECK(ChunkStateOf(*expected) == ChunkState::kBeingWritten);
+ PERFETTO_DCHECK(ChunkStateOf(complete_word) == ChunkState::kComplete);
+
+ // BeingWritten(N) -> Complete(M).
+ //
+ // On failure, the reader requested a rewrite first. |*expected| receives
+ // RewriteRequested(N), and the caller relocates any unpublished fragment.
+ //
+ // Proposed memory ordering:
+ // - Success: release to publish M fragments and their sizes.
+ // The first publication also makes BufferID visible.
+ // - Failure: acquire to observe the reader's RewriteRequested(N).
+ // The reader must finish copying N fragments before the writer relocates.
+ std::atomic<uint32_t>* state_word = chunk_state_word_at(chunk_idx);
+ return state_word->compare_exchange_strong(*expected, complete_word);
+}
+
+bool SharedRingBuffer::TryReacquireChunkForWriting(ChunkIndex chunk_idx,
+ uint32_t observed) {
+ PERFETTO_DCHECK(ChunkStateOf(observed) == ChunkState::kComplete);
+
+ // Complete(N) -> BeingWritten(N).
+ //
+ // On failure, the reader reclaimed the chunk first. The writer discards its
+ // cached handle and acquires another chunk.
+ //
+ // Proposed memory ordering:
+ // - Success: relaxed because reuse publishes no new bytes.
+ // The read-modify-write extends Complete(N)'s release sequence.
+ // The reader's acquire load still sees the N published fragments.
+ // - Failure: relaxed because the returned word is ignored.
+ uint32_t expected = observed;
+ std::atomic<uint32_t>* state_word = chunk_state_word_at(chunk_idx);
+ return state_word->compare_exchange_strong(
+ expected, ReplaceChunkState(observed, ChunkState::kBeingWritten));
+}
+
+bool SharedRingBuffer::TryAcknowledgeRewrite(ChunkIndex chunk_idx,
+ uint32_t observed) {
+ PERFETTO_DCHECK(ChunkStateOf(observed) == ChunkState::kRewriteRequested);
+
+ // RewriteRequested -> RewriteAcknowledged, with all other bits zero.
+ //
+ // On failure, report a protocol error. Only this writer can change
+ // RewriteRequested, so the observed word must still match.
+ //
+ // Proposed memory ordering:
+ // - Success: release to save the unpublished fragment before
+ // acknowledgement. The reader can then reclaim the chunk.
+ // - Failure: relaxed because it only reports a protocol error.
+ uint32_t expected = observed;
+ std::atomic<uint32_t>* state_word = chunk_state_word_at(chunk_idx);
+ return state_word->compare_exchange_strong(expected,
+ kRewriteAcknowledgedStateWord);
+}
+
+// --- Reader-side chunk transitions. ---
+
+uint32_t SharedRingBuffer::LoadChunkStateWordAcquire(
+ ChunkIndex chunk_idx) const {
+ // The acquire load pairs with the writer's release publication of fragments
+ // and their sizes. The first publication also makes BufferID visible.
+ //
+ // If the writer reuses Complete(N) as BeingWritten(N), its CAS preserves the
+ // fragment count and extends the release sequence. This load still makes
+ // those N fragments, their sizes and BufferID visible when N is nonzero.
+ return chunk_state_word_at(chunk_idx)->load(std::memory_order_acquire);
+}
+
+uint32_t SharedRingBuffer::LoadWritePosRelaxed() const {
+ // This bounds the reader's pass. It does not show whether each reservation
+ // has published data. LoadChunkStateWordAcquire() provides that information.
+ return WritePosOf(header()->rw_positions.load(std::memory_order_relaxed));
+}
+
+uint32_t SharedRingBuffer::LoadNumOutstandingPositionsRelaxed() const {
+ const uint64_t rw_positions =
+ header()->rw_positions.load(std::memory_order_relaxed);
+ return NumOutstandingPositions(WritePosOf(rw_positions),
+ ReadPosOf(rw_positions));
+}
+
+bool SharedRingBuffer::TryRequestRewrite(ChunkIndex chunk_idx,
+ uint32_t* expected) {
+ PERFETTO_DCHECK(ChunkStateOf(*expected) == ChunkState::kBeingWritten);
+
+ // BeingWritten(N) -> RewriteRequested(N).
+ // |*expected| is the word the reader used to copy the N fragments.
+ //
+ // On failure, the writer published first. The reader discards its copy and
+ // retries this position immediately in Drain() to include the new fragments.
+ //
+ // Proposed memory ordering:
+ // - Success: release to finish that copy before the writer observes
+ // RewriteRequested and relocates its unpublished fragment.
+ // - Failure: relaxed because the copy is discarded. The next attempt
+ // acquire-loads the state word again before reading any payload.
+ std::atomic<uint32_t>* state_word = chunk_state_word_at(chunk_idx);
+ return state_word->compare_exchange_strong(
+ *expected, ReplaceChunkState(*expected, ChunkState::kRewriteRequested));
+}
+
+bool SharedRingBuffer::TryMoveFreeChunkToNextWrap(uint32_t chunk_pos,
+ uint32_t* expected) {
+ PERFETTO_DCHECK(ChunkStateOf(*expected) == ChunkState::kFree);
+
+ // Free(wrap_count(chunk_pos)) -> Free(next wrap).
+ //
+ // On failure, the delayed writer claimed the chunk first. The reader retries
+ // this position immediately in Drain() to consume BeingWritten or Complete.
+ //
+ // Proposed memory ordering:
+ // - Success: release to publish the next Free wrap to a claiming writer.
+ // - Failure: relaxed because the next attempt acquire-loads the state
+ // word again before reading any payload.
+ std::atomic<uint32_t>* state_word = chunk_state_word_for_position(chunk_pos);
+ return state_word->compare_exchange_strong(
+ *expected, MakeFreeWordForNextWrap(chunk_pos));
+}
+
+bool SharedRingBuffer::TryReleaseCompleteChunkAsFree(uint32_t chunk_pos,
+ uint32_t* expected) {
+ PERFETTO_DCHECK(ChunkStateOf(*expected) == ChunkState::kComplete);
+
+ // Complete(N) -> Free(next wrap).
+ // |*expected| is the word the reader used to copy the N fragments.
+ //
+ // On failure, the writer reused the chunk first. It can also publish more
+ // fragments before the reader retries, so the N-fragment copy can be stale.
+ // Drain() reloads the state and copies the current published fragments.
+ // If the state is BeingWritten, the reader then requests a rewrite.
+ // Otherwise, it tries to release Complete again. The reader delivers the
+ // copy only after a successful transition, so retries cannot duplicate data.
+ //
+ // Proposed memory ordering:
+ // - Success: release to finish the copy before another writer acquires
+ // Free and overwrites the chunk.
+ // - Failure: relaxed because the copy is discarded. The next attempt
+ // acquire-loads the state word again before reading any payload.
+ std::atomic<uint32_t>* state_word = chunk_state_word_for_position(chunk_pos);
+ return state_word->compare_exchange_strong(
+ *expected, MakeFreeWordForNextWrap(chunk_pos));
+}
+
+bool SharedRingBuffer::TryReleaseRewriteAcknowledgedChunkAsFree(
+ uint32_t chunk_pos,
+ uint32_t* observed) {
+ // RewriteAcknowledged -> Free(next wrap).
+ // The expected word contains only the RewriteAcknowledged state bits.
+ //
+ // On failure, |*observed| receives the unexpected word. This is a protocol
+ // error because only this reader can change an acknowledged chunk.
+ //
+ // Proposed memory ordering:
+ // - Success: acq_rel for two handoffs:
+ // - Acquire observes the writer's acknowledgement after it saves its
+ // unpublished fragment.
+ // - Release passes the chunk to the next writer after that copy.
+ // - Failure: relaxed because the returned word only diagnoses the
+ // protocol error.
+ uint32_t expected = kRewriteAcknowledgedStateWord;
+ std::atomic<uint32_t>* state_word = chunk_state_word_for_position(chunk_pos);
+ const bool reclaimed = state_word->compare_exchange_strong(
+ expected, MakeFreeWordForNextWrap(chunk_pos));
+ if (PERFETTO_UNLIKELY(!reclaimed))
+ *observed = expected;
+ return reclaimed;
+}
+
+// --- Backpressure. ---
+
+SharedRingBuffer::WriterWaitResult SharedRingBuffer::WaitForReadPosChange(
+ uint32_t read_pos_for_wait,
+ uint32_t timeout_ms) {
+ PERFETTO_DCHECK(timeout_ms > 0);
+ if (!SupportsWriterWait())
+ return WriterWaitResult::kUnavailable;
+
+ RingBufferHeader* ring_header = header();
+
+ // To avoid a missed wake:
+ // - the writer counts itself as waiting before checking read_pos.
+ // - the reader publishes read_pos before checking the waiter count.
+ //
+ // The fences order each update before the other side's check. Together
+ // they prevent both checks from seeing an older value:
+ //
+ // writer reader
+ // ------ ------
+ // num_writers_waiting += 1 publish read_pos
+ // seq_cst fence seq_cst fence
+ // load read_pos load num_writers_waiting
+ // FutexWait if unchanged FutexWake if nonzero
+ //
+ // - Writer's fence first: the reader sees the waiter and wakes it.
+ // - Reader's fence first: the writer sees the new read_pos.
+ // It does not sleep.
+ //
+ // num_writers_waiting is only a wake hint, so its accesses use relaxed order.
+ ring_header->num_writers_waiting.fetch_add(1, std::memory_order_relaxed);
+ std::atomic_thread_fence(std::memory_order_seq_cst);
+
+ WriterWaitResult result = WriterWaitResult::kRetry;
+ const uint32_t read_pos =
+ ReadPosOf(ring_header->rw_positions.load(std::memory_order_relaxed));
+ if (read_pos == read_pos_for_wait) {
+ // FutexWait checks the value again before sleeping. If read_pos changed
+ // after the load above, the call returns kValueMismatch and no wake is
+ // lost.
+ //
+ // Every result other than kError means "recheck capacity".
+ const base::FutexWaitResult wait_result =
+ base::FutexWait(ReadPosFutexAddress(&ring_header->rw_positions),
+ read_pos_for_wait, timeout_ms);
+ result = wait_result == base::FutexWaitResult::kError
+ ? WriterWaitResult::kUnavailable
+ : WriterWaitResult::kRetry;
+ }
+
+ ring_header->num_writers_waiting.fetch_sub(1, std::memory_order_relaxed);
+ return result;
+}
+
+void SharedRingBuffer::PublishReadPos(uint32_t read_pos) {
+ // This load only supplies the initial expected value for the CAS below.
+ PublishReadPosFromSnapshot(
+ header()->rw_positions.load(std::memory_order_relaxed), read_pos);
+}
+
+void SharedRingBuffer::PublishReadPosFromSnapshot(uint64_t rw_positions,
+ uint32_t read_pos) {
+ RingBufferHeader* ring_header = header();
+
+ // (write_pos, old read_pos) -> (write_pos, read_pos).
+ //
+ // On failure, the CAS stores the current positions in the local rw_positions.
+ // A writer can advance write_pos first, or compare_exchange_weak can fail
+ // spuriously. The loop preserves that write_pos and retries the read_pos
+ // update.
+ //
+ // Proposed memory ordering:
+ // - Success: release so writers that acquire the new read_pos also see
+ // this pass's Free words.
+ // - Failure: relaxed because the returned word only supplies the next
+ // CAS attempt. No payload access depends on it.
+ while (!ring_header->rw_positions.compare_exchange_weak(
+ rw_positions, ReplaceReadPos(rw_positions, read_pos))) {
+ }
+
+ if (!SupportsWriterWait())
+ return;
+
+ // See the missed-wake schedule in WaitForReadPosChange(). The fence
+ // orders read_pos publication before the waiter-count load.
+ std::atomic_thread_fence(std::memory_order_seq_cst);
+
+ if (ring_header->num_writers_waiting.load(std::memory_order_relaxed) == 0)
+ return;
-} // namespace perfetto
+ // Wake everyone because one drain pass can free many chunks. Waking one
+ // writer could leave capacity unused.
+ //
+ // This runs once per pass rather than once per reclaimed chunk.
+ //
+ // Waits are bounded, so a failed wake delays writers but cannot strand them.
+ base::FutexWake(ReadPosFutexAddress(&ring_header->rw_positions), INT_MAX);
+}
-#endif // SRC_TRACING_SERVICE_ZLIB_COMPRESSOR_H_
+} // namespace perfetto::tracing_v2
+// gen_amalgamated begin source: src/tracing/v2/shared_ring_buffer_reader.cc
+// gen_amalgamated begin header: src/tracing/v2/shared_ring_buffer_reader.h
/*
- * Copyright (C) 2023 The Android Open Source Project
+ * Copyright (C) 2026 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.
@@ -59550,149 +66420,593 @@ void ZlibCompressFn(std::vector<TracePacket>*);
* limitations under the License.
*/
-// gen_amalgamated expanded: #include "src/tracing/service/zlib_compressor.h"
+#ifndef SRC_TRACING_V2_SHARED_RING_BUFFER_READER_H_
+#define SRC_TRACING_V2_SHARED_RING_BUFFER_READER_H_
-// gen_amalgamated expanded: #include "perfetto/base/build_config.h"
+#include <stdint.h>
-// File compiles to nothing when the buildflag is off (e.g. SDK opt-out).
-#if PERFETTO_BUILDFLAG(PERFETTO_ZLIB)
+#include <functional>
+#include <vector>
-#include <zlib.h>
+// gen_amalgamated expanded: #include "perfetto/ext/tracing/core/basic_types.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/field.h"
+// gen_amalgamated expanded: #include "src/tracing/v2/shared_ring_buffer.h"
+// gen_amalgamated expanded: #include "src/tracing/v2/shared_ring_buffer_abi.h"
-// gen_amalgamated expanded: #include "protos/perfetto/trace/trace.pbzero.h"
-// gen_amalgamated expanded: #include "protos/perfetto/trace/trace_packet.pbzero.h"
-// gen_amalgamated expanded: #include "src/tracing/service/packet_compressor_common.h"
+namespace perfetto::tracing_v2 {
-namespace perfetto {
+namespace test {
+class SharedRingBufferInternalsForTest;
+}
-namespace {
+// Reads packet fragments from one SharedRingBuffer.
+//
+// - Use each instance from one execution context. The ring buffer's storage and
+// SharedRingBuffer view must outlive the reader.
+// - Reservations are consumed in order. A relocated fragment gets a later
+// reservation.
+// - The reader never waits for a writer, but may retry when it loses a
+// concurrent state transition.
+// - If a writer still owns a chunk, the reader copies its published fragments.
+// This is a partial chunk read. The writer moves its unpublished fragment to
+// a later reservation.
+// - A chunk marked kFlagDataLoss is consumed without delivering its fragments.
+// The delegate receives a loss report instead.
+// - Fragment sizes are decoded once into reader-owned values, and the payload
+// copy uses those values without rereading the shared size bytes. The
+// delegate only ever sees reader-owned scratch, never a view of
+// producer-controlled shared memory.
+class SharedRingBufferReader {
+ public:
+ // Result of consuming one position.
+ enum class ConsumeResult {
+ // No reservation at read_pos is visible yet.
+ // read_pos has caught up with the observed write_pos.
+ kNoData,
+ // A chunk was handed to the delegate and read_pos advanced.
+ kChunkRead,
+ // No payload was delivered. read_pos advanced and data can no longer be
+ // published for this position.
+ kPositionSkipped,
+ // A writer changed the chunk before the reader's CAS:
+ // - Claimed Free before the reader advanced its wrap count.
+ // - Published Complete before the reader requested a rewrite.
+ // - Reused Complete before the reader reclaimed it.
+ // read_pos stays unchanged. Drain() retries the same position immediately,
+ // within its per-position attempt limit.
+ kRetryImmediately,
+ // Invalid ring buffer state. This reader cannot continue.
+ // - The offending position is neither advanced nor reclaimed.
+ // - Earlier chunks in this drain may already have been delivered.
+ // - Drain() still publishes any progress made before the error.
+ kProtocolError,
+ };
-using packet_compressor::GetPreamble;
-using packet_compressor::kCompressSliceSize;
-using packet_compressor::Preamble;
-using packet_compressor::PreambleToSlice;
+ struct ChunkContents {
+ WriterID writer_id = 0;
+ BufferID target_buffer = 0;
+ // A bitwise OR of PayloadFlags.
+ uint32_t payload_flags = 0;
+ // A view into reader-owned scratch. Valid only for the duration of the
+ // Delegate call.
+ const protozero::ConstBytes* fragments = nullptr;
+ uint32_t num_fragments = 0;
+ };
-// A compressor for `TracePacket`s that uses zlib. The class is exposed for
-// testing.
-class ZlibPacketCompressor {
- public:
- ZlibPacketCompressor();
- ~ZlibPacketCompressor();
+ struct DrainResult {
+ uint32_t positions_consumed = 0;
+ ConsumeResult last_result = ConsumeResult::kNoData;
- // Can be called multiple times, before Finish() is called.
- void PushPacket(const TracePacket& packet);
+ // The caller should schedule another Drain() call.
+ bool needs_another_drain() const {
+ return last_result != ConsumeResult::kNoData &&
+ last_result != ConsumeResult::kProtocolError;
+ }
+ };
- // Returned the compressed data. Can be called at most once. After this call,
- // the object is unusable (PushPacket should not be called) and must be
- // destroyed.
- TracePacket Finish();
+ // Handles the drained fragments and loss reports. Must outlive the reader.
+ // Calls run synchronously from Drain() and must not reenter or destroy the
+ // reader.
+ class Delegate {
+ public:
+ virtual ~Delegate();
+
+ // Called after a chunk's published payload has been copied into
+ // reader-owned memory. The view is valid only for this call.
+ virtual void OnChunkRead(const ChunkContents&) = 0;
+
+ // Called when published data is discarded after validation fails or the
+ // chunk carries kFlagDataLoss. Also handles a flagged Complete chunk with
+ // no fragments. No OnChunkRead() call delivers those fragments.
+ //
+ // The delegate must handle packet recovery for this writer:
+ // - Discard any partial packet and remember the gap.
+ // - A later unflagged chunk may start with an orphan continuation.
+ // Discard that fragment because its earlier bytes were lost.
+ // - Later fragments in that chunk can start complete, valid packets.
+ // Deliver those packets and report the gap on the first one.
+ virtual void OnDataLoss(WriterID) = 0;
+ };
+
+ SharedRingBufferReader(SharedRingBuffer* ring, Delegate* delegate);
+ ~SharedRingBufferReader();
+
+ SharedRingBufferReader(const SharedRingBufferReader&) = delete;
+ SharedRingBufferReader& operator=(const SharedRingBufferReader&) = delete;
+ SharedRingBufferReader(SharedRingBufferReader&&) = delete;
+ SharedRingBufferReader& operator=(SharedRingBufferReader&&) = delete;
+
+ // Consumes up to |max_positions| logical reservations:
+ // - A position counts even when it delivers no fragments.
+ // - An unclaimed reservation uses the budget when the reader passes it.
+ // - A lost CAS retries the same position without using the position budget.
+ // A separate attempt limit bounds retries at each position. Reaching it
+ // leaves that position unchanged and requests another drain.
+ //
+ // Publishes read_pos once and wakes writers parked on a full ring buffer.
+ // The budget bounds copying and delegate callbacks in this pass.
+ // This lets other tasks run between passes over a large ring buffer.
+ DrainResult Drain(uint32_t max_positions);
+
+ bool has_protocol_error() const { return has_protocol_error_; }
+ uint32_t read_pos() const { return read_pos_; }
+
+ // For diagnostics only. The protocol never reads these counters.
+ // TODO(sashwinbalaji): Wire these counters into service statistics.
+ struct Stats {
+ uint64_t positions_skipped = 0;
+ // Successful BeingWritten -> RewriteRequested transitions.
+ uint64_t rewrite_requests = 0;
+ uint64_t chunks_read = 0;
+ uint64_t malformed_chunks = 0;
+ uint64_t unsupported_format_chunks = 0;
+ };
+ Stats GetStats() const { return stats_; }
private:
- void PushData(const void* data, uint32_t size);
- void NewOutputSlice();
- void PushCurSlice();
+ friend class test::SharedRingBufferInternalsForTest;
- z_stream stream_;
- size_t total_new_slices_size_ = 0;
- std::vector<Slice> new_slices_;
- std::unique_ptr<uint8_t[]> cur_slice_;
-};
+ // Consumes at most one position. Drain() publishes read_pos once per pass.
+ ConsumeResult ConsumeNextPosition();
-ZlibPacketCompressor::ZlibPacketCompressor() {
- memset(&stream_, 0, sizeof(stream_));
- int status = deflateInit(&stream_, 6);
- PERFETTO_CHECK(status == Z_OK);
-}
+ enum class CopiedChunkStatus {
+ kNoFragments,
+ kReady,
+ kMalformed,
+ kUnsupportedFormat,
+ kDataLoss,
+ };
-ZlibPacketCompressor::~ZlibPacketCompressor() {
- int status = deflateEnd(&stream_);
- PERFETTO_CHECK(status == Z_OK);
-}
+ // Validates and copies the published fragments.
+ // Skips payload access if kFlagDataLoss is set. Otherwise validates sizes
+ // and format before copying.
+ // The caller handles ownership before reporting any data loss.
+ CopiedChunkStatus CopyPublishedFragments(ChunkIndex chunk_idx,
+ uint32_t state_word);
+
+ // Called only after winning the position's compare-and-swap.
+ // Delivers valid, unflagged fragments to the delegate. Reports discarded
+ // chunks as loss.
+ ConsumeResult HandleCopiedChunk(CopiedChunkStatus);
+
+ // Latches the error and logs |reason| once, together with the position and
+ // the offending word. read_pos is not advanced.
+ ConsumeResult StopOnProtocolError(const char* reason, uint32_t state_word);
+
+ SharedRingBuffer* const ring_;
+ Delegate* const delegate_;
+ const uint32_t num_chunks_;
+ const uint32_t chunk_size_;
+
+ // The reader owns this value and publishes it once per Drain().
+ uint32_t read_pos_ = 0;
+ bool has_protocol_error_ = false;
+
+ // Test callback, called just before the reader's chunk-state CAS.
+ // - The reader has loaded the state and copied any readable fragments.
+ // - The callback makes a writer claim, publish or reuse the chunk.
+ // The reader's CAS then fails because it expects the earlier state.
+ // - Tests verify that Drain() retries without advancing read_pos or
+ // delivering fragments from the failed attempt.
+ // Empty in production. Tests force the race without scheduling threads.
+ std::function<void()> before_state_transition_for_testing_;
+
+ // TODO(sashwinbalaji): Revisit both scratch vectors:
+ // - Check heap/stack allocation in production and tests before enlarging
+ // the reader with inline std::array members.
+ // - copied_payload_: establish a common maximum chunk size, then use a byte
+ // array of that size.
+ // - copied_fragments_: use kMaxFragmentsPerChunk inline ConstBytes entries.
+ // - Measure whether this + offset access improves the read/copy path over
+ // following pointers to separate vector allocations.
+
+ // Published fragment bytes copied out of shared memory.
+ std::vector<uint8_t> copied_payload_;
+
+ // Each fragment's decoded size and pointer into copied_payload_.
+ std::vector<protozero::ConstBytes> copied_fragments_;
+
+ // Chunk metadata and a view of copied_fragments_ passed to OnChunkRead().
+ ChunkContents copied_chunk_;
+
+ Stats stats_;
+};
-void ZlibPacketCompressor::PushPacket(const TracePacket& packet) {
- // We need to be able to tokenize packets in the compressed stream, so we
- // prefix a proto preamble to each packet. The compressed stream looks like a
- // valid Trace proto.
- Preamble preamble =
- GetPreamble<protos::pbzero::Trace::kPacketFieldNumber>(packet.size());
- PushData(preamble.buf.data(), preamble.size);
- for (const Slice& slice : packet.slices()) {
- PushData(slice.start, static_cast<uint32_t>(slice.size));
- }
-}
+} // namespace perfetto::tracing_v2
-void ZlibPacketCompressor::PushData(const void* data, uint32_t size) {
- stream_.next_in = const_cast<Bytef*>(static_cast<const Bytef*>(data));
- stream_.avail_in = static_cast<uInt>(size);
- while (stream_.avail_in != 0) {
- if (stream_.avail_out == 0) {
- NewOutputSlice();
- }
- int status = deflate(&stream_, Z_NO_FLUSH);
- PERFETTO_CHECK(status == Z_OK);
- }
-}
+#endif // SRC_TRACING_V2_SHARED_RING_BUFFER_READER_H_
+/*
+ * Copyright (C) 2026 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.
+ */
-TracePacket ZlibPacketCompressor::Finish() {
- for (;;) {
- int status = deflate(&stream_, Z_FINISH);
- if (status == Z_STREAM_END)
- break;
- PERFETTO_CHECK(status == Z_OK || status == Z_BUF_ERROR);
- NewOutputSlice();
- }
+// gen_amalgamated expanded: #include "src/tracing/v2/shared_ring_buffer_reader.h"
- PushCurSlice();
+#include <stdint.h>
- TracePacket packet;
- packet.AddSlice(PreambleToSlice(
- GetPreamble<protos::pbzero::TracePacket::kCompressedPacketsFieldNumber>(
- total_new_slices_size_)));
- for (auto& slice : new_slices_) {
- packet.AddSlice(std::move(slice));
- }
- return packet;
-}
+// gen_amalgamated expanded: #include "perfetto/base/logging.h"
+// gen_amalgamated expanded: #include "src/tracing/v2/shared_ring_buffer.h"
+// gen_amalgamated expanded: #include "src/tracing/v2/shared_ring_buffer_abi.h"
-void ZlibPacketCompressor::NewOutputSlice() {
- PushCurSlice();
- cur_slice_ = std::make_unique<uint8_t[]>(kCompressSliceSize);
- stream_.next_out = reinterpret_cast<Bytef*>(cur_slice_.get());
- stream_.avail_out = kCompressSliceSize;
-}
+namespace perfetto::tracing_v2 {
+namespace {
-void ZlibPacketCompressor::PushCurSlice() {
- if (cur_slice_) {
- total_new_slices_size_ += kCompressSliceSize - stream_.avail_out;
- new_slices_.push_back(Slice::TakeOwnership(
- std::move(cur_slice_), kCompressSliceSize - stream_.avail_out));
- }
+// Bound attempts at one position. For M = kMaxFragmentsPerChunk:
+// - Each fragment can defeat the reader's CAS twice:
+// 1. Publication: BeingWritten(N) -> Complete(N + 1).
+// 2. Reuse: Complete(N + 1) -> BeingWritten(N + 1).
+// Allow M attempts for each, giving 2 * M.
+// - Add one for the initial Free -> BeingWritten claim.
+// - Add one for the reader's successful CAS, giving 2 * M + 2.
+//
+// This is conservative. SharedRingBufferWriter stops reusing at M fragments,
+// so there are at most M - 1 reuses. Zero-byte fragments still use the count.
+// FinishCurrentChunk() drops the cached handle even when abandoning a fragment.
+// The limit also bounds work if another producer keeps changing the state
+// without increasing the fragment count.
+constexpr uint32_t kMaxAttemptsPerPosition = 2 * kMaxFragmentsPerChunk + 2;
+
+// For the protocol-error log only.
+const char* ChunkStateName(ChunkState state) {
+ switch (state) {
+ case ChunkState::kFree:
+ return "Free";
+ case ChunkState::kBeingWritten:
+ return "BeingWritten";
+ case ChunkState::kComplete:
+ return "Complete";
+ case ChunkState::kRewriteRequested:
+ return "RewriteRequested";
+ case ChunkState::kRewriteAcknowledged:
+ return "RewriteAcknowledged";
+ case ChunkState::kReserved5:
+ case ChunkState::kReserved6:
+ case ChunkState::kReserved7:
+ return "reserved";
+ }
+ return "unknown";
}
} // namespace
-void ZlibCompressFn(std::vector<TracePacket>* packets) {
- if (packets->empty()) {
- return;
+SharedRingBufferReader::Delegate::~Delegate() = default;
+
+SharedRingBufferReader::SharedRingBufferReader(SharedRingBuffer* ring,
+ Delegate* delegate)
+ : ring_(ring),
+ delegate_(delegate),
+ num_chunks_(ring->num_chunks()),
+ chunk_size_(ring->chunk_size()) {
+ // Reserve enough scratch for any chunk format so draining does not allocate.
+ copied_payload_.reserve(chunk_size_);
+ copied_fragments_.reserve(kMaxFragmentsPerChunk);
+}
+
+SharedRingBufferReader::~SharedRingBufferReader() = default;
+
+SharedRingBufferReader::DrainResult SharedRingBufferReader::Drain(
+ uint32_t max_positions) {
+ const uint32_t start_pos = read_pos_;
+ DrainResult result{};
+ for (uint32_t i = 0; i < max_positions; ++i) {
+ // A failed CAS leaves read_pos_ unchanged. Retry the same position with
+ // a fresh state and fragment copy before it counts towards max_positions.
+ // Limit attempts so repeated writer updates cannot monopolize this pass.
+ for (uint32_t attempt = 0; attempt < kMaxAttemptsPerPosition; ++attempt) {
+ result.last_result = ConsumeNextPosition();
+ if (result.last_result != ConsumeResult::kRetryImmediately)
+ break;
+ }
+ // If every attempt lost, yield with another drain requested. Contention
+ // alone is not a protocol error. Publish earlier progress below.
+ if (result.last_result != ConsumeResult::kChunkRead &&
+ result.last_result != ConsumeResult::kPositionSkipped) {
+ break;
+ }
}
- ZlibPacketCompressor stream;
-
- for (const TracePacket& packet : *packets) {
- stream.PushPacket(packet);
+ // Unsigned subtraction also counts positions across uint32_t rollover.
+ // Advancing from UINT32_MAX to zero consumes one position.
+ result.positions_consumed = read_pos_ - start_pos;
+ if (result.positions_consumed != 0) {
+ // One publication and at most one wake cover the whole pass. Until this
+ // point writers can only under-estimate free capacity.
+ //
+ // TODO(sashwinbalaji): benchmark useful publication batch sizes.
+ ring_->PublishReadPos(read_pos_);
}
+ return result;
+}
- TracePacket packet = stream.Finish();
+// The shared lifecycle is in shared_ring_buffer_abi.h.
+//
+// The races this function has to handle:
+//
+// 1. Free: advance to the next wrap, racing the delayed writer's claim.
+// 2. BeingWritten: copy N fragments, then request RewriteRequested(N), racing
+// the writer's publication of Complete(M).
+// 3. Complete: copy the fragments, then reclaim, racing the writer's reuse.
+// 4. RewriteRequested: skip. The writer still owns the chunk. Once it becomes
+// RewriteAcknowledged, only the reader may reclaim it on a later traversal.
+//
+// In the first three cases, a failed CAS leaves read_pos unchanged. Drain()
+// retries immediately. Deliver the copy only after a successful transition,
+// so a retry cannot deliver the same fragments twice.
+//
+// RewriteAcknowledged has no competing writer transition. On failure to reclaim
+// it, report a protocol error.
+SharedRingBufferReader::ConsumeResult
+SharedRingBufferReader::ConsumeNextPosition() {
+ if (PERFETTO_UNLIKELY(has_protocol_error_))
+ return ConsumeResult::kProtocolError;
+
+ // A relaxed load is enough here. An older write_pos only shortens this
+ // drain pass, which is still correct. A later pass can consume the rest.
+ const uint32_t write_pos = ring_->LoadWritePosRelaxed();
+ const uint32_t outstanding = NumOutstandingPositions(write_pos, read_pos_);
+ if (outstanding == 0)
+ return ConsumeResult::kNoData;
+ if (PERFETTO_UNLIKELY(outstanding > num_chunks_)) {
+ // A legal writer cannot reserve more than num_chunks outstanding
+ // positions.
+ has_protocol_error_ = true;
+ PERFETTO_ELOG(
+ "tracing v2: stopping ring buffer reader: write_pos %u is %u "
+ "positions ahead of read_pos %u, which is more than the %u chunks "
+ "in the ring buffer",
+ write_pos, outstanding, read_pos_, num_chunks_);
+ return ConsumeResult::kProtocolError;
+ }
+
+ // read_pos_ is the next logical position.
+ const uint32_t chunk_pos = read_pos_;
+ const ChunkIndex chunk_idx = ChunkIndex::FromPosition(chunk_pos, num_chunks_);
+
+ // A failed compare-and-swap replaces this with the word that won.
+ uint32_t state_word = ring_->LoadChunkStateWordAcquire(chunk_idx);
+
+ switch (ChunkStateOf(state_word)) {
+ case ChunkState::kFree: {
+ // Check reserved bits first. Reclaiming must not hide an invalid word.
+ if (PERFETTO_UNLIKELY((state_word & ~kWriterIDMask) != 0))
+ return StopOnProtocolError("Free word has reserved bits", state_word);
+ // Only this reader advances the wrap. A different wrap here is an error.
+ const uint32_t expected_free_word =
+ MakeFreeStateWordForPosition(chunk_pos, num_chunks_);
+ if (PERFETTO_UNLIKELY(state_word != expected_free_word)) {
+ return StopOnProtocolError(
+ "Free word carries another position's wrap count", state_word);
+ }
+ if (before_state_transition_for_testing_)
+ before_state_transition_for_testing_();
+ // Advance the wrap count to consume this unclaimed reservation.
+ // On failure, the delayed writer claimed first. Drain() retries this
+ // position with the writer's BeingWritten or Complete state.
+ if (!ring_->TryMoveFreeChunkToNextWrap(chunk_pos, &state_word))
+ return ConsumeResult::kRetryImmediately;
+ ++read_pos_;
+ ++stats_.positions_skipped;
+ return ConsumeResult::kPositionSkipped;
+ }
+
+ case ChunkState::kBeingWritten: {
+ const auto status = CopyPublishedFragments(chunk_idx, state_word);
+ if (before_state_transition_for_testing_)
+ before_state_transition_for_testing_();
+ // Request a rewrite before read_pos_ advances, even if validation failed.
+ // On failure, the writer published first. Drain() retries with a fresh
+ // copy before it delivers fragments or reports loss for this position.
+ if (!ring_->TryRequestRewrite(chunk_idx, &state_word))
+ return ConsumeResult::kRetryImmediately;
+ ++read_pos_;
+ ++stats_.rewrite_requests;
+ return HandleCopiedChunk(status);
+ }
+
+ case ChunkState::kComplete: {
+ const auto status = CopyPublishedFragments(chunk_idx, state_word);
+ if (before_state_transition_for_testing_)
+ before_state_transition_for_testing_();
+ // Reclaim the chunk before read_pos_ advances, even if validation failed.
+ // On failure, the writer reused the chunk and can publish more fragments.
+ // Drain() reloads the state and copies the current published fragments.
+ // If the state is BeingWritten, that attempt requests a rewrite.
+ // Deliver fragments or report loss only after a successful transition.
+ if (!ring_->TryReleaseCompleteChunkAsFree(chunk_pos, &state_word))
+ return ConsumeResult::kRetryImmediately;
+ ++read_pos_;
+ // Report loss even if the Complete chunk has no fragments. The writer
+ // cannot reuse the reclaimed chunk, so no later publication can report
+ // its flag.
+ //
+ // For BeingWritten(0), the writer still owns the chunk and transfers
+ // kFlagDataLoss to the relocated fragment instead.
+ if (status == CopiedChunkStatus::kNoFragments &&
+ (copied_chunk_.payload_flags & kFlagDataLoss)) {
+ delegate_->OnDataLoss(copied_chunk_.writer_id);
+ }
+ return HandleCopiedChunk(status);
+ }
- packets->clear();
- packets->push_back(std::move(packet));
+ case ChunkState::kRewriteRequested:
+ // This chunk is still awaiting rewrite acknowledgement from its owner.
+ // The current reservation could not claim it. Advance read_pos without
+ // changing the chunk's state word or delivering fragments.
+ ++read_pos_;
+ ++stats_.positions_skipped;
+ return ConsumeResult::kPositionSkipped;
+
+ case ChunkState::kRewriteAcknowledged:
+ // Reclaim the chunk before advancing past this unclaimed reservation.
+ // No fragments are delivered. The chunk becomes available for a later
+ // reservation.
+ //
+ // The expected word contains only the RewriteAcknowledged state bits.
+ // Only this reader can change it after the writer's acknowledgement.
+ // On failure, the word was invalid or another actor changed it.
+ if (!ring_->TryReleaseRewriteAcknowledgedChunkAsFree(chunk_pos,
+ &state_word)) {
+ return StopOnProtocolError(
+ ChunkStateOf(state_word) == ChunkState::kRewriteAcknowledged
+ ? "RewriteAcknowledged word has payload bits set"
+ : "RewriteAcknowledged word changed under the reader",
+ state_word);
+ }
+ ++read_pos_;
+ ++stats_.positions_skipped;
+ return ConsumeResult::kPositionSkipped;
+
+ case ChunkState::kReserved5:
+ case ChunkState::kReserved6:
+ case ChunkState::kReserved7:
+ // The reader cannot safely reclaim an unknown state.
+ return StopOnProtocolError("reserved chunk state", state_word);
+ }
+ PERFETTO_FATAL("tracing v2: unhandled chunk state word 0x%08x", state_word);
+}
+
+SharedRingBufferReader::CopiedChunkStatus
+SharedRingBufferReader::CopyPublishedFragments(ChunkIndex chunk_idx,
+ uint32_t state_word) {
+ copied_fragments_.clear();
+ copied_chunk_ = ChunkContents{};
+ copied_chunk_.writer_id = WriterIDOf(state_word);
+ copied_chunk_.payload_flags = PayloadFlagsOf(state_word);
+
+ const uint32_t num_fragments = NumFragmentsOf(state_word);
+ if (num_fragments == 0) {
+ // A writer may still be storing BufferID after claiming BeingWritten(0).
+ // Only its first fragment publication makes that store visible. Do not
+ // touch any bytes beyond the state word when no fragment is published.
+ return CopiedChunkStatus::kNoFragments;
+ }
+
+ // The loss flag does not identify where data was lost within the chunk.
+ // - Drop every published fragment, even a complete packet after the gap.
+ // - Do not read an unpublished fragment. The writer may relocate it.
+ // The caller must win the state transition before reporting the gap or
+ // advancing read_pos. See Delegate::OnDataLoss() for packet recovery.
+ if (state_word & kFlagDataLoss)
+ return CopiedChunkStatus::kDataLoss;
+
+ if (ChunkFormatOf(state_word) != ChunkFormat::kTargetBuffer)
+ return CopiedChunkStatus::kUnsupportedFormat;
+
+ // Decode first to find the payload end and the directory start.
+ // Until then, payload_begin is the decoder's lower bound. It prevents size
+ // reads from reaching the header, but does not prove the payload fits.
+ const uint32_t capacity = chunk_size_ - kTargetBufferPayloadOffset;
+ const uint8_t* chunk = ring_->chunk_at(chunk_idx);
+ const uint8_t* const payload_begin = chunk + kTargetBufferPayloadOffset;
+ const uint8_t* sizes_cursor = chunk + chunk_size_;
+ uint32_t total = 0;
+ for (uint32_t i = 0; i < num_fragments; ++i) {
+ const auto fragment_size =
+ ReadFragmentSizeReversed(payload_begin, &sizes_cursor);
+ if (!fragment_size || *fragment_size > capacity - total) {
+ return CopiedChunkStatus::kMalformed;
+ }
+ total += *fragment_size;
+ copied_fragments_.push_back(protozero::ConstBytes{nullptr, *fragment_size});
+ }
+
+ // The sizes are valid varints. Their payloads may still overlap the
+ // directory:
+ // - Count the bytes actually read, including non-minimal size encodings.
+ // - On overlap, reject the chunk before copying or delivering any payload.
+ // - sizes_cursor is local to this read attempt. Returning discards it.
+ // No cursor change needs to be undone.
+ const uint32_t sizes_bytes =
+ static_cast<uint32_t>(chunk + chunk_size_ - sizes_cursor);
+ if (total > capacity - sizes_bytes)
+ return CopiedChunkStatus::kMalformed;
+
+ // Copy the published payload out of shared memory.
+ copied_payload_.assign(payload_begin, payload_begin + total);
+
+ // Point each fragment at its copy and collect the chunk metadata.
+ size_t offset = 0;
+ for (protozero::ConstBytes& fragment : copied_fragments_) {
+ fragment.data = copied_payload_.data() + offset;
+ offset += fragment.size;
+ }
+ copied_chunk_.target_buffer = LoadTargetBufferId(chunk);
+ copied_chunk_.fragments = copied_fragments_.data();
+ copied_chunk_.num_fragments = num_fragments;
+ return CopiedChunkStatus::kReady;
+}
+
+SharedRingBufferReader::ConsumeResult SharedRingBufferReader::HandleCopiedChunk(
+ CopiedChunkStatus status) {
+ switch (status) {
+ case CopiedChunkStatus::kReady:
+ ++stats_.chunks_read;
+ delegate_->OnChunkRead(copied_chunk_);
+ return ConsumeResult::kChunkRead;
+ case CopiedChunkStatus::kMalformed:
+ ++stats_.malformed_chunks;
+ delegate_->OnDataLoss(copied_chunk_.writer_id);
+ break;
+ case CopiedChunkStatus::kUnsupportedFormat:
+ ++stats_.unsupported_format_chunks;
+ delegate_->OnDataLoss(copied_chunk_.writer_id);
+ break;
+ case CopiedChunkStatus::kDataLoss:
+ delegate_->OnDataLoss(copied_chunk_.writer_id);
+ break;
+ case CopiedChunkStatus::kNoFragments:
+ break;
+ }
+
+ ++stats_.positions_skipped;
+ return ConsumeResult::kPositionSkipped;
}
-} // namespace perfetto
+SharedRingBufferReader::ConsumeResult
+SharedRingBufferReader::StopOnProtocolError(const char* reason,
+ uint32_t state_word) {
+ // Stop rather than trusting a malformed word from a producer. Log once.
+ has_protocol_error_ = true;
+ PERFETTO_ELOG(
+ "tracing v2: stopping ring buffer reader at position %u: %s "
+ "(chunk state word 0x%08x, %s)",
+ read_pos_, reason, state_word, ChunkStateName(ChunkStateOf(state_word)));
+ return ConsumeResult::kProtocolError;
+}
-#endif // PERFETTO_BUILDFLAG(PERFETTO_ZLIB)
-// gen_amalgamated begin source: src/tracing/service/zstd_compressor.cc
-// gen_amalgamated begin header: src/tracing/service/zstd_compressor.h
+} // namespace perfetto::tracing_v2
+// gen_amalgamated begin source: src/tracing/v2/shared_ring_buffer_writer.cc
/*
* Copyright (C) 2026 The Android Open Source Project
*
@@ -59709,24 +67023,495 @@ void ZlibCompressFn(std::vector<TracePacket>* packets) {
* limitations under the License.
*/
-#ifndef SRC_TRACING_SERVICE_ZSTD_COMPRESSOR_H_
-#define SRC_TRACING_SERVICE_ZSTD_COMPRESSOR_H_
+// gen_amalgamated expanded: #include "src/tracing/v2/shared_ring_buffer_writer.h"
-#include <vector>
+#include <stdint.h>
+#include <string.h>
-// gen_amalgamated expanded: #include "perfetto/base/build_config.h"
-// gen_amalgamated expanded: #include "perfetto/ext/tracing/core/trace_packet.h"
+#include <algorithm>
+#include <optional>
-namespace perfetto {
+// gen_amalgamated expanded: #include "perfetto/base/logging.h"
+// gen_amalgamated expanded: #include "perfetto/base/time.h"
+// gen_amalgamated expanded: #include "perfetto/ext/tracing/core/basic_types.h"
+// gen_amalgamated expanded: #include "src/tracing/v2/shared_ring_buffer.h"
+// gen_amalgamated expanded: #include "src/tracing/v2/shared_ring_buffer_abi.h"
-#if PERFETTO_BUILDFLAG(PERFETTO_ZSTD)
-// Compresses `packets` with zstd at the given compression `level`.
-void ZstdCompressFn(std::vector<TracePacket>*, int level);
-#endif
+namespace perfetto::tracing_v2 {
+namespace {
-} // namespace perfetto
+// The 100 ms sleep limit matches SharedMemoryArbiterImpl::GetNewChunk().
+constexpr uint32_t kMaxFallbackSleepUs = 100000;
-#endif // SRC_TRACING_SERVICE_ZSTD_COMPRESSOR_H_
+} // namespace
+
+SharedRingBufferWriter::SharedRingBufferWriter(SharedRingBuffer* ring,
+ WriterID writer_id,
+ BufferID target_buffer)
+ : ring_(ring),
+ writer_id_(writer_id),
+ target_buffer_(target_buffer),
+ chunk_size_(ring->chunk_size()),
+ max_fragment_size_(MaxFragmentSizeForEmptyChunk(chunk_size_)) {
+ // The WriterID goes into every chunk that this writer claims. The caller
+ // controls its lifetime.
+ //
+ // TraceWriterV2Impl releases it after its final publication. The service
+ // can still read chunks under the ID after that. See the TODO in
+ // ProducerRingBufferArbiter::OnWriterDestroyed().
+ PERFETTO_DCHECK(writer_id_ != 0 && writer_id_ <= kMaxWriterID);
+}
+
+SharedRingBufferWriter::~SharedRingBufferWriter() {
+ FinishCurrentChunk();
+}
+
+SharedRingBufferWriter::FragmentRange SharedRingBufferWriter::BeginFragment(
+ uint32_t min_size,
+ bool continues_from_prev) {
+ PERFETTO_DCHECK(!has_open_fragment());
+ // A new chunk now would put the next packet ahead of the saved fragment.
+ PERFETTO_DCHECK(!pending_relocation_);
+ // EndFragment(..., /*continues_on_next=*/true) discards the cached handle
+ // when a packet continues into another chunk. A continuation must claim a
+ // new chunk because only AcquireNewChunk() sets kFlagContinuesFromPrevChunk.
+ PERFETTO_DCHECK(!continues_from_prev || !cur_chunk_);
+
+ if (min_size > max_fragment_size_)
+ return FragmentRange{BeginFragmentResult::kTooLarge};
+
+ // Try the cached Complete chunk before a new reservation.
+ if (cur_chunk_) {
+ PERFETTO_DCHECK(cur_chunk_state() == ChunkState::kComplete);
+ const uint32_t available = MaxFragmentSizeInCurrentChunk();
+ // Pending loss does not prevent reuse, which requires no new reservation.
+ // The next publication sets kFlagDataLoss. The reader then discards all
+ // published fragments in this chunk, including those before the loss.
+ if (available >= min_size && ring_->TryReacquireChunkForWriting(
+ cur_chunk_idx_, expected_state_word_)) {
+ expected_state_word_ =
+ ReplaceChunkState(expected_state_word_, ChunkState::kBeingWritten);
+ return BeginFragmentInCurrentChunk(available);
+ }
+ // The chunk has insufficient space or the reader reclaimed it first.
+ // Discard the handle before the next claim.
+ ResetCurrentChunk();
+ }
+
+ const uint32_t flags = continues_from_prev ? kFlagContinuesFromPrevChunk : 0u;
+ const BeginFragmentResult result = AcquireNewChunk(flags);
+ if (result != BeginFragmentResult::kSuccess)
+ return FragmentRange{result};
+ return BeginFragmentInCurrentChunk(max_fragment_size_);
+}
+
+SharedRingBufferWriter::FragmentRange
+SharedRingBufferWriter::BeginFragmentInCurrentChunk(uint32_t available) {
+ PERFETTO_DCHECK(cur_chunk_);
+ PERFETTO_DCHECK(cur_chunk_state() == ChunkState::kBeingWritten);
+ PERFETTO_DCHECK(available > 0);
+ cur_fragment_begin_ = payload_end_;
+ return FragmentRange{/*result=*/BeginFragmentResult::kSuccess,
+ /*begin=*/cur_chunk_ + cur_fragment_begin_,
+ /*end=*/cur_chunk_ + cur_fragment_begin_ + available};
+}
+
+SharedRingBufferWriter::EndFragmentResult SharedRingBufferWriter::EndFragment(
+ uint32_t size,
+ bool continues_on_next) {
+ PERFETTO_DCHECK(has_open_fragment());
+ PERFETTO_DCHECK(cur_chunk_);
+ PERFETTO_DCHECK(cur_chunk_state() == ChunkState::kBeingWritten);
+ PERFETTO_DCHECK(size_directory_bytes_ <= chunk_size_);
+ PERFETTO_DCHECK(cur_fragment_begin_ <= chunk_size_ - size_directory_bytes_);
+ // The fragment must leave space for its size entry before the directory.
+ PERFETTO_DCHECK(
+ size <= MaxFragmentSizeForAvailableBytes(
+ chunk_size_ - size_directory_bytes_ - cur_fragment_begin_));
+
+ // The reader cannot access this fragment until publication updates the shared
+ // fragment count. Write the size entry before that publication.
+ uint8_t* const chunk_end = cur_chunk_ + chunk_size_;
+ uint8_t* const sizes_begin =
+ WriteFragmentSizeReversed(chunk_end - size_directory_bytes_, size);
+ // sizes_begin points to the new size entry, before the existing entries.
+ // Subtract it from chunk_end to count all directory bytes, including the new
+ // entry. The directory grows towards lower addresses.
+ size_directory_bytes_ = static_cast<uint32_t>(chunk_end - sizes_begin);
+ payload_end_ = cur_fragment_begin_ + size;
+ ++num_fragments_;
+ cur_fragment_begin_ = kNoFragmentOpen;
+
+ return ReleaseCurrentChunkAsComplete(size, continues_on_next);
+}
+
+SharedRingBufferWriter::EndFragmentResult
+SharedRingBufferWriter::FinishCurrentChunk() {
+ PERFETTO_DCHECK(!pending_relocation_);
+ // Abandon any open fragment. Its bytes are outside the published count, so
+ // this does not affect the fragments the reader can already access.
+ cur_fragment_begin_ = kNoFragmentOpen;
+
+ EndFragmentResult result = EndFragmentResult::kSuccess;
+ if (cur_chunk_ && cur_chunk_state() == ChunkState::kBeingWritten) {
+ result = ReleaseCurrentChunkAsComplete(std::nullopt,
+ /*continues_on_next=*/false);
+ }
+ ResetCurrentChunk();
+ return result;
+}
+
+uint32_t SharedRingBufferWriter::MaxFragmentSizeInCurrentChunk() const {
+ PERFETTO_DCHECK(cur_chunk_);
+ if (num_fragments_ >= kMaxFragmentsPerChunk)
+ return 0;
+ PERFETTO_DCHECK(payload_end_ <= chunk_size_);
+ PERFETTO_DCHECK(size_directory_bytes_ <= chunk_size_ - payload_end_);
+ const uint32_t available_bytes =
+ chunk_size_ - payload_end_ - size_directory_bytes_;
+ return MaxFragmentSizeForAvailableBytes(available_bytes);
+}
+
+SharedRingBufferWriter::BeginFragmentResult
+SharedRingBufferWriter::AcquireNewChunk(uint32_t continuation_flags) {
+ PERFETTO_DCHECK(!cur_chunk_);
+
+ // A new chunk must preserve loss from either source:
+ // - data_loss_pending_: this writer has a loss to report.
+ // - continuation_flags: a rewrite of BeingWritten(0) left a loss unreported.
+ // The replacement inherits that flag even if data_loss_pending_ is false.
+ const uint32_t flags =
+ continuation_flags | (data_loss_pending_ ? kFlagDataLoss : 0u);
+ const uint32_t being_written_word =
+ MakeDataStateWord(ChunkState::kBeingWritten, ChunkFormat::kTargetBuffer,
+ flags, 0, writer_id_);
+ const uint32_t num_chunks = ring_->num_chunks();
+
+ // After num_chunks failed claims, return without a chunk.
+ //
+ // Other writers can reserve intervening positions, so our attempts
+ // can select the same physical chunk on different traversals.
+ // This limit bounds attempts, but does not guarantee a visit to every chunk.
+ uint32_t num_failed_claims = 0;
+
+ // Each attempt reserves a position, then tries to claim its physical chunk:
+ //
+ // 1. TryReserveWritePos() finds the ring buffer full.
+ // - write_pos stays unchanged. No position was reserved.
+ // - Return without a chunk below.
+ //
+ // 2. Reservation and TryAcquireChunkForWriting() both succeed.
+ // - This writer now owns the chunk. Return it to the caller.
+ //
+ // 3. Reservation succeeds, but TryAcquireChunkForWriting() fails.
+ // - The reader advanced the wrap count before we claimed the chunk.
+ // We may have been descheduled after advancing write_pos.
+ // - Or the chunk still belongs to an older reservation:
+ // - Its writer claimed the chunk, then got descheduled.
+ // - The reader copied its published fragments and set RewriteRequested.
+ // - The reader advanced read_pos. It did not release the chunk.
+ // - Advancing read_pos made room for another reservation.
+ // TryReserveWritePos() checks the positions, not the chunk state.
+ // - Our new reservation selects that same physical chunk.
+ // The claim fails because the older writer has not acknowledged yet.
+ // - Leave the reservation unclaimed. Try a new reservation with continue.
+ // - After num_chunks failed claims, return without a chunk instead.
+ for (;;) {
+ const auto reservation = ring_->TryReserveWritePos();
+ read_pos_for_wait_ = reservation.read_pos_for_wait;
+
+ if (reservation.result == SharedRingBuffer::ReserveResult::kReserved) {
+ // Claim the chunk only if its Free word matches this reservation's wrap.
+ if (ring_->TryAcquireChunkForWriting(reservation.chunk_pos,
+ being_written_word)) {
+ cur_chunk_idx_ =
+ ChunkIndex::FromPosition(reservation.chunk_pos, num_chunks);
+ cur_chunk_ = ring_->chunk_at(cur_chunk_idx_);
+ expected_state_word_ = being_written_word;
+ payload_end_ = kTargetBufferPayloadOffset;
+ size_directory_bytes_ = 0;
+ num_fragments_ = 0;
+ // The shared word now contains any pending loss. If a rewrite prevents
+ // publication, relocation preserves the flag from that word.
+ data_loss_pending_ = false;
+ fallback_sleep_us_ = 0;
+ StoreTargetBufferId(cur_chunk_, target_buffer_);
+ return BeginFragmentResult::kSuccess;
+ }
+
+ ++stats_.failed_claims;
+ // write_pos advanced, but the writer did not acquire the physical chunk.
+ // This leaves an unclaimed position for the reader to consume, unless it
+ // already consumed the position before our claim.
+ //
+ // Retry with a new reservation, which supplies both the index and wrap
+ // count. Other writers can reserve intervening positions, so this need
+ // not select the next physical chunk. A different Free wrap belongs to
+ // a position we did not reserve. Do not use it to retry the failed claim.
+ if (++num_failed_claims < num_chunks)
+ continue;
+ }
+
+ // If we reach this point, either:
+ // - TryReserveWritePos() found the ring buffer full and did not increment
+ // write_pos.
+ // - TryAcquireChunkForWriting() failed num_chunks times in this round.
+ // Earlier failures took continue above to try another reservation.
+ // The last failure reached the attempt limit.
+
+ // The result tells why the call found no chunk:
+ // - kClaimFailed: a claim failed at least once in this call, even if a
+ // later reservation found the ring buffer full.
+ // - kFull: every reservation found the ring buffer full.
+ //
+ // The caller applies its BufferExhaustedPolicy. To wait, it calls
+ // WaitForReadPosChange() and then calls again.
+ return num_failed_claims != 0 ? BeginFragmentResult::kClaimFailed
+ : BeginFragmentResult::kFull;
+ }
+}
+
+void SharedRingBufferWriter::WaitForReadPosChange(uint32_t timeout_ms) {
+ if (use_futex_) {
+ // Wait while read_pos equals the value from the last reservation attempt.
+ const SharedRingBuffer::WriterWaitResult result =
+ ring_->WaitForReadPosChange(read_pos_for_wait_, timeout_ms);
+ if (result == SharedRingBuffer::WriterWaitResult::kRetry)
+ return;
+ // If the futex is unavailable, use fallback sleeps for this writer's later
+ // waits. This avoids repeated calls to an unsupported syscall.
+ use_futex_ = false;
+ }
+
+ // No futex. Sleep with v1's backoff: 0, 8, 72, ... microseconds, up to
+ // kMaxFallbackSleepUs. No sleep requests more than |timeout_ms|.
+ const uint64_t timeout_us = uint64_t{timeout_ms} * 1000;
+ base::SleepMicroseconds(static_cast<unsigned>(
+ std::min<uint64_t>(fallback_sleep_us_, timeout_us)));
+ fallback_sleep_us_ =
+ std::min(kMaxFallbackSleepUs, (fallback_sleep_us_ + 1) * 8);
+}
+
+SharedRingBufferWriter::EndFragmentResult
+SharedRingBufferWriter::ReleaseCurrentChunkAsComplete(
+ std::optional<uint32_t> fragment_size,
+ bool continues_on_next) {
+ PERFETTO_DCHECK(cur_chunk_);
+ PERFETTO_DCHECK(cur_chunk_state() == ChunkState::kBeingWritten);
+ PERFETTO_DCHECK(!has_open_fragment());
+
+ // Publication competes with the reader's rewrite request. For N published
+ // fragments, the possible transitions are:
+ // - Writer: BeingWritten(N) -> Complete(num_fragments_).
+ // - Reader: BeingWritten(N) -> RewriteRequested(N).
+ //
+ // On failure, relocate any unpublished fragment and retry publication.
+ // The reader can also request a rewrite of the replacement chunk.
+ // Repeat until publication succeeds or acquisition of a replacement fails.
+ //
+ // A failed acquisition leaves the relocation pending.
+ for (;;) {
+ uint32_t flags = PayloadFlagsOf(expected_state_word_);
+ // Publish pending loss and the fragment count in the same state word.
+ // The reader must observe the loss flag before it can deliver fragments.
+ if (data_loss_pending_)
+ flags |= kFlagDataLoss;
+ if (continues_on_next)
+ flags |= kFlagContinuesOnNextChunk;
+ const uint32_t complete_word =
+ MakeDataStateWord(ChunkState::kComplete, ChunkFormat::kTargetBuffer,
+ flags, num_fragments_, writer_id_);
+
+ uint32_t expected = expected_state_word_;
+ if (ring_->TryReleaseChunkAsComplete(cur_chunk_idx_, complete_word,
+ &expected)) {
+ expected_state_word_ = complete_word;
+ data_loss_pending_ = false;
+ PERFETTO_DCHECK(payload_end_ <= chunk_size_);
+ PERFETTO_DCHECK(size_directory_bytes_ <= chunk_size_ - payload_end_);
+
+ // Discard the cached handle if any of these limits prevents reuse:
+ // - continues_on_next: kFlagContinuesOnNextChunk describes the last
+ // fragment. If another fragment follows, the flag describes the wrong
+ // fragment and the reader cannot identify the split packet.
+ // - num_fragments_ reached kMaxFragmentsPerChunk.
+ // - At most one byte remains between the payload and the size directory.
+ // BeginFragment() requires a non-empty range plus one size byte, even
+ // if the caller later ends the fragment with a size of zero.
+ if (continues_on_next || num_fragments_ >= kMaxFragmentsPerChunk ||
+ chunk_size_ - payload_end_ - size_directory_bytes_ <= 1) {
+ ResetCurrentChunk();
+ }
+ return EndFragmentResult::kSuccess;
+ }
+
+ // On failure, expected must be RewriteRequested for this writer. Only the
+ // reader can change the word before publication, so any other value is a
+ // protocol error.
+ if (PERFETTO_UNLIKELY(ChunkStateOf(expected) !=
+ ChunkState::kRewriteRequested ||
+ WriterIDOf(expected) != writer_id_)) {
+ PERFETTO_FATAL(
+ "tracing v2: publication of chunk %u by writer %u lost to state word "
+ "0x%08x, which is not a rewrite request for this writer",
+ cur_chunk_idx_.value(), writer_id_, expected);
+ }
+
+ // expected is RewriteRequested: the reader did a partial chunk read while
+ // this writer prepared another fragment.
+ // - It consumed NumFragmentsOf(expected) published fragments. It discarded
+ // them if kFlagDataLoss was set or validation failed.
+ // - It did not consume the unpublished fragment. The reader will not return
+ // to this reservation for more fragments.
+ // - The writer must publish the remaining
+ // num_fragments_ - NumFragmentsOf(expected) fragments in a new chunk.
+ const uint32_t num_fragments_read = NumFragmentsOf(expected);
+
+ // The rewrite request preserves the count from our last publication.
+ PERFETTO_DCHECK(num_fragments_read == NumFragmentsOf(expected_state_word_));
+
+ // At most one fragment needs relocation because EndFragment() publishes
+ // before another fragment can begin:
+ // - EndFragment() adds the finished fragment to num_fragments_.
+ // - FinishCurrentChunk() abandons the open fragment without increasing it.
+ PERFETTO_DCHECK(num_fragments_ ==
+ num_fragments_read + (fragment_size.has_value() ? 1u : 0u));
+
+ // The unpublished fragment occupies the last |*fragment_size| bytes before
+ // payload_end_. The reader already consumed the earlier fragments.
+ // Save these bytes before acknowledgement. The reader can then reclaim
+ // the chunk.
+ if (fragment_size) {
+ // TODO(sashwinbalaji): Measure allocation latency on the first relocation
+ // and retained memory per writer. Use the results to decide when to
+ // allocate this scratch buffer and whether to retain it for later use.
+ relocation_payload_.assign(cur_chunk_ + payload_end_ - *fragment_size,
+ cur_chunk_ + payload_end_);
+ }
+
+ // Acknowledge before the next acquisition. The reader can then reclaim the
+ // old chunk even if this writer must wait for replacement space.
+ if (PERFETTO_UNLIKELY(
+ !ring_->TryAcknowledgeRewrite(cur_chunk_idx_, expected))) {
+ PERFETTO_FATAL(
+ "tracing v2: writer %u could not acknowledge chunk %u: only its "
+ "owner may leave RewriteRequested",
+ writer_id_, cur_chunk_idx_.value());
+ }
+ ++stats_.relocations;
+
+ // If num_fragments_read is zero, preserve both flags:
+ // - kFlagContinuesFromPrevChunk still describes the unpublished fragment.
+ // - kFlagDataLoss still needs a report because the reader ignores loss in
+ // BeingWritten(0).
+ //
+ // Otherwise, clear both flags:
+ // - The reader consumed the first fragment, so its continuation flag no
+ // longer applies. The unpublished fragment starts a new packet because
+ // EndFragment(..., /*continues_on_next=*/true) prevents further fragments
+ // in the old chunk.
+ // - The reader handles the old loss. The delegate tracks that gap for the
+ // next complete packet. Repeating the flag would discard the replacement.
+ //
+ // kFlagContinuesOnNextChunk comes from this call's continues_on_next value.
+ const uint32_t inherited_flags =
+ PayloadFlagsOf(expected) &
+ (kFlagContinuesFromPrevChunk | kFlagDataLoss);
+ const uint32_t relocated_flags =
+ num_fragments_read == 0 ? inherited_flags : 0;
+
+ ResetCurrentChunk();
+
+ if (!fragment_size) {
+ PERFETTO_DCHECK(!continues_on_next);
+ // FinishCurrentChunk() has no fragment to relocate. If the reader did not
+ // report the old loss, the next acquired chunk must report it.
+ if (relocated_flags & kFlagDataLoss)
+ data_loss_pending_ = true;
+ return EndFragmentResult::kSuccess;
+ }
+
+ // AcquireNewChunk() also includes data_loss_pending_. A loss recorded after
+ // the old publication must survive even if the reader handled the old flag.
+ const BeginFragmentResult claim = AcquireNewChunk(relocated_flags);
+ if (claim != BeginFragmentResult::kSuccess) {
+ // Keep the saved fragment. The caller retries or drops it.
+ pending_relocation_ =
+ PendingRelocation{relocated_flags, continues_on_next};
+ return claim == BeginFragmentResult::kFull
+ ? EndFragmentResult::kFull
+ : EndFragmentResult::kClaimFailed;
+ }
+ if (PERFETTO_UNLIKELY(after_replacement_claim_for_testing_))
+ after_replacement_claim_for_testing_();
+ CopyRelocatedFragment(*fragment_size);
+ }
+}
+
+SharedRingBufferWriter::RetryRelocationResult
+SharedRingBufferWriter::RetryRelocation() {
+ PERFETTO_DCHECK(pending_relocation_);
+ PERFETTO_DCHECK(!cur_chunk_);
+
+ RetryRelocationResult retry;
+ const BeginFragmentResult claim =
+ AcquireNewChunk(pending_relocation_->chunk_flags);
+ if (claim != BeginFragmentResult::kSuccess) {
+ retry.result = claim == BeginFragmentResult::kFull
+ ? EndFragmentResult::kFull
+ : EndFragmentResult::kClaimFailed;
+ return retry;
+ }
+ retry.acquired_replacement = true;
+ if (PERFETTO_UNLIKELY(after_replacement_claim_for_testing_))
+ after_replacement_claim_for_testing_();
+
+ const auto fragment_size = static_cast<uint32_t>(relocation_payload_.size());
+ const bool continues_on_next = pending_relocation_->continues_on_next;
+ pending_relocation_.reset();
+ CopyRelocatedFragment(fragment_size);
+ // If the reader also takes this replacement, this relocates again.
+ retry.result =
+ ReleaseCurrentChunkAsComplete(fragment_size, continues_on_next);
+ return retry;
+}
+
+void SharedRingBufferWriter::DropRelocation() {
+ PERFETTO_DCHECK(pending_relocation_);
+ pending_relocation_.reset();
+ ++stats_.fragments_dropped;
+ // Also covers a loss flag that the relocation inherited.
+ data_loss_pending_ = true;
+}
+
+void SharedRingBufferWriter::CopyRelocatedFragment(uint32_t fragment_size) {
+ // All chunks have the same capacity, so the saved fragment and its size
+ // entry fit in the empty replacement. An empty payload still needs a size
+ // entry and contributes one to the fragment count.
+ if (!relocation_payload_.empty()) {
+ memcpy(cur_chunk_ + kTargetBufferPayloadOffset, relocation_payload_.data(),
+ relocation_payload_.size());
+ }
+ payload_end_ = kTargetBufferPayloadOffset + fragment_size;
+ uint8_t* const chunk_end = cur_chunk_ + chunk_size_;
+ uint8_t* const sizes_begin =
+ WriteFragmentSizeReversed(chunk_end, fragment_size);
+ size_directory_bytes_ = static_cast<uint32_t>(chunk_end - sizes_begin);
+ num_fragments_ = 1;
+}
+
+void SharedRingBufferWriter::ResetCurrentChunk() {
+ cur_chunk_ = nullptr;
+ cur_chunk_idx_ = ChunkIndex::FromIndex(0);
+ expected_state_word_ = 0;
+ payload_end_ = 0;
+ size_directory_bytes_ = 0;
+ num_fragments_ = 0;
+ cur_fragment_begin_ = kNoFragmentOpen;
+}
+
+} // namespace perfetto::tracing_v2
+// gen_amalgamated begin source: src/tracing/v2/trace_writer_v2_impl.cc
/*
* Copyright (C) 2026 The Android Open Source Project
*
@@ -59743,175 +67528,338 @@ void ZstdCompressFn(std::vector<TracePacket>*, int level);
* limitations under the License.
*/
-// gen_amalgamated expanded: #include "src/tracing/service/zstd_compressor.h"
-
-// gen_amalgamated expanded: #include "perfetto/base/build_config.h"
-
-#if PERFETTO_BUILDFLAG(PERFETTO_ZSTD)
-
-#include <memory>
+// gen_amalgamated expanded: #include "src/tracing/v2/trace_writer_v2_impl.h"
-#include <zstd.h>
+#include <algorithm>
+#include <cstdint>
+#include <functional>
+#include <optional>
+#include <utility>
// gen_amalgamated expanded: #include "perfetto/base/logging.h"
-// gen_amalgamated expanded: #include "perfetto/ext/base/scoped_file.h"
-// gen_amalgamated expanded: #include "protos/perfetto/trace/trace.pbzero.h"
-// gen_amalgamated expanded: #include "protos/perfetto/trace/trace_packet.pbzero.h"
-// gen_amalgamated expanded: #include "src/tracing/service/packet_compressor_common.h"
+// gen_amalgamated expanded: #include "perfetto/base/proc_utils.h"
+// gen_amalgamated expanded: #include "perfetto/base/time.h"
+// gen_amalgamated expanded: #include "perfetto/ext/base/thread_annotations.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/message.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/proto_utils.h"
+// gen_amalgamated expanded: #include "src/tracing/v2/producer_ring_buffer_arbiter.h"
+// gen_amalgamated expanded: #include "src/tracing/v2/shared_ring_buffer_abi.h"
-namespace perfetto {
+// gen_amalgamated expanded: #include "protos/perfetto/trace/trace_packet.pbzero.h"
+namespace perfetto::tracing_v2 {
namespace {
-using packet_compressor::GetPreamble;
-using packet_compressor::kCompressSliceSize;
-using packet_compressor::Preamble;
-using packet_compressor::PreambleToSlice;
+// A new fragment must fit Protozero's largest scalar field.
+constexpr uint32_t kMinFragmentPayloadSize =
+ static_cast<uint32_t>(protozero::proto_utils::kMaxSimpleFieldEncodedSize);
-// ScopedResource's close function must return int; ZSTD_freeCStream returns
-// size_t, so wrap it. It only fails for a static-allocated stream, not the
-// heap one ZSTD_createCStream gives us, so returning 0 is safe.
-inline int ZstdFreeCStream(ZSTD_CStream* cstream) {
- ZSTD_freeCStream(cstream);
- return 0;
+// Each wait for space requests at most this time. A wait can end early, for
+// example when the reader moves read_pos.
+// SharedRingBufferWriter::WaitForReadPosChange() states the exact guarantees.
+//
+// The limit makes the writer check again also without reader progress:
+// - If the reader detached during the wait, the writer drops the data. It
+// does not wait until the stall deadline and crash.
+// - If the last drain did not free space, the writer asks for another one.
+//
+// The 100 ms limit matches the longest sleep in
+// SharedMemoryArbiterImpl::GetNewChunk().
+constexpr uint32_t kMaxWaitMs = 100;
+
+// After this time, kStall aborts and kStallThenDrop drops the data.
+// - The time starts when one chunk acquisition first needs to wait.
+// - It covers all failed claim rounds and waits of that acquisition.
+// - It does not limit the time to finish a fragment: a relocation can claim
+// several replacements, each with its own deadline.
+//
+// The 30-second limit matches v1's approximate timeout from kAssertAtNStalls
+// in SharedMemoryArbiterImpl::GetNewChunk().
+constexpr uint32_t kStallTimeoutMs = 30000;
+
+// Drop mode writes go here, so the data source can finish the packet. Nobody
+// reads it.
+// - All writers of the process share it, as v1 writers share
+// g_garbage_chunk. Their concurrent writes are a benign race.
+// - Sized to the largest chunk. A raw stream caller can then request a
+// contiguous range as large as in a normal fragment.
+uint8_t g_drop_buffer[kMaxChunkSize];
+
+} // namespace
+
+TraceWriterV2Impl::TraceWriterV2Impl(
+ ProducerRingBufferArbiter* ring_buffer_arbiter,
+ WriterID id,
+ BufferID target_buffer,
+ BufferExhaustedPolicy policy)
+ : ring_buffer_arbiter_(ring_buffer_arbiter),
+ ring_buffer_writer_(ring_buffer_arbiter->ring_buffer(),
+ id,
+ target_buffer),
+ buffer_exhausted_policy_(policy),
+ process_id_(base::GetProcessId()),
+ stream_writer_(this),
+ cur_packet_(std::make_unique<
+ protozero::RootMessage<protos::pbzero::TracePacket>>()) {}
+
+TraceWriterV2Impl::~TraceWriterV2Impl() {
+ // Flush implicitly, as TraceWriterBase documents: publish the last packet
+ // and ask for a drain. A publication alone makes the bytes readable, but it
+ // does not make the service read them.
+ //
+ // Both happen before the arbiter releases this WriterID:
+ // - The release can let the endpoint destroy the arbiter.
+ // - Ring buffer reservations keep the order if another ring buffer writer
+ // reuses the ID. Nothing handles reuse by a v1 writer yet. See the TODO
+ // in ProducerRingBufferArbiter::OnWriterDestroyed().
+ FinishTracePacket();
+ Flush();
+ ring_buffer_arbiter_->OnWriterDestroyed(writer_id());
}
-using ScopedZstdCStream = base::ScopedResource<ZSTD_CStream*,
- ZstdFreeCStream,
- /*InvalidValue=*/nullptr,
- /*CheckClose=*/false>;
-// A compressor for `TracePacket`s that uses zstd's streaming API: data is fed
-// in with ZSTD_compressStream2(ZSTD_e_continue) and the frame is finalized with
-// ZSTD_e_end, emitting output in fixed-size slices (kCompressSliceSize).
-// zstd API reference: https://facebook.github.io/zstd/zstd_manual.html
-class ZstdPacketCompressor {
- public:
- explicit ZstdPacketCompressor(int level);
+TraceWriter::TracePacketHandle TraceWriterV2Impl::NewTracePacket() {
+ PERFETTO_DCHECK(process_id_ == base::GetProcessId());
+ EnsurePacketClosed();
- // Can be called multiple times, before Finish() is called.
- void PushPacket(const TracePacket& packet);
+ stream_writer_.Reset(BeginPacketFragment(/*continues_from_prev=*/false));
+ cur_packet_->Reset(&stream_writer_,
+ protozero::Message::Encoding::kProtoGroup);
+ packet_open_ = true;
+ if (PERFETTO_UNLIKELY(first_packet_on_sequence_)) {
+ cur_packet_->set_first_packet_on_sequence(true);
+ first_packet_on_sequence_ = false;
+ }
- // Returns the compressed data. Can be called at most once. After this call,
- // the object is unusable (PushPacket should not be called) and must be
- // destroyed.
- TracePacket Finish();
+ TracePacketHandle handle(cur_packet_.get());
+ handle.set_finalization_listener(this);
+ return handle;
+}
- private:
- void PushData(const void* data, uint32_t size);
- void NewOutputSlice();
- void PushCurSlice();
+void TraceWriterV2Impl::FinishTracePacket() {
+ PERFETTO_DCHECK(process_id_ == base::GetProcessId());
+ if (!packet_open_)
+ return;
- ScopedZstdCStream cstream_;
- // Points into `cur_slice_`. Zero-initialized so that the first compression
- // call observes a full output buffer and allocates the initial slice.
- ZSTD_outBuffer out_{/*dst=*/nullptr, /*size=*/0, /*pos=*/0};
- size_t total_new_slices_size_ = 0;
- std::vector<Slice> new_slices_;
- std::unique_ptr<uint8_t[]> cur_slice_;
-};
+ // Finalize() can append closing bytes that cross a chunk boundary. Keep
+ // packet_open_ true until it returns so GetNewBuffer() can obtain space for
+ // those bytes. Then publish the final fragment without a continuation flag.
+ cur_packet_->Finalize();
+ packet_open_ = false;
+ EndPacketFragment(/*continues_on_next=*/false);
+}
-ZstdPacketCompressor::ZstdPacketCompressor(int level) {
- cstream_.reset(ZSTD_createCStream());
- PERFETTO_CHECK(cstream_);
- // zstd maps 0 to its default level, clamps levels above its max, and treats
- // negatives as fast modes, so any int is safe to pass through here.
- size_t rc =
- ZSTD_CCtx_setParameter(cstream_.get(), ZSTD_c_compressionLevel, level);
- PERFETTO_CHECK(!ZSTD_isError(rc));
+void TraceWriterV2Impl::Flush(std::function<void()> callback) {
+ EnsurePacketClosed();
+
+ // A completed fragment leaves its chunk cached for later packets. Release
+ // that chunk before ring_buffer_arbiter_->Flush() so later packets use new
+ // reservations.
+ ring_buffer_writer_.FinishCurrentChunk();
+ stream_writer_.Reset({nullptr, nullptr});
+ ring_buffer_arbiter_->Flush(std::move(callback));
}
-void ZstdPacketCompressor::PushPacket(const TracePacket& packet) {
- // Prefix each packet with its proto preamble so the compressed stream itself
- // parses as a valid Trace proto, and its packets can be tokenized back out.
- Preamble preamble =
- GetPreamble<protos::pbzero::Trace::kPacketFieldNumber>(packet.size());
- PushData(preamble.buf.data(), preamble.size);
- for (const Slice& slice : packet.slices()) {
- PushData(slice.start, static_cast<uint32_t>(slice.size));
- }
+void TraceWriterV2Impl::OnMessageFinalized(protozero::Message*) {
+ FinishTracePacket();
}
-void ZstdPacketCompressor::PushData(const void* data, uint32_t size) {
- // ZSTD_e_continue hands data to the encoder, which buffers and emits at its
- // own discretion. It may not consume all input in one call (e.g. when the
- // output slice fills), so loop until `in` is drained, giving it a fresh slice
- // whenever `out_` is full.
- ZSTD_inBuffer in = {/*src=*/data, /*size=*/size, /*pos=*/0};
- while (in.pos < in.size) {
- if (out_.pos == out_.size) {
- NewOutputSlice();
- }
- size_t rc =
- ZSTD_compressStream2(cstream_.get(), &out_, &in, ZSTD_e_continue);
- PERFETTO_CHECK(!ZSTD_isError(rc));
+protozero::ContiguousMemoryRange TraceWriterV2Impl::GetNewBuffer() {
+ if (!packet_open_) {
+ // A stale handle can request space without an open packet. This caller
+ // error violates the data-source API contract.
+ PERFETTO_DFATAL("TraceWriterV2Impl: write outside an open packet");
+ EnterDropMode();
+ return GetDropBuffer();
}
-}
-TracePacket ZstdPacketCompressor::Finish() {
- // ZSTD_e_end flushes buffered data and writes the frame epilogue. Per the
- // contract, keep calling (draining `out_` into new slices) until it reports 0
- // bytes remaining.
- size_t remaining;
- do {
- if (out_.pos == out_.size) {
- NewOutputSlice();
- }
- ZSTD_inBuffer in = {/*src=*/nullptr, /*size=*/0, /*pos=*/0};
- remaining = ZSTD_compressStream2(cstream_.get(), &out_, &in, ZSTD_e_end);
- PERFETTO_CHECK(!ZSTD_isError(remaining));
- } while (remaining != 0);
+ // If the writer loses part of a packet, the remaining bytes are not useful.
+ // Send the rest to the drop buffer. Try the ring buffer for the next packet.
+ if (in_drop_mode_)
+ return GetDropBuffer();
- PushCurSlice();
+ // The current range cannot satisfy the stream's request. Publish this
+ // fragment with kFlagContinuesOnNextChunk and continue in another chunk.
+ EndPacketFragment(/*continues_on_next=*/true);
- TracePacket packet;
- packet.AddSlice(PreambleToSlice(
- GetPreamble<
- protos::pbzero::TracePacket::kZstdCompressedPacketsFieldNumber>(
- total_new_slices_size_)));
- for (auto& slice : new_slices_) {
- packet.AddSlice(std::move(slice));
- }
- return packet;
+ // EndPacketFragment() can fail to relocate after the reader requests a
+ // rewrite. Then the rest of the packet goes to the drop buffer, not to a
+ // continuation fragment.
+ if (in_drop_mode_)
+ return GetDropBuffer();
+
+ return BeginPacketFragment(/*continues_from_prev=*/true);
}
-void ZstdPacketCompressor::NewOutputSlice() {
- PushCurSlice();
- cur_slice_ = std::make_unique<uint8_t[]>(kCompressSliceSize);
- out_.dst = cur_slice_.get();
- out_.size = kCompressSliceSize;
- out_.pos = 0;
+uint8_t* TraceWriterV2Impl::AnnotatePatch(uint8_t*) {
+ PERFETTO_FATAL("TraceWriterV2Impl cannot patch previously written bytes");
}
-void ZstdPacketCompressor::PushCurSlice() {
- if (!cur_slice_) {
- return;
- }
- total_new_slices_size_ += out_.pos;
- new_slices_.push_back(Slice::TakeOwnership(std::move(cur_slice_), out_.pos));
+void TraceWriterV2Impl::EnsurePacketClosed() {
+ if (packet_open_ && cur_packet_->is_finalized())
+ FinishTracePacket();
+ PERFETTO_CHECK(!packet_open_);
}
-} // namespace
+protozero::ContiguousMemoryRange TraceWriterV2Impl::BeginPacketFragment(
+ bool continues_from_prev) {
+ std::optional<base::TimeMillis> stall_deadline;
+ for (;;) {
+ const auto range = ring_buffer_writer_.BeginFragment(
+ kMinFragmentPayloadSize, continues_from_prev);
+ if (range.result == SharedRingBufferWriter::BeginFragmentResult::kSuccess) {
+ fragment_begin_ = range.begin;
+ in_drop_mode_ = false;
+ return {range.begin, range.end};
+ }
+ // Every valid chunk size holds kMinFragmentPayloadSize.
+ PERFETTO_DCHECK(range.result !=
+ SharedRingBufferWriter::BeginFragmentResult::kTooLarge);
-void ZstdCompressFn(std::vector<TracePacket>* packets, int level) {
- if (packets->empty()) {
+ const bool claim_failed =
+ range.result ==
+ SharedRingBufferWriter::BeginFragmentResult::kClaimFailed;
+ if (!TryStallForSpace(claim_failed, &stall_deadline)) {
+ EnterDropMode();
+ return GetDropBuffer();
+ }
+ }
+}
+
+void TraceWriterV2Impl::EndPacketFragment(bool continues_on_next) {
+ if (!fragment_begin_) {
+ // The packet went to the drop buffer. The next publication carries
+ // kFlagDataLoss, even if it reuses a cached chunk.
return;
}
- ZstdPacketCompressor stream(level);
+ const uint32_t used =
+ static_cast<uint32_t>(stream_writer_.write_ptr() - fragment_begin_);
+ fragment_begin_ = nullptr;
- for (const TracePacket& packet : *packets) {
- stream.PushPacket(packet);
+ // If the reader took the chunk, EndFragment() relocates the fragment and
+ // needs a replacement chunk. See SharedRingBufferWriter::EndFragment().
+ //
+ // If EndFragment() cannot claim a replacement, the relocation stays pending
+ // until the policy lets the writer try again or drop it.
+ SharedRingBufferWriter::EndFragmentResult result =
+ ring_buffer_writer_.EndFragment(used, continues_on_next);
+ // The stall deadline of the current replacement acquisition. It starts at
+ // the first wait after EndFragment() returns.
+ std::optional<base::TimeMillis> stall_deadline;
+ while (result != SharedRingBufferWriter::EndFragmentResult::kSuccess) {
+ const bool claim_failed =
+ result == SharedRingBufferWriter::EndFragmentResult::kClaimFailed;
+ if (!TryStallForSpace(claim_failed, &stall_deadline)) {
+ // Discard the saved fragment and the rest of the packet.
+ ring_buffer_writer_.DropRelocation();
+ EnterDropMode();
+ return;
+ }
+ const auto retry = ring_buffer_writer_.RetryRelocation();
+ // A claimed replacement ends the current acquisition, even if the reader
+ // then took it before publication. The next acquisition gets its own
+ // deadline at its first wait. Retries without a claim keep the deadline.
+ if (retry.acquired_replacement)
+ stall_deadline.reset();
+ result = retry.result;
+ }
+
+ // Batch drain requests until occupancy reaches the threshold:
+ // - This reduces task and IPC traffic when packets arrive separately.
+ // - It lets this writer reuse its cached Complete chunk for longer. A drain
+ // frees that chunk, and the next fragment then needs a new one.
+ const uint32_t outstanding_positions =
+ ring_buffer_arbiter_->ring_buffer()->LoadNumOutstandingPositionsRelaxed();
+ if (outstanding_positions >=
+ ring_buffer_arbiter_->drain_occupancy_threshold()) {
+ ring_buffer_arbiter_->RequestDrain(
+ ProducerRingBufferArbiter::DrainUrgency::kRoutine);
+ }
+}
+
+bool TraceWriterV2Impl::TryStallForSpace(
+ bool claim_failed,
+ std::optional<base::TimeMillis>* stall_deadline) {
+ // While a loss waits for its report, kStallThenDrop acts as kDrop.
+ // Otherwise each dropped packet can cost another full timeout.
+ //
+ // A later
+ // acquisition can stall again after a chunk carries the loss. This matches
+ // v1's drop_packets_ behavior.
+ bool can_stall = buffer_exhausted_policy_ != BufferExhaustedPolicy::kDrop;
+ if (buffer_exhausted_policy_ == BufferExhaustedPolicy::kStallThenDrop &&
+ ring_buffer_writer_.has_pending_data_loss()) {
+ can_stall = false;
+ }
+
+ // Time left before the stall deadline. Zero means drop.
+ // Without an attached reader, nothing frees space. So drop, also under
+ // kStall. A wait would only end at the deadline, where kStall crashes.
+ uint32_t time_left_ms = 0;
+ if (can_stall && ring_buffer_arbiter_->IsReaderAttached()) {
+ const base::TimeMillis now = get_time_ms_();
+ if (!stall_deadline->has_value())
+ *stall_deadline = now + base::TimeMillis(kStallTimeoutMs);
+ const base::TimeMillis deadline = **stall_deadline;
+ if (now < deadline) {
+ time_left_ms = static_cast<uint32_t>((deadline - now).count());
+ } else if (buffer_exhausted_policy_ == BufferExhaustedPolicy::kStall) {
+ PERFETTO_FATAL(
+ "tracing v2: writer %u could not acquire a chunk for %u ms: "
+ "possible deadlock",
+ writer_id(), kStallTimeoutMs);
+ }
}
- TracePacket packet = stream.Finish();
+ // Every drop takes this exit.
+ if (time_left_ms == 0) {
+ // Failed claims left reserved positions that only the reader can move
+ // past. Until it does, they block the reservations of all writers. An
+ // earlier drain does not cover positions reserved after it.
+ if (claim_failed) {
+ ring_buffer_arbiter_->RequestDrain(
+ ProducerRingBufferArbiter::DrainUrgency::kRoutine);
+ }
+ PERFETTO_DLOG(
+ "tracing v2: writer %u: %s: dropping data", writer_id(),
+ claim_failed ? "no chunk could be claimed" : "ring buffer full");
+ return false;
+ }
- packets->clear();
- packets->push_back(std::move(packet));
+ // Make the reader run before the wait. Its drain frees space, and moves
+ // read_pos past the positions of failed claims.
+ ring_buffer_arbiter_->RequestDrain(
+ ProducerRingBufferArbiter::DrainUrgency::kUrgent);
+
+ // With a futex, the wait compares read_pos with the value that the last
+ // reservation attempt saw, before the request above. So it also sees reader
+ // progress that happens between the request and the wait.
+ //
+ // The requested wait time comes from the time left before the deadline,
+ // measured before the request above. So the wait can end slightly after the
+ // deadline. The next check then drops or aborts.
+ ring_buffer_writer_.WaitForReadPosChange(std::min(kMaxWaitMs, time_left_ms));
+ return true;
}
-} // namespace perfetto
+void TraceWriterV2Impl::EnterDropMode() {
+ fragment_begin_ = nullptr;
+ // Consecutive dropped packets count as one drop.
+ if (in_drop_mode_)
+ return;
+ in_drop_mode_ = true;
+ ++drop_count_;
+ ring_buffer_writer_.RecordDataLoss();
+}
-#endif // PERFETTO_BUILDFLAG(PERFETTO_ZSTD)
+protozero::ContiguousMemoryRange TraceWriterV2Impl::GetDropBuffer() {
+ PERFETTO_DCHECK(in_drop_mode_);
+ PERFETTO_ANNOTATE_BENIGN_RACE_SIZED(&g_drop_buffer, sizeof(g_drop_buffer),
+ "nobody reads the drop buffer")
+ return {&g_drop_buffer[0], &g_drop_buffer[0] + sizeof(g_drop_buffer)};
+}
+
+} // namespace perfetto::tracing_v2
// gen_amalgamated begin source: src/tracing/service/clock.cc
// gen_amalgamated begin header: src/tracing/service/clock.h
/*
@@ -60501,8 +68449,8 @@ double RandomImpl::GetValue() {
}
} // namespace perfetto::tracing_service
-// gen_amalgamated begin source: src/tracing/service/trace_buffer_v1.cc
-// gen_amalgamated begin header: src/tracing/service/trace_buffer_v1.h
+// gen_amalgamated begin source: src/tracing/service/service_ring_buffer_drainer.cc
+// gen_amalgamated begin header: src/tracing/service/service_ring_buffer_drainer.h
// gen_amalgamated begin header: include/perfetto/ext/tracing/core/client_identity.h
/*
* Copyright (C) 2023 The Android Open Source Project
@@ -60555,6 +68503,157 @@ class ClientIdentity {
} // namespace perfetto
#endif // INCLUDE_PERFETTO_EXT_TRACING_CORE_CLIENT_IDENTITY_H_
+/*
+ * Copyright (C) 2026 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 SRC_TRACING_SERVICE_SERVICE_RING_BUFFER_DRAINER_H_
+#define SRC_TRACING_SERVICE_SERVICE_RING_BUFFER_DRAINER_H_
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include <functional>
+#include <memory>
+
+// gen_amalgamated expanded: #include "perfetto/ext/base/thread_checker.h"
+// gen_amalgamated expanded: #include "perfetto/ext/base/weak_runner.h"
+// gen_amalgamated expanded: #include "perfetto/ext/tracing/core/basic_types.h"
+// gen_amalgamated expanded: #include "perfetto/ext/tracing/core/client_identity.h"
+// gen_amalgamated expanded: #include "perfetto/ext/tracing/core/shared_memory.h"
+// gen_amalgamated expanded: #include "src/tracing/v2/shared_ring_buffer.h"
+// gen_amalgamated expanded: #include "src/tracing/v2/shared_ring_buffer_reader.h"
+
+namespace perfetto {
+class TraceBuffer;
+namespace tracing_v2 {
+
+namespace test {
+class ServiceRingBufferDrainerTestPeer;
+} // namespace test
+
+// Copies published data from one producer connection's v2 ring buffer into
+// authorized trace buffers that support SMB v2. ProducerRingBufferArbiter
+// manages the producer side. See AttachV2RingBuffer in producer_port.proto for
+// the IPC flow.
+//
+// All operations, including construction and destruction, run on the service
+// sequence.
+//
+// ProducerEndpointImpl
+// |-- owns ---> ServiceRingBufferDrainer (this class)
+// |-- shares -> SharedMemory: the ring buffer mapping
+// |-- owns ---> SharedRingBuffer: the view
+// |-- owns ---> SharedRingBufferReader
+// |-- uses ---> Delegate (the ProducerEndpointImpl)
+// |-- uses ---> the service task runner
+//
+// Over IPC, |memory_| holds the service's separate mapping. In-process, the
+// producer and service share the same mapping.
+class ServiceRingBufferDrainer : public SharedRingBufferReader::Delegate {
+ public:
+ // Delegate calls must not destroy or reenter the drainer.
+ class Delegate {
+ public:
+ virtual ~Delegate();
+
+ // Returns a trace buffer that the producer may write to and that supports
+ // SMB v2, or nullptr. The service owns the buffer, which must remain valid
+ // during OnChunkRead().
+ virtual TraceBuffer* GetV2RingBufferDestination(BufferID) = 0;
+
+ // Calls |callback| inline for each buffer that GetV2RingBufferDestination()
+ // would return. Buffer references are valid only during the callback.
+ // The callback must not change the set of destinations or destroy a buffer.
+ virtual void ForEachV2RingBufferDestination(
+ const std::function<void(TraceBuffer&)>& callback) = 0;
+
+ // Adds |count| to the service's chunks_discarded statistic for chunks that
+ // never reached a trace buffer. Excludes loss reported by the producer.
+ virtual void OnRingBufferChunksDiscarded(uint64_t count) = 0;
+ };
+
+ // Shares ownership of |memory|. The mapping and |chunk_size_bytes| must
+ // describe a valid ring buffer layout. |delegate| and |task_runner| must
+ // remain valid until destruction.
+ ServiceRingBufferDrainer(std::shared_ptr<SharedMemory> memory,
+ uint32_t chunk_size_bytes,
+ ProducerID,
+ ClientIdentity,
+ Delegate* delegate,
+ base::TaskRunner* task_runner);
+
+ // Cancels pending retry tasks. Destruction does not call Drain() or copy any
+ // remaining data from |ring_buffer_|.
+ ~ServiceRingBufferDrainer() override;
+ ServiceRingBufferDrainer(const ServiceRingBufferDrainer&) = delete;
+ ServiceRingBufferDrainer& operator=(const ServiceRingBufferDrainer&) = delete;
+ ServiceRingBufferDrainer(ServiceRingBufferDrainer&&) = delete;
+ ServiceRingBufferDrainer& operator=(ServiceRingBufferDrainer&&) = delete;
+
+ // Reads at most |ring_buffer_.num_chunks()| logical positions. Reaching the
+ // position or retry limit schedules another pass after a delay. At most one
+ // retry task is pending at a time.
+ //
+ // A protocol error stops all future reads and records one ABI violation in
+ // each authorized destination. Data already copied is kept. The producer
+ // stays connected without notification or a v1 fallback. When the ring buffer
+ // fills, its writers drop packets, or stall and time out.
+ void Drain();
+
+ // Mapping size for the service's memory guardrail.
+ size_t size_bytes() const { return memory_->size(); }
+
+ private:
+ friend class test::ServiceRingBufferDrainerTestPeer;
+
+ // SharedRingBufferReader::Delegate implementation.
+ // The reader calls these inline during Drain().
+ void OnChunkRead(const SharedRingBufferReader::ChunkContents&) override;
+ void OnDataLoss(WriterID) override;
+
+ // Marks a gap in the sequence for |writer_id| in its destination buffer.
+ void RecordWriterLoss(WriterID writer_id);
+
+ // Trusted identity supplied by the endpoint.
+ const ProducerID producer_id_;
+ const ClientIdentity client_identity_;
+
+ Delegate* const delegate_;
+
+ // Declared before |ring_buffer_| and |reader_| so the mapping outlives them.
+ std::shared_ptr<SharedMemory> memory_;
+
+ // Constructing |ring_buffer_| leaves the contents of |memory_| unchanged,
+ // preserving any data the producer has already written.
+ SharedRingBuffer ring_buffer_;
+ SharedRingBufferReader reader_;
+
+ bool retry_scheduled_ = false;
+
+ PERFETTO_THREAD_CHECKER(thread_checker_)
+
+ // Declared last to cancel retry tasks before reader or mapping destruction.
+ base::WeakRunner weak_runner_;
+};
+
+} // namespace tracing_v2
+} // namespace perfetto
+
+#endif // SRC_TRACING_SERVICE_SERVICE_RING_BUFFER_DRAINER_H_
+// gen_amalgamated begin header: src/tracing/service/trace_buffer.h
// gen_amalgamated begin header: src/tracing/service/histogram.h
/*
* Copyright (C) 2023 The Android Open Source Project
@@ -60649,7 +68748,6 @@ class Histogram {
} // namespace perfetto
#endif // SRC_TRACING_SERVICE_HISTOGRAM_H_
-// gen_amalgamated begin header: src/tracing/service/trace_buffer.h
/*
* Copyright (C) 2018 The Android Open Source Project
*
@@ -60672,6 +68770,7 @@ class Histogram {
#include <stdint.h>
#include <array>
#include <memory>
+#include <new>
// gen_amalgamated expanded: #include "perfetto/ext/base/flat_hash_map.h"
// gen_amalgamated expanded: #include "perfetto/ext/tracing/core/basic_types.h"
@@ -60679,9 +68778,14 @@ class Histogram {
// gen_amalgamated expanded: #include "perfetto/ext/tracing/core/trace_stats.h"
// gen_amalgamated expanded: #include "src/tracing/service/histogram.h"
+namespace protozero {
+struct ConstBytes;
+} // namespace protozero
+
namespace perfetto {
class TracePacket;
+class TraceBufferProtoVms;
class TraceBuffer_WriterStats;
// Virtual interface for trace buffers to enable multiple implementations.
@@ -60743,6 +68847,54 @@ class TraceBuffer {
size_t patches_size,
bool other_patches_pending) = 0;
+ // Returns true if the buffer accepts tracing v2 data through
+ // CopyChunkV2Untrusted(). The service offers tracing v2 only to data sources
+ // that write into such a buffer.
+ virtual bool supports_tracing_v2() const = 0;
+
+ // Copies a batch of SMB v2 fragments into the buffer. The caller must pass
+ // fragments and batches in write order for each {ProducerID, WriterID}.
+ // The caller owns the fragment array and payloads. Both must remain valid
+ // and unchanged until this call returns.
+ //
+ // Each fragment is a whole packet unless a continuation flag is set.
+ // - |first_continues_from_prev| means the first fragment continues a packet
+ // that started in this writer's previous batch.
+ // - |last_continues_on_next| means the last fragment continues in this
+ // writer's next batch.
+ // The caller decodes these flags from its transport. If the transport marks
+ // a batch as lossy, call RecordChunkV2DataLoss() instead of copying it.
+ //
+ // Returns true if the whole batch was stored. Returns false if the batch
+ // was rejected:
+ // - The rejection of a nonempty batch records loss as RecordChunkV2DataLoss()
+ // does. An empty batch changes nothing.
+ // - Invalid input increments abi_violations. Other rejections increment
+ // chunks_discarded.
+ //
+ // If supports_tracing_v2() is false, returns false and changes nothing.
+ virtual bool CopyChunkV2Untrusted(const PacketSequenceProperties&,
+ const protozero::ConstBytes* fragments,
+ size_t num_fragments,
+ bool first_continues_from_prev,
+ bool last_continues_on_next) = 0;
+
+ // Records a gap after the last SMB v2 batch that the writer appended.
+ // Packets already in the buffer remain readable. The gap stays pending
+ // until the next stored batch carries it or the writer's state is discarded.
+ // Reads report the gap on the first readable packet after it. This does not
+ // increment any statistics.
+ //
+ // Does nothing if the buffer holds no SMB v2 state for the writer. A caller
+ // that cannot identify the destination can call this on every candidate
+ // buffer without creating state for writers that never used it.
+ virtual void RecordChunkV2DataLoss(ProducerID, WriterID) = 0;
+
+ // Increments abi_violations for a violation that the caller found outside
+ // this buffer, e.g. a protocol error in a producer's ring buffer. This only
+ // updates the statistic and does not record a gap on any packet sequence.
+ virtual void RecordAbiViolation() = 0;
+
// To read the contents of the buffer the caller needs to:
// BeginRead()
// while (ReadNextTracePacket(packet_fragments)) { ... }
@@ -60763,10 +68915,23 @@ class TraceBuffer {
PacketSequenceProperties* sequence_properties,
uint32_t* previous_packet_on_sequence_dropped) = 0;
+ // Attempts to reclaim unused buffer space.
+ // The caller must release all packets from previous reads before this call,
+ // because their slices can point into the buffer.
+ // Call BeginRead() before reading again.
+ virtual void MaybeCompact() = 0;
+
// Creates a read-only clone of the trace buffer. The read iterators of the
// new buffer will be reset, as if no Read() had been called.
virtual std::unique_ptr<TraceBuffer> CloneReadOnly() const = 0;
+ // Returns the ProtoVM state owned by this buffer, or nullptr if the
+ // implementation cannot run a ProtoVM. The pointer remains valid until the
+ // buffer is destroyed.
+ // The service uses it to set up VMs and emit their state. The buffer feeds
+ // packets to the VMs before overwriting them.
+ virtual TraceBufferProtoVms* protovms() = 0;
+
virtual void set_read_only() = 0;
virtual const TraceStats::BufferStats& stats() const = 0;
virtual const WriterStats& writer_stats() const = 0;
@@ -60791,6 +68956,19 @@ class TraceBuffer_WriterStats {
base::QuadraticProbe,
/*AppendOnly=*/true>;
+ TraceBuffer_WriterStats() = default;
+ TraceBuffer_WriterStats(const TraceBuffer_WriterStats& other) {
+ for (auto it = other.map_.GetIterator(); it; ++it)
+ map_.Insert(it.key(), it.value());
+ }
+ TraceBuffer_WriterStats& operator=(const TraceBuffer_WriterStats& other) {
+ if (this != &other) {
+ this->~TraceBuffer_WriterStats();
+ new (this) TraceBuffer_WriterStats(other);
+ }
+ return *this;
+ }
+
void Insert(ProducerAndWriterID key, HistValue val) {
map_.Insert(key, {}).first->Add(val);
}
@@ -60804,6 +68982,405 @@ class TraceBuffer_WriterStats {
} // namespace perfetto
#endif // SRC_TRACING_SERVICE_TRACE_BUFFER_H_
+/*
+ * Copyright (C) 2026 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.
+ */
+
+// gen_amalgamated expanded: #include "src/tracing/service/service_ring_buffer_drainer.h"
+
+#include <utility>
+
+// gen_amalgamated expanded: #include "perfetto/base/compiler.h"
+// gen_amalgamated expanded: #include "perfetto/base/logging.h"
+// gen_amalgamated expanded: #include "src/tracing/service/trace_buffer.h"
+
+namespace perfetto::tracing_v2 {
+
+namespace {
+
+// Delay retries so writers that repeatedly win chunk state transitions
+// cannot keep the service sequence busy.
+constexpr uint32_t kDrainRetryDelayMs = 1;
+
+} // namespace
+
+ServiceRingBufferDrainer::Delegate::~Delegate() = default;
+
+ServiceRingBufferDrainer::ServiceRingBufferDrainer(
+ std::shared_ptr<SharedMemory> memory,
+ uint32_t chunk_size_bytes,
+ ProducerID producer_id,
+ ClientIdentity client_identity,
+ Delegate* delegate,
+ base::TaskRunner* task_runner)
+ : producer_id_(producer_id),
+ client_identity_(client_identity),
+ delegate_(delegate),
+ memory_(std::move(memory)),
+ ring_buffer_(static_cast<uint8_t*>(memory_->start()),
+ memory_->size(),
+ chunk_size_bytes),
+ reader_(&ring_buffer_, this),
+ weak_runner_(task_runner) {}
+
+ServiceRingBufferDrainer::~ServiceRingBufferDrainer() {
+ PERFETTO_DCHECK_THREAD(thread_checker_);
+}
+
+void ServiceRingBufferDrainer::Drain() {
+ PERFETTO_DCHECK_THREAD(thread_checker_);
+
+ if (PERFETTO_UNLIKELY(reader_.has_protocol_error()))
+ return;
+
+ // Bound each pass to num_chunks() logical positions, including positions
+ // reserved during the pass.
+ const SharedRingBufferReader::Stats stats_before = reader_.GetStats();
+ const auto result = reader_.Drain(ring_buffer_.num_chunks());
+ const SharedRingBufferReader::Stats stats_after = reader_.GetStats();
+
+ // The reader discards malformed chunks and chunks in an unknown format. It
+ // reports them as loss for the writer. Count them here, once per pass.
+ const uint64_t num_rejected =
+ (stats_after.malformed_chunks - stats_before.malformed_chunks) +
+ (stats_after.unsupported_format_chunks -
+ stats_before.unsupported_format_chunks);
+ if (PERFETTO_UNLIKELY(num_rejected != 0))
+ delegate_->OnRingBufferChunksDiscarded(num_rejected);
+
+ if (PERFETTO_UNLIKELY(reader_.has_protocol_error())) {
+ // Record the error in every authorized destination. Later drains return
+ // above, so each destination counts this violation only once.
+ delegate_->ForEachV2RingBufferDestination(
+ [](TraceBuffer& buffer) { buffer.RecordAbiViolation(); });
+ return;
+ }
+
+ if (result.needs_another_drain() && !retry_scheduled_) {
+ retry_scheduled_ = true;
+ weak_runner_.PostDelayedTask(
+ [this] {
+ // Clear the flag so Drain() can schedule another retry if needed.
+ retry_scheduled_ = false;
+ Drain();
+ },
+ kDrainRetryDelayMs);
+ }
+}
+
+void ServiceRingBufferDrainer::OnChunkRead(
+ const SharedRingBufferReader::ChunkContents& chunk) {
+ if (PERFETTO_UNLIKELY(!chunk.writer_id || chunk.writer_id > kMaxWriterID)) {
+ delegate_->OnRingBufferChunksDiscarded(1);
+ return;
+ }
+
+ TraceBuffer* buffer =
+ delegate_->GetV2RingBufferDestination(chunk.target_buffer);
+ if (PERFETTO_UNLIKELY(!buffer)) {
+ delegate_->OnRingBufferChunksDiscarded(1);
+ RecordWriterLoss(chunk.writer_id);
+ return;
+ }
+
+ // The reader reports a chunk with kFlagDataLoss through OnDataLoss(). Only
+ // the continuation flags can reach this point.
+ PERFETTO_DCHECK(!(chunk.payload_flags & kFlagDataLoss));
+ const TraceBuffer::PacketSequenceProperties sequence{
+ producer_id_, client_identity_, chunk.writer_id};
+ // On rejection, the trace buffer counts the chunk in its own statistics and
+ // records the loss on the sequence.
+ //
+ // TODO(sashwinbalaji): the payload is copied twice: from shared memory into
+ // the reader's scratch, then into a TBv2 chunk. The reader could pass the
+ // decoded sizes and one payload range, so that TBv2 copies once. Measure
+ // the drain cost in a profile first.
+ buffer->CopyChunkV2Untrusted(
+ sequence, chunk.fragments, chunk.num_fragments,
+ chunk.payload_flags & kFlagContinuesFromPrevChunk,
+ chunk.payload_flags & kFlagContinuesOnNextChunk);
+}
+
+void ServiceRingBufferDrainer::OnDataLoss(WriterID writer_id) {
+ // Record the loss in |writer_id|'s sequence so it can be reported through
+ // previous_packet_dropped.
+ //
+ // Drain() counts chunks discarded by the reader in chunks_discarded.
+ // Loss reported by the producer does not increase that counter.
+ RecordWriterLoss(writer_id);
+}
+
+void ServiceRingBufferDrainer::RecordWriterLoss(WriterID writer_id) {
+ if (!writer_id || writer_id > kMaxWriterID)
+ return;
+ // The destination of a lost chunk is unknown. RecordChunkV2DataLoss() changes
+ // only a buffer that holds this writer's sequence.
+ // - A writer has one destination, so at most one buffer matches.
+ // - Before the writer's first stored chunk, no buffer matches.
+ delegate_->ForEachV2RingBufferDestination(
+ [this, writer_id](TraceBuffer& buffer) {
+ buffer.RecordChunkV2DataLoss(producer_id_, writer_id);
+ });
+}
+
+} // namespace perfetto::tracing_v2
+// gen_amalgamated begin source: src/tracing/service/trace_buffer_protovms.cc
+// gen_amalgamated begin header: src/tracing/service/trace_buffer_protovms.h
+/*
+ * Copyright (C) 2026 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 SRC_TRACING_SERVICE_TRACE_BUFFER_PROTOVMS_H_
+#define SRC_TRACING_SERVICE_TRACE_BUFFER_PROTOVMS_H_
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include <memory>
+#include <string>
+#include <vector>
+
+// gen_amalgamated expanded: #include "perfetto/base/flat_set.h"
+// gen_amalgamated expanded: #include "perfetto/ext/tracing/core/basic_types.h"
+
+namespace perfetto {
+
+class TracePacket;
+
+namespace protovm {
+class Vm;
+}
+
+// Owns the ProtoVM instances for one trace buffer (go/perfetto-proto-vm).
+// When the buffer is about to overwrite a packet, it passes the packet to
+// MaybeProcessOverwrittenPacket() to merge it into a ProtoVM's incremental
+// state. The service emits this state when it reads the buffer.
+//
+// The buffer decides which packets to pass here. They must be length-delimited
+// protobuf and arrive in write order within each packet sequence.
+class TraceBufferProtoVms {
+ public:
+ // A ProtoVM instance and the producers whose packets it processes.
+ struct Vm {
+ Vm();
+ ~Vm();
+ Vm(Vm&&) noexcept;
+
+ Vm CloneReadOnly() const;
+
+ std::unique_ptr<protovm::Vm> instance;
+ std::string data_source_name;
+ uint64_t program_hash = 0;
+ uint32_t memory_limit_kb = 0;
+ base::FlatSet<ProducerID> producers;
+ };
+
+ TraceBufferProtoVms();
+ ~TraceBufferProtoVms();
+
+ TraceBufferProtoVms(const TraceBufferProtoVms&) = delete;
+ TraceBufferProtoVms& operator=(const TraceBufferProtoVms&) = delete;
+
+ // Adds |producer_id| to the ProtoVM that runs |program_bytes| for
+ // |data_source_name|. Creates that ProtoVM if it does not exist.
+ void MaybeSetUp(const std::string& data_source_name,
+ const std::string& program_bytes,
+ uint32_t memory_limit_kb,
+ ProducerID producer_id);
+
+ // Tries each ProtoVM registered for |producer| until ApplyPatch() succeeds.
+ // Does nothing if the producer has no ProtoVM.
+ void MaybeProcessOverwrittenPacket(const TracePacket&, ProducerID producer);
+
+ // Replaces this object's instances with read-only clones from |src|.
+ // If any clone fails, clears all instances from this object.
+ void CloneReadOnlyFrom(const TraceBufferProtoVms& src);
+
+ bool HasProducer(ProducerID) const;
+ size_t GetMemoryUsageBytes() const;
+
+ bool empty() const { return vms_.empty(); }
+ const std::vector<Vm>& instances() const { return vms_; }
+
+ private:
+ std::vector<Vm> vms_;
+
+ // Contiguous storage for a packet's slices, as required by ProtoVM's
+ // protozero decoder. We reuse it across packets and only allocate when
+ // it needs to grow.
+ std::string patch_;
+};
+
+} // namespace perfetto
+
+#endif // SRC_TRACING_SERVICE_TRACE_BUFFER_PROTOVMS_H_
+/*
+ * Copyright (C) 2026 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.
+ */
+
+// gen_amalgamated expanded: #include "src/tracing/service/trace_buffer_protovms.h"
+
+#include <algorithm>
+#include <utility>
+
+// gen_amalgamated expanded: #include "perfetto/base/logging.h"
+// gen_amalgamated expanded: #include "perfetto/ext/base/murmur_hash.h"
+// gen_amalgamated expanded: #include "perfetto/ext/base/string_utils.h"
+// gen_amalgamated expanded: #include "perfetto/ext/tracing/core/trace_packet.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/field.h"
+// gen_amalgamated expanded: #include "src/protovm/vm.h"
+
+namespace perfetto {
+
+TraceBufferProtoVms::Vm::Vm() = default;
+TraceBufferProtoVms::Vm::~Vm() = default;
+TraceBufferProtoVms::Vm::Vm(Vm&&) noexcept = default;
+
+TraceBufferProtoVms::Vm TraceBufferProtoVms::Vm::CloneReadOnly() const {
+ Vm cloned_vm;
+ cloned_vm.data_source_name = data_source_name;
+ cloned_vm.program_hash = program_hash;
+ cloned_vm.memory_limit_kb = memory_limit_kb;
+ cloned_vm.producers = producers;
+ cloned_vm.instance = instance->CloneReadOnly();
+ return cloned_vm;
+}
+
+TraceBufferProtoVms::TraceBufferProtoVms() = default;
+TraceBufferProtoVms::~TraceBufferProtoVms() = default;
+
+void TraceBufferProtoVms::MaybeSetUp(const std::string& data_source_name,
+ const std::string& program_bytes,
+ uint32_t memory_limit_kb,
+ ProducerID producer_id) {
+ Vm* vm = nullptr;
+ // Re-use existing ProtoVM instance, if any.
+ uint64_t program_hash = base::MurmurHashValue(program_bytes);
+ auto vm_it = std::find_if(vms_.begin(), vms_.end(), [&](const Vm& other) {
+ return other.data_source_name == data_source_name &&
+ other.program_hash == program_hash;
+ });
+ if (vm_it != vms_.end()) {
+ vm = &(*vm_it);
+ } else {
+ // Otherwise instantiate new ProtoVM
+ Vm new_vm;
+ new_vm.data_source_name = data_source_name;
+ new_vm.program_hash = program_hash;
+ new_vm.memory_limit_kb = memory_limit_kb;
+
+ protozero::ConstBytes program_bytes_view{
+ reinterpret_cast<const uint8_t*>(program_bytes.data()),
+ program_bytes.size()};
+
+ new_vm.instance = std::make_unique<protovm::Vm>(
+ program_bytes_view, new_vm.memory_limit_kb * 1024);
+ if (!new_vm.instance) {
+ PERFETTO_ELOG("Failed to allocate ProtoVM");
+ return;
+ }
+
+ vms_.push_back(std::move(new_vm));
+ vm = &vms_.back();
+ }
+ // Update ProtoVM's producer IDs
+ vm->producers.insert(producer_id);
+}
+
+void TraceBufferProtoVms::MaybeProcessOverwrittenPacket(
+ const TracePacket& packet,
+ ProducerID producer) {
+ patch_.clear();
+
+ for (auto& vm : vms_) {
+ if (vm.producers.find(producer) == vm.producers.end()) {
+ continue;
+ }
+ // TODO(keanmariotti): add an optimized path for the case
+ // "packet.slices().size() == 1" (zero copy)
+ if (patch_.empty()) {
+ packet.GetRawBytes(&patch_);
+ }
+ protozero::ConstBytes bytes{reinterpret_cast<const uint8_t*>(patch_.data()),
+ patch_.size()};
+ auto status = vm.instance->ApplyPatch(bytes);
+ if (status.IsOk()) {
+ break;
+ }
+ if (status.IsAbort()) {
+ // TODO(keanmariotti): consider doing something more here. Ideally
+ // triggering a field upload containing the stacktrace.
+ PERFETTO_ELOG("ProtoVM abort while applying patch. Stacktrace:\n%s",
+ base::Join(status.stacktrace(), "\n").c_str());
+ }
+ }
+}
+
+void TraceBufferProtoVms::CloneReadOnlyFrom(const TraceBufferProtoVms& src) {
+ vms_.clear();
+ for (const auto& vm : src.vms_) {
+ auto vm_cloned = vm.CloneReadOnly();
+ if (!vm_cloned.instance) {
+ PERFETTO_ELOG("Failed to clone ProtoVMs");
+ vms_.clear();
+ break;
+ }
+ vms_.push_back(std::move(vm_cloned));
+ }
+}
+
+bool TraceBufferProtoVms::HasProducer(ProducerID producer) const {
+ return std::any_of(vms_.begin(), vms_.end(), [&](const Vm& vm) {
+ return vm.producers.count(producer) != 0;
+ });
+}
+
+size_t TraceBufferProtoVms::GetMemoryUsageBytes() const {
+ size_t total_bytes = 0;
+ for (const Vm& vm : vms_)
+ total_bytes += vm.instance->GetMemoryUsageBytes();
+ return total_bytes;
+}
+
+} // namespace perfetto
+// gen_amalgamated begin source: src/tracing/service/trace_buffer_v1.cc
+// gen_amalgamated begin header: src/tracing/service/trace_buffer_v1.h
/*
* Copyright (C) 2018 The Android Open Source Project
*
@@ -61013,6 +69590,21 @@ class TraceBufferV1 : public TraceBuffer {
size_t patches_size,
bool other_patches_pending) override;
+ // Returns false as TraceBufferV1 only accepts SMB v1 chunks.
+ bool supports_tracing_v2() const override;
+
+ // Returns false without changing the buffer or its statistics.
+ bool CopyChunkV2Untrusted(const PacketSequenceProperties&,
+ const protozero::ConstBytes* fragments,
+ size_t num_fragments,
+ bool first_continues_from_prev,
+ bool last_continues_on_next) override;
+
+ // No-op because TraceBufferV1 holds no SMB v2 state.
+ void RecordChunkV2DataLoss(ProducerID, WriterID) override;
+
+ void RecordAbiViolation() override;
+
// To read the contents of the buffer the caller needs to:
// BeginRead()
// while (ReadNextTracePacket(packet_fragments)) { ... }
@@ -61054,11 +69646,17 @@ class TraceBufferV1 : public TraceBuffer {
PacketSequenceProperties* sequence_properties,
uint32_t* previous_packet_on_sequence_dropped) override;
+ // No-op. TraceBufferV1 does not compact its buffer.
+ void MaybeCompact() override;
+
// Creates a read-only clone of the trace buffer. Calls to
// CopyChunkUntrusted() and TryPatchChunkContents() on the returned cloned
// TraceBuffer will CHECK().
std::unique_ptr<TraceBuffer> CloneReadOnly() const override;
+ // Returns nullptr because TraceBufferV1 cannot run a ProtoVM.
+ TraceBufferProtoVms* protovms() override;
+
void set_read_only() override { read_only_ = true; }
const TraceStats::BufferStats& stats() const override { return stats_; }
const WriterStats& writer_stats() const override { return writer_stats_; }
@@ -61984,6 +70582,24 @@ bool TraceBufferV1::TryPatchChunkContents(ProducerID producer_id,
return true;
}
+bool TraceBufferV1::supports_tracing_v2() const {
+ return false;
+}
+
+bool TraceBufferV1::CopyChunkV2Untrusted(const PacketSequenceProperties&,
+ const protozero::ConstBytes*,
+ size_t,
+ bool,
+ bool) {
+ return false;
+}
+
+void TraceBufferV1::RecordChunkV2DataLoss(ProducerID, WriterID) {}
+
+void TraceBufferV1::RecordAbiViolation() {
+ stats_.set_abi_violations(stats_.abi_violations() + 1);
+}
+
void TraceBufferV1::BeginRead() {
read_iter_ = GetReadIterForSequence(index_.begin());
#if PERFETTO_DCHECK_IS_ON()
@@ -62247,6 +70863,8 @@ bool TraceBufferV1::ReadNextTracePacket(
} // for(;;MoveNext()) [iterate over chunks].
}
+void TraceBufferV1::MaybeCompact() {}
+
TraceBufferV1::ReadAheadResult TraceBufferV1::ReadAhead(TracePacket* packet) {
static_assert(static_cast<ChunkID>(kMaxChunkID + 1) == 0,
"relying on kMaxChunkID to wrap naturally");
@@ -62433,6 +71051,10 @@ std::unique_ptr<TraceBuffer> TraceBufferV1::CloneReadOnly() const {
return buf;
}
+TraceBufferProtoVms* TraceBufferV1::protovms() {
+ return nullptr;
+}
+
TraceBufferV1::TraceBufferV1(CloneCtor, const TraceBufferV1& src)
: overwrite_policy_(src.overwrite_policy_),
read_only_(true),
@@ -62876,203 +71498,6 @@ class CircularQueue {
} // namespace perfetto
#endif // INCLUDE_PERFETTO_EXT_BASE_CIRCULAR_QUEUE_H_
-// gen_amalgamated begin header: include/perfetto/ext/base/small_vector.h
-/*
- * Copyright (C) 2021 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_SMALL_VECTOR_H_
-#define INCLUDE_PERFETTO_EXT_BASE_SMALL_VECTOR_H_
-
-#include <algorithm>
-#include <type_traits>
-#include <utility>
-
-// gen_amalgamated expanded: #include "perfetto/base/compiler.h"
-// gen_amalgamated expanded: #include "perfetto/base/logging.h"
-// gen_amalgamated expanded: #include "perfetto/ext/base/utils.h"
-
-namespace perfetto {
-namespace base {
-
-// Uses inline storage first, switches to dynamic storage when it overflows.
-template <typename T, size_t kSize>
-class SmallVector {
- public:
- static constexpr size_t kInlineSize = kSize;
-
- explicit SmallVector() = default;
-
- ~SmallVector() {
- clear();
- if (PERFETTO_UNLIKELY(is_using_heap()))
- AlignedFree(begin_);
- begin_ = end_ = end_of_storage_ = nullptr;
- }
-
- // Move operators.
- SmallVector(SmallVector&& other) noexcept(
- std::is_nothrow_move_constructible<T>::value) {
- if (other.is_using_heap()) {
- // Move the heap content, no need to move the individual objects as their
- // location won't change.
- begin_ = other.begin_;
- end_ = other.end_;
- end_of_storage_ = other.end_of_storage_;
- } else {
- const size_t other_size = other.size();
- PERFETTO_DCHECK(other_size <= capacity());
- for (size_t i = 0; i < other_size; i++) {
- // Move the entries and destroy the ones in the moved-from object.
- new (&begin_[i]) T(std::move(other.begin_[i]));
- other.begin_[i].~T();
- }
- end_ = begin_ + other_size;
- }
- auto* const other_inline_storage = other.inline_storage_begin();
- other.end_ = other.begin_ = other_inline_storage;
- other.end_of_storage_ = other_inline_storage + kInlineSize;
- }
-
- SmallVector& operator=(SmallVector&& other) noexcept(
- std::is_nothrow_move_constructible<T>::value) {
- this->~SmallVector();
- new (this) SmallVector<T, kSize>(std::move(other));
- return *this;
- }
-
- // Copy operators.
- SmallVector(const SmallVector& other) {
- const size_t other_size = other.size();
- if (other_size > capacity())
- Grow(other_size);
- // Copy-construct the elements.
- for (size_t i = 0; i < other_size; ++i)
- new (&begin_[i]) T(other.begin_[i]);
- end_ = begin_ + other_size;
- }
-
- SmallVector& operator=(const SmallVector& other) {
- if (PERFETTO_UNLIKELY(this == &other))
- return *this;
- this->~SmallVector();
- new (this) SmallVector<T, kSize>(other);
- return *this;
- }
-
- T* data() { return begin_; }
- const T* data() const { return begin_; }
-
- T* begin() { return begin_; }
- const T* begin() const { return begin_; }
-
- T* end() { return end_; }
- const T* end() const { return end_; }
-
- size_t size() const { return static_cast<size_t>(end_ - begin_); }
-
- bool empty() const { return end_ == begin_; }
-
- size_t capacity() const {
- return static_cast<size_t>(end_of_storage_ - begin_);
- }
-
- T& front() {
- PERFETTO_DCHECK(!empty());
- return begin_[0];
- }
- const T& front() const {
- PERFETTO_DCHECK(!empty());
- return begin_[0];
- }
-
- T& back() {
- PERFETTO_DCHECK(!empty());
- return end_[-1];
- }
- const T& back() const {
- PERFETTO_DCHECK(!empty());
- return end_[-1];
- }
-
- T& operator[](size_t index) {
- PERFETTO_DCHECK(index < size());
- return begin_[index];
- }
-
- const T& operator[](size_t index) const {
- PERFETTO_DCHECK(index < size());
- return begin_[index];
- }
-
- template <typename... Args>
- void emplace_back(Args&&... args) {
- T* end = end_;
- if (PERFETTO_UNLIKELY(end == end_of_storage_))
- end = Grow();
- new (end) T(std::forward<Args>(args)...);
- end_ = end + 1;
- }
-
- void pop_back() {
- PERFETTO_DCHECK(!empty());
- back().~T();
- --end_;
- }
-
- // Clear without reverting back to inline storage.
- void clear() {
- while (!empty())
- pop_back();
- }
-
- private:
- PERFETTO_NO_INLINE T* Grow(size_t desired_capacity = 0) {
- size_t cur_size = size();
- size_t new_capacity = desired_capacity;
- if (desired_capacity <= cur_size)
- new_capacity = std::max(capacity() * 2, size_t(128));
- T* new_storage =
- static_cast<T*>(AlignedAlloc(alignof(T), new_capacity * sizeof(T)));
- for (size_t i = 0; i < cur_size; ++i) {
- // Move the elements into the new heap buffer and destroy the old ones.
- new (&new_storage[i]) T(std::move(begin_[i]));
- begin_[i].~T();
- }
- if (is_using_heap())
- AlignedFree(begin_);
- begin_ = new_storage;
- end_ = new_storage + cur_size;
- end_of_storage_ = new_storage + new_capacity;
- return end_;
- }
-
- T* inline_storage_begin() { return reinterpret_cast<T*>(inline_storage_); }
- bool is_using_heap() { return begin_ != inline_storage_begin(); }
-
- T* begin_ = inline_storage_begin();
- T* end_ = begin_;
- T* end_of_storage_ = begin_ + kInlineSize;
-
- alignas(T) char inline_storage_[sizeof(T) * kInlineSize];
-};
-
-} // namespace base
-} // namespace perfetto
-
-#endif // INCLUDE_PERFETTO_EXT_BASE_SMALL_VECTOR_H_
/*
* Copyright (C) 2025 The Android Open Source Project
*
@@ -63098,8 +71523,8 @@ class SmallVector {
#include <limits>
#include <optional>
#include <unordered_map>
+#include <vector>
-// gen_amalgamated expanded: #include "perfetto/base/flat_set.h"
// gen_amalgamated expanded: #include "perfetto/base/logging.h"
// gen_amalgamated expanded: #include "perfetto/ext/base/circular_queue.h"
// gen_amalgamated expanded: #include "perfetto/ext/base/flat_hash_map.h"
@@ -63112,18 +71537,17 @@ class SmallVector {
// gen_amalgamated expanded: #include "perfetto/ext/tracing/core/slice.h"
// gen_amalgamated expanded: #include "perfetto/ext/tracing/core/trace_packet.h"
// gen_amalgamated expanded: #include "perfetto/ext/tracing/core/trace_stats.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/field.h"
// gen_amalgamated expanded: #include "src/tracing/service/histogram.h"
+// gen_amalgamated expanded: #include "src/tracing/service/proto_group_rewriter.h"
// gen_amalgamated expanded: #include "src/tracing/service/trace_buffer.h"
+// gen_amalgamated expanded: #include "src/tracing/service/trace_buffer_protovms.h"
namespace perfetto {
class TracePacket;
class TraceBufferV2;
-namespace protovm {
-class Vm;
-}
-
namespace internal {
// See /docs/design-docs/trace-buffer.md for details about the design and
@@ -63132,8 +71556,8 @@ namespace internal {
// +---------------------------------------------------------------------------+
// | TBChunk |
// +---------------------------------------------------------------------------+
-// TBChunk is the struct, stored in the trace buffer memory as a result of
-// calling CopyChunkUntrusted from a SMB chunk.
+// TBChunk stores fragments copied into the trace buffer, either from SMB chunks
+// by CopyChunkUntrusted() or from the newer SMB v2 by CopyChunkV2Untrusted().
// TBChunk exists only in the TraceBuffer PagedMemory `data_`, never on the
// stack or on the heap. It is followed by the fragments and alignment padding.
// A TBChunk is very similar to a SMB chunk with the following caveats:
@@ -63161,6 +71585,7 @@ struct TBChunk {
}
// The ChunkID, as specified by the TraceWriter in the original SMB chunk.
+ // Unused for SMB v2 sequences, whose chunks are appended in order.
ChunkID chunk_id = 0;
// A combination of producer and writer ID. This forms the primary key to
@@ -63186,9 +71611,10 @@ struct TBChunk {
// unconsumed fragment header (the varint with the size).
uint16_t payload_avail = 0;
- // These are == the SharedMemoryABI's chunk flags, with the addition of
- // MSB flags added by TraceBufferV2 like kChunkIncomplete (0x80) which doesn't
- // exist at the ABI level, but are synthesized here.
+ // SharedMemoryABI chunk flags, with additional bits set by TraceBufferV2:
+ // kChunkIncomplete (0x80) for scraped chunks and kChunkLossBefore (0x40) for
+ // a gap before an SMB v2 chunk. These additional bits never come from
+ // the producer.
uint8_t flags = 0;
// This is used for (D)CHECKS to verify the integrity of the chunk.
@@ -63272,11 +71698,38 @@ struct SequenceState {
// copies it into previous_packet_dropped and resets it. Zero means no loss.
uint32_t data_loss_reasons = 0;
- // An ordered list of chunk offsets, sorted by their ChunkID. Each member
- // corresponsds to the offset within buf_ for the chunk.
+ // An ordered list of chunk offsets, sorted by ChunkID for SMB sequences or
+ // by append order for SMB v2 sequences.
// We store buffer offsets rather than pointers to make buffer cloning easier.
// This is effectively a deque of TBChunk* (% a call to GetTBChunkAt(off)).
base::CircularQueue<size_t> chunks;
+
+ // All chunks of a sequence use the same format: either the legacy SMB v1 or
+ // the newer proto-group based SMB v2. SMB v2 chunks are immutable, arrive in
+ // order and need rewriting at readback.
+ bool is_smb_v2 = false;
+
+ // A gap after the last appended SMB v2 chunk, not yet stamped on a
+ // chunk.
+ // - SMB sequences need no such state. A gap shows up as a non-successor
+ // ChunkID, so the reader finds it at the right position by itself.
+ // - SMB v2 chunks have no ChunkID. The gap must be recorded when it
+ // happens, at the position between two chunks.
+ // - data_loss_reasons cannot hold it. The reader reports that on the next
+ // packet it reads, which can be an older packet buffered before the gap.
+ // The next append moves this flag to kChunkLossBefore on its chunk. The
+ // reader then reports the loss on the first packet after the gap.
+ //
+ // Example for one writer:
+ //
+ // Step Buffer pending_chunk_v2_data_loss
+ // Append(A) [A] false
+ // RecordChunkV2DataLoss() [A] true
+ // Append(C) [A] [C*] false, moved to C as *
+ //
+ // * = kChunkLossBefore. A read returns A with no loss, then C with
+ // DATA_LOSS_READ_GAP.
+ bool pending_chunk_v2_data_loss = false;
};
// +---------------------------------------------------------------------------+
@@ -63464,6 +71917,10 @@ class ChunkSeqReader {
// +---------------------------------------------------------------------------+
// | TraceBufferV2 |
// +---------------------------------------------------------------------------+
+// TODO(b/559531402): Rename trace_buffer_v1 to trace_buffer_legacy
+// (TraceBufferLegacy), and trace_buffer_v2 to trace_buffer_impl
+// (TraceBufferImpl). The "v2" here is easy to confuse with tracing v2 (the
+// SMB v2 transport), which this buffer also stores.
class TraceBufferV2 : public TraceBuffer {
public:
using TBChunk = internal::TBChunk;
@@ -63471,20 +71928,6 @@ class TraceBufferV2 : public TraceBuffer {
using Patch = TraceBuffer::Patch;
using PacketSequenceProperties = TraceBuffer::PacketSequenceProperties;
- // Represents a ProtoVM instance and some metadata
- struct Vm {
- Vm();
- ~Vm();
- Vm(Vm&&) noexcept;
- Vm CloneReadOnly() const;
-
- std::unique_ptr<protovm::Vm> instance;
- std::string data_source_name;
- uint64_t program_hash = 0;
- uint32_t memory_limit_kb = 0;
- base::FlatSet<ProducerID> producers;
- };
-
// Can return nullptr if the memory allocation fails.
static std::unique_ptr<TraceBufferV2> Create(size_t size_in_bytes,
OverwritePolicy = kOverwrite);
@@ -63540,12 +71983,34 @@ class TraceBufferV2 : public TraceBuffer {
size_t patches_size,
bool other_patches_pending) override;
- void MaybeSetUpProtoVm(const std::string& data_source_name,
- const std::string& program_bytes,
- uint32_t memory_limit_kb,
- ProducerID producer_id);
+ // Returns true. Both SMB v1 and SMB v2 writers can use this buffer, but each
+ // {ProducerID, WriterID} sequence must use one format throughout its
+ // lifetime.
+ bool supports_tracing_v2() const override;
- const std::vector<Vm>& GetProtoVmInstances() const { return protovms_; }
+ // Stores the batch in one TBChunk. See TraceBuffer::CopyChunkV2Untrusted()
+ // for ownership, ordering, continuation flags and loss reporting.
+ //
+ // Invalid input increments abi_violations. This includes a null fragment
+ // array, a nonempty fragment with a null payload, a batch larger than one
+ // TBChunk or than the whole buffer, or a writer ID whose sequence already
+ // holds SMB v1 chunks.
+ //
+ // Rejection because a kDiscard buffer is full or the producer has a ProtoVM
+ // on this buffer increments chunks_discarded. Once a kDiscard buffer stops
+ // accepting writes, it rejects later batches without validating their input.
+ bool CopyChunkV2Untrusted(const PacketSequenceProperties& sequence,
+ const protozero::ConstBytes* fragments,
+ size_t num_fragments,
+ bool first_continues_from_prev,
+ bool last_continues_on_next) override;
+
+ // Keeps the gap in the writer's SequenceState until the next stored batch
+ // carries it as kChunkLossBefore. If DeleteStaleEmptySequences() prunes the
+ // state before another batch arrives, the pending gap is forgotten.
+ void RecordChunkV2DataLoss(ProducerID, WriterID) override;
+
+ void RecordAbiViolation() override;
// To read the contents of the buffer the caller needs to:
// BeginRead()
@@ -63556,13 +72021,18 @@ class TraceBufferV2 : public TraceBuffer {
void BeginRead() override;
// Returns the next packet in the buffer, if any, and the producer/writer
- // identity that wrote it (as passed in the CopyChunkUntrusted() call).
+ // identity supplied when the sequence was created.
// Returns false if no packets can be read at this point.
// If a packet was read successfully, |previous_packet_on_sequence_dropped|
// signals whether any data loss has been detected on the sequence
// (e.g. because its chunk was overridden due to the ring buffer wrapping or
// due to an ABI violation), and to |false| otherwise.
//
+ // SMB v2 packets are reassembled and rewritten to length-delimited
+ // protobuf. Malformed packets and packets that length-delimited protobuf
+ // cannot encode are dropped, with loss reported on the next readable packet
+ // in the sequence.
+ //
// This function returns only complete packets. Specifically:
// When there is at least one complete packet in the buffer, this function
// returns true and populates the TracePacket argument with the boundaries of
@@ -63587,22 +72057,38 @@ class TraceBufferV2 : public TraceBuffer {
PacketSequenceProperties* sequence_properties,
uint32_t* previous_packet_on_sequence_dropped) override;
+ // Compacts the buffer by moving live chunks to the front in ring order.
+ // It clears the unused tail and retains pages for the old |used_size_| plus
+ // 1/|kSpareCapacityDivisor| of it, capped at the buffer size.
+ // It advises the OS to release the whole pages after that range.
+ // If live chunks are on both sides of the write cursor, it skips compaction.
+ //
+ // Compaction can invalidate packet slices from earlier reads, so the caller
+ // must not use those packets after MaybeCompact().
+ //
+ // This is a no-op if the buffer is read-only or if it is a kDiscard buffer.
+ void MaybeCompact() override;
+
// Creates a read-only clone of the trace buffer. The read iterators of the
- // new buffer will be reset, as if no Read() had been called. Calls to
- // CopyChunkUntrusted() and TryPatchChunkContents() on the returned cloned
- // TraceBuffer will CHECK().
+ // new buffer will be reset.
+ //
+ // Calls to CopyChunkUntrusted(), CopyChunkV2Untrusted(),
+ // TryPatchChunkContents(), RecordChunkV2DataLoss() or RecordAbiViolation()
+ // on the returned clone will CHECK().
std::unique_ptr<TraceBuffer> CloneReadOnly() const override;
+ TraceBufferProtoVms* protovms() override;
+
+ void set_read_only() override { read_only_ = true; }
+ const TraceStats::BufferStats& stats() const override { return stats_; }
+ const WriterStats& writer_stats() const override { return writer_stats_; }
size_t size() const override { return size_; }
size_t used_size() const override { return used_size_; }
size_t GetMemoryUsageBytes() const override;
OverwritePolicy overwrite_policy() const override {
return overwrite_policy_;
}
- const TraceStats::BufferStats& stats() const override { return stats_; }
- const WriterStats& writer_stats() const override { return writer_stats_; }
- bool has_data() const override { return used_size_ > 0; }
- void set_read_only() override { read_only_ = true; }
+ bool has_data() const override { return has_data_; }
BufType buf_type() const override { return kV2; }
void DumpForTesting();
@@ -63627,14 +72113,29 @@ class TraceBufferV2 : public TraceBuffer {
bool Initialize(size_t size);
TBChunk* CreateTBChunk(size_t off, size_t payload_size);
+
+ // Prepares contiguous storage at wr_. The caller checks that size <= size_.
+ // May evict chunks and wrap. Does not prune sequences or change stats for
+ // rejected writes. Returns false if the write reaches the end of a kDiscard
+ // buffer. The caller then seals the buffer with DiscardWrite().
+ bool MakeSpaceToWrite(size_t size);
void DeleteNextChunksFor(size_t bytes_to_clear);
+ // Makes a reassembled SMB v2 packet length-delimited protobuf. A packet
+ // without nested messages keeps its slices into the buffer, as an SMB
+ // packet does. Otherwise the packet gets one owned slice. Returns false,
+ // leaving the packet unchanged, for:
+ // - malformed input, counted in abi_violations.
+ // - a packet that length-delimited protobuf cannot encode, counted in
+ // oversized_packets_dropped.
+ bool RewriteProtoGroupPacket(TracePacket*);
+
void DcheckIsAlignedAndWithinBounds(size_t off) const {
PERFETTO_DCHECK((off & (alignof(TBChunk) - 1)) == 0);
PERFETTO_DCHECK(off <= size_ - sizeof(TBChunk));
}
- // This should only be used when followed by a placement new.
+ // Used for placement new and to update the checksum after moving a chunk.
TBChunk* GetTBChunkAtUnchecked(size_t off) {
DcheckIsAlignedAndWithinBounds(off);
return reinterpret_cast<TBChunk*>(begin() + off);
@@ -63665,7 +72166,6 @@ class TraceBufferV2 : public TraceBuffer {
void DiscardWrite();
void DeleteStaleEmptySequences();
- void MaybeProcessOverwrittenPacketWithProtoVm(const TracePacket&, ProducerID);
uint8_t* begin() const { return reinterpret_cast<uint8_t*>(data_.Get()); }
uint8_t* end() const { return begin() + size_; }
@@ -63674,11 +72174,24 @@ class TraceBufferV2 : public TraceBuffer {
base::PagedMemory data_;
size_t size_ = 0; // Size in bytes of |data_|.
- // High watermark. The number of bytes (<= |size_|) written into the buffer
- // before the first wraparound. This increases as data is written into the
- // buffer and then saturates at |size_|.
+ // High watermark of the written bytes (<= |size_|).
+ // Writes increase it until the write cursor wraps around, and MaybeCompact()
+ // sets it to the total size of the remaining chunks.
+ // Reads and overwrites stop here, and [used_size_, size_) is zero-filled.
size_t used_size_ = 0;
+ // Where the last madvise in MaybeCompact() began.
+ // The whole pages from here to |size_| are released or were never written.
+ // Writes after that can go past it. If they do, the next MaybeCompact() first
+ // raises it to |used_size_|, to cover the pages they touched.
+ // MaybeCompact() then uses it to skip a madvise that would release nothing.
+ size_t prev_madvise_begin_ = 0;
+
+ // Set when the first chunk is written, and never cleared.
+ // Unlike |used_size_|, this stays set when compaction empties the buffer.
+ // As in TraceBufferV1, clear_before_clone uses it to skip unused buffers.
+ bool has_data_ = false;
+
size_t wr_ = 0; // Write cursor (offset since start()).
size_t rd_ = 0; // Read cursor. Reset to wr_ on every BeginRead().
std::optional<ChunkSeqReader> chunk_seq_reader_;
@@ -63706,8 +72219,8 @@ class TraceBufferV2 : public TraceBuffer {
// This is used to sort SequenceState by least-recently cleared.
uint64_t seq_age_ = 0;
- // This buffer is a read-only snapshot obtained via Clone(). If this is true
- // calls to CopyChunkUntrusted() and TryPatchChunkContents() will CHECK().
+ // This buffer is a read-only snapshot obtained via Clone(). If this is true,
+ // appending chunks, patching or recording loss will CHECK().
bool read_only_ = false;
// Only used when |overwrite_policy_ == kDiscard|. This is set the first time
@@ -63720,7 +72233,7 @@ class TraceBufferV2 : public TraceBuffer {
bool suppress_client_dchecks_for_testing_ = false;
// ProtoVMs used to process overwritten packets (go/perfetto-proto-vm)
- std::vector<Vm> protovms_;
+ TraceBufferProtoVms protovms_;
// Used to collect slices of the overwritten packet. Note that this is a
// member variable (instead of local) so that the memory (internal
@@ -63729,12 +72242,8 @@ class TraceBufferV2 : public TraceBuffer {
// few times during the initial iterations).
TracePacket overwritten_packet_;
- // Storage used to re-write overwritten packets (from TBv2) into contiguous
- // memory to be used as ProtoVM patches (must be continguous to be decoded
- // with protozero). Note that this is a member variable (instead of local) so
- // that the memory is re-used across overwritten packets, thus involving
- // allocations only when the storage needs to be expanded.
- std::string protovm_patch_;
+ // Rewrites SMB v2 packets at readback.
+ tracing_v2::ProtoGroupRewriter rewriter_;
};
} // namespace perfetto
@@ -63760,16 +72269,15 @@ class TraceBufferV2 : public TraceBuffer {
#include <algorithm>
#include <memory>
+#include <type_traits>
// gen_amalgamated expanded: #include "perfetto/base/logging.h"
-// gen_amalgamated expanded: #include "perfetto/ext/base/murmur_hash.h"
// gen_amalgamated expanded: #include "perfetto/ext/base/string_utils.h"
// gen_amalgamated expanded: #include "perfetto/ext/base/utils.h"
// gen_amalgamated expanded: #include "perfetto/ext/tracing/core/basic_types.h"
// gen_amalgamated expanded: #include "perfetto/ext/tracing/core/client_identity.h"
// gen_amalgamated expanded: #include "perfetto/ext/tracing/core/shared_memory_abi.h"
// gen_amalgamated expanded: #include "perfetto/protozero/proto_utils.h"
-// gen_amalgamated expanded: #include "src/protovm/vm.h"
// gen_amalgamated expanded: #include "protos/perfetto/trace/trace_packet.pbzero.h"
@@ -63809,6 +72317,11 @@ constexpr uint8_t kChunkIncomplete = 0x80;
// Mask out the flags that don't come from the ABI like kChunkIncomplete.
constexpr uint8_t kFlagsMask = SharedMemoryABI::ChunkHeader::kFlagsMask;
+// SMB v2 sequences have no ChunkID. A gap is recorded on the first chunk
+// appended after the loss, so earlier packets do not inherit the loss marker.
+constexpr uint8_t kChunkLossBefore = 0x40;
+static_assert((kChunkLossBefore & (kFlagsMask | kChunkIncomplete)) == 0);
+
// Compares two ChunkID(s) in a wrapping 32-bit ID space.
// Returns:
// -1 if a comes before b in modular (wrapping) order.
@@ -63830,6 +72343,11 @@ constexpr size_t kKeepLastEmptySeq = 1024;
// The threshold when we start scanning and deleting the oldest sequences.
constexpr size_t kEmptySequencesGcTreshold = kKeepLastEmptySeq + 128;
+
+// Controls how much spare capacity compaction retains so later writes can
+// reuse pages and avoid page faults.
+constexpr size_t kSpareCapacityDivisor = 4;
+
} // namespace.
namespace internal {
@@ -63978,7 +72496,8 @@ TBChunk* ChunkSeqIterator::NextChunkInSequence() {
size_t next_chunk_off = chunk_list.at(next_list_idx); // O(1)
TBChunk* next_chunk = buf_->GetTBChunkAt(next_chunk_off); // O(1)
- if (last_chunk_id.has_value() && next_chunk->chunk_id != *last_chunk_id + 1)
+ if (!seq_->is_smb_v2 && last_chunk_id.has_value() &&
+ next_chunk->chunk_id != *last_chunk_id + 1)
sequence_gap_detected_ = true;
chunk_ = next_chunk;
@@ -64043,6 +72562,9 @@ ChunkSeqReader::ChunkSeqReader(TraceBufferV2* buf,
: 0,
iter_->chunk_id, end_->chunk_id);
+ if (seq_->is_smb_v2)
+ return;
+
if (seq_->last_chunk_consumed.has_value()) {
const auto& last = *seq_->last_chunk_consumed;
// Re-admit: an incomplete chunk that was evicted has been re-committed
@@ -64075,6 +72597,12 @@ bool ChunkSeqReader::ReadNextPacketInSeqOrder(TracePacket* out_packet) {
// This is because this class is used both while doing readbacks and,
// importantly, in DeleteNextChunksFor() when overwriting.
for (;;) {
+ // Report an SMB v2 gap when we reach the chunk after it. Clear the
+ // flag so later packets in this chunk do not report the same gap again.
+ if (PERFETTO_UNLIKELY(iter_->flags & kChunkLossBefore)) {
+ AddSeqDataLoss(seq_, DataLossReason::DATA_LOSS_READ_GAP);
+ iter_->flags &= static_cast<uint8_t>(~kChunkLossBefore);
+ }
std::optional<Frag> maybe_frag = frag_iter_.NextFragmentInChunk();
if (!maybe_frag.has_value()) {
// Once we exhaust all fragments, move to the next chunk in the sequence.
@@ -64255,8 +72783,10 @@ ChunkSeqReader::ReassembleFragmentedPacket(TracePacket* out_packet,
outcome.result = FragReassemblyResult::kNotEnoughData;
break;
}
- if (chunk_iter.sequence_gap_detected()) {
- // There is a gap in the sequence ID.
+ if (PERFETTO_UNLIKELY(chunk_iter.sequence_gap_detected() ||
+ (next_chunk->flags & kChunkLossBefore))) {
+ // SMB sequences detect gaps via chunk_id discontinuity.
+ // SMB v2 sequences use the kChunkLossBefore flag instead.
outcome.result = FragReassemblyResult::kDataLoss;
outcome.reason = DataLossReason::DATA_LOSS_REASSEMBLY_GAP;
break;
@@ -64334,6 +72864,8 @@ std::unique_ptr<TraceBufferV2> TraceBufferV2::Create(size_t size_in_bytes,
// efficiency.
static_assert(sizeof(TBChunk) == 16);
static_assert(alignof(TBChunk) == 4);
+ // CloneReadOnly() and MaybeCompact() copy chunks as raw bytes.
+ static_assert(std::is_trivially_copyable_v<TBChunk>);
std::unique_ptr<TraceBufferV2> trace_buffer(new TraceBufferV2(pol));
if (!trace_buffer->Initialize(size_in_bytes))
return nullptr;
@@ -64413,6 +72945,17 @@ bool TraceBufferV2::ReadNextTracePacket(
// If it returns false, we should continue in buffer order.
if (chunk_seq_reader_->ReadNextPacketInSeqOrder(out_packet)) {
SequenceState& s = *chunk_seq_reader_->seq();
+ if (s.is_smb_v2) {
+ if (out_packet->size() == 0)
+ continue; // Skip empty fragments.
+
+ if (PERFETTO_UNLIKELY(!RewriteProtoGroupPacket(out_packet))) {
+ out_packet->Clear();
+ internal::AddSeqDataLoss(&s,
+ DataLossReason::DATA_LOSS_CHUNK_CORRUPTED);
+ continue;
+ }
+ }
*sequence_properties = {s.producer_id, s.client_identity, s.writer_id};
*previous_packet_on_sequence_dropped = s.data_loss_reasons;
s.data_loss_reasons = 0;
@@ -64437,6 +72980,151 @@ bool TraceBufferV2::ReadNextTracePacket(
} // for(;;)
}
+void TraceBufferV2::MaybeCompact() {
+ TRACE_BUFFER_V2_DLOG("MaybeCompact(), wr_=%zu", wr_);
+ chunk_seq_reader_.reset();
+ if (overwrite_policy_ != kOverwrite || read_only_) {
+ return;
+ }
+
+ // The read cycle is complete, so usually only a few chunks remain.
+ size_t num_chunks = 0;
+ for (const auto& seq_entry : sequences_)
+ num_chunks += seq_entry.second.chunks.size();
+
+ // Store pointers to the chunk offsets in each SequenceState::chunks queue
+ // so we can update those offsets without another lookup.
+ // TODO(sashwinbalaji): Using these queues avoids scanning the buffer but
+ // leaves removed padding unaccounted for in padding_bytes_cleared.
+ std::vector<size_t*> chunk_offset_ptrs;
+ chunk_offset_ptrs.reserve(num_chunks);
+ for (auto& seq_entry : sequences_) {
+ for (size_t& chunk_offset : seq_entry.second.chunks)
+ chunk_offset_ptrs.emplace_back(&chunk_offset);
+ }
+
+ // Sort the pointer vector by chunk offset, from lowest to highest.
+ // This reorders only the vector, so the queue entries stay in sequence order.
+ // The loop below updates each chunk's offset in its original queue entry.
+ std::sort(chunk_offset_ptrs.begin(), chunk_offset_ptrs.end(),
+ [](const size_t* lhs, const size_t* rhs) { return *lhs < *rhs; });
+
+ // If live chunks are on both sides of wr_, skip compaction.
+ // The chunks at or after wr_ are older, so address order is not ring order.
+ //
+ // In this diagram and the ones below:
+ // - [C0], [D0], [C1], ... are live chunks of two sequences, C and D.
+ // The number is the order of the chunk within its sequence.
+ // - "." is padding (read chunks).
+ // - "~" is unused space, past the new used_size_.
+ //
+ // 0 wr_ used_size_
+ // |..[C1]..[D1]..[C2]......|..[C0]....[D0]..........|
+ const bool chunks_on_both_sides = !chunk_offset_ptrs.empty() &&
+ *chunk_offset_ptrs.front() < wr_ &&
+ *chunk_offset_ptrs.back() >= wr_;
+ if (PERFETTO_UNLIKELY(chunks_on_both_sides)) {
+ stats_.set_compactions_skipped(stats_.compactions_skipped() + 1);
+ return;
+ }
+
+ // All live chunks are on one side of wr_, so address order is ring order.
+ // Move each chunk to the lowest available offset, in address order.
+ // Each destination starts at or before its source, so a move cannot
+ // overwrite a chunk that comes later in address order.
+ //
+ // All live chunks are before wr_:
+ //
+ // 0 wr_ used_size_
+ // |.[C0].[D0]..[C1]..[C2]..|........................|
+ //
+ // All live chunks are at or after wr_ because reads consumed every chunk
+ // before wr_ after the write cursor wrapped.
+ //
+ // 0 wr_ used_size_
+ // |........................|.[C0].[D0]..[C1]..[C2]..|
+ //
+ // After compaction:
+ //
+ // 0 dst used_size_
+ // |[C0][D0][C1][C2]|~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~|
+ size_t dst = 0;
+ size_t prev_chunk_end = 0;
+ for (size_t* offset_ptr : chunk_offset_ptrs) {
+ const size_t src = *offset_ptr;
+ TBChunk* chunk = GetTBChunkAt(src);
+ PERFETTO_DCHECK(!chunk->is_padding());
+ const size_t outer_size = chunk->outer_size();
+ PERFETTO_CHECK(src >= prev_chunk_end);
+ prev_chunk_end = src + outer_size;
+ if (dst != src) {
+ memmove(begin() + dst, chunk, outer_size);
+ *offset_ptr = dst;
+ TBChunk* moved_chunk = GetTBChunkAtUnchecked(dst);
+ moved_chunk->checksum = TBChunk::Checksum(dst, moved_chunk->size);
+ }
+ dst += outer_size;
+ }
+
+ TRACE_BUFFER_V2_DLOG("Compacted %zu -> %zu bytes", used_size_, dst);
+ const size_t old_used_size = used_size_;
+ PERFETTO_CHECK(dst <= old_used_size && old_used_size <= size_);
+ wr_ = dst;
+ used_size_ = dst;
+
+ // Bytes beyond |old_used_size| are zero from allocation or earlier
+ // compactions.
+ // Clear [dst, old_used_size) on each compaction so the unused tail stays zero
+ // even when used_size_ shrinks.
+ // ReadNextTracePacket() visits offset 0 even when the buffer is empty and so
+ // if dst == 0, this also leaves the empty padding chunk that it needs.
+ memset(begin() + dst, 0, old_used_size - dst);
+
+ const size_t spare_size =
+ std::min(old_used_size / kSpareCapacityDivisor, size_ - old_used_size);
+ const size_t cur_madvise_begin = old_used_size + spare_size;
+
+ // Writes since the last compaction touched pages up to |old_used_size|.
+ prev_madvise_begin_ = std::max(prev_madvise_begin_, old_used_size);
+
+ // Skip the madvise if it starts at or past |prev_madvise_begin_|, because
+ // the pages from there on are already released.
+ if (cur_madvise_begin < prev_madvise_begin_) {
+ data_.AdviseDontNeedAfter(cur_madvise_begin);
+ prev_madvise_begin_ = cur_madvise_begin;
+ }
+ stats_.set_compactions(stats_.compactions() + 1);
+}
+
+bool TraceBufferV2::RewriteProtoGroupPacket(TracePacket* packet) {
+ PERFETTO_DCHECK(packet->size() > 0);
+
+ // The packet's slices point into TBChunks. The rewriter reads them in
+ // place, and writes the output into one slice that the packet owns.
+ //
+ // TODO(sashwinbalaji): Allocate the rewritten packets from an arena owned by
+ // the read batch. Today each rewritten packet is one heap allocation.
+ // Readers use packets in batches (an IPC reply or a file write) and drop
+ // them together, so one arena per batch fits their lifetime.
+ std::optional<Slice> rewritten;
+ switch (rewriter_.Rewrite(packet->slices(), &rewritten)) {
+ case tracing_v2::RewriteResult::kRewritten:
+ break;
+ case tracing_v2::RewriteResult::kUnchanged:
+ return true;
+ case tracing_v2::RewriteResult::kMalformedInput:
+ stats_.set_abi_violations(stats_.abi_violations() + 1);
+ return false;
+ case tracing_v2::RewriteResult::kGroupTooLarge:
+ stats_.set_oversized_packets_dropped(stats_.oversized_packets_dropped() +
+ 1);
+ return false;
+ }
+ packet->Clear();
+ packet->AddSlice(std::move(*rewritten));
+ return true;
+}
+
void TraceBufferV2::CopyChunkUntrusted(
ProducerID producer_id_trusted,
const ClientIdentity& client_identity_trusted,
@@ -64457,6 +73145,10 @@ void TraceBufferV2::CopyChunkUntrusted(
if (PERFETTO_UNLIKELY(discard_writes_))
return DiscardWrite();
+ // Only ABI flags may come from the producer. In particular, loss markers
+ // and the incomplete-chunk flag are set by the service.
+ chunk_flags &= kFlagsMask;
+
// chunk_complete is true in the majority of cases, and is false only when
// the service performs SMB scraping (upon flush).
// If the chunk hasn't been completed, we should only consider the first
@@ -64528,6 +73220,13 @@ void TraceBufferV2::CopyChunkUntrusted(
}
SequenceState& seq = seq_it->second;
+ // A sequence uses one input format. SMB v1 and SMB v2 writers share one
+ // WriterID space per producer, so an SMB v2 sequence with this key
+ // belongs to another writer. Leave that writer's sequence unchanged.
+ if (seq.is_smb_v2) {
+ stats_.set_abi_violations(stats_.abi_violations() + 1);
+ return;
+ }
if (trace_writer_data_drop) {
stats_.set_trace_writer_packet_loss(stats_.trace_writer_packet_loss() + 1);
internal::AddSeqDataLoss(&seq, DataLossReason::DATA_LOSS_WRITER_ABORT);
@@ -64619,9 +73318,10 @@ void TraceBufferV2::CopyChunkUntrusted(
// Nothing for the erase to lose, nothing for the relocation to duplicate.
const bool copy_fully_consumed = recommit_chunk->payload_avail == 0;
- // The producer's final commit (not another scrape), with new fragments.
+ // Any re-commit with new fragments, whether the producer's final commit or
+ // a later scrape of the same still-open chunk.
const bool commit_adds_new_data =
- chunk_complete && all_frags_size > recommit_chunk->payload_size;
+ all_frags_size > recommit_chunk->payload_size;
// EraseCurrentChunk() only supports the first chunk of a sequence. Later
// chunks may stay physically ahead of the relocated one, which is fine:
@@ -64668,30 +73368,11 @@ void TraceBufferV2::CopyChunkUntrusted(
internal::ChunkSeqIterator(this, &seq).EraseCurrentChunk();
} // if (recommit_chunk)
- // If there isn't enough room from the given write position: write a padding
- // record to clear the end of the buffer, wrap and start at offset 0.
- const size_t cached_size_to_end = size_to_end();
- if (PERFETTO_UNLIKELY(tbchunk_outer_size > cached_size_to_end)) {
- // If we reached the end of the buffer and we are using discard policy,
- // this is where we stop. This buffer will no longer accept data.
- if (overwrite_policy_ == kDiscard)
- return DiscardWrite();
-
- // Skip the tail cleanup if the previous write landed exactly at the end
- // of the buffer (|wr_| == |size_|): there is no leftover tail to clear.
- if (cached_size_to_end > 0)
- DeleteNextChunksFor(cached_size_to_end);
-
- wr_ = 0;
- stats_.set_write_wrap_count(stats_.write_wrap_count() + 1);
- PERFETTO_DCHECK(size_to_end() >= tbchunk_outer_size);
- }
-
- // Deletes all chunks from |wptr_| to |wptr_| + |record_size|.
- DeleteNextChunksFor(tbchunk_outer_size);
+ if (!MakeSpaceToWrite(tbchunk_outer_size))
+ return DiscardWrite();
// |insert_pos| is invalid if any chunk was removed from this sequence since
- // it was computed: either by the DeleteNextChunksFor above, or by the
+ // it was computed: either by MakeSpaceToWrite() above, or by the
// relocation erase.
// Why don't we compute the insert_pos here? Because we also need to check
// for re-commits (which are rare, but possible) and don't want to iterate
@@ -64722,6 +73403,7 @@ void TraceBufferV2::CopyChunkUntrusted(
stats_.chunks_committed_out_of_order() + 1);
}
chunk_list.InsertAfter(insert_pos, wr_);
+ has_data_ = true;
if (chunk_list.size() == 1 && !seq_is_new) {
PERFETTO_DCHECK(empty_sequences_ > 0);
--empty_sequences_;
@@ -64743,6 +73425,166 @@ void TraceBufferV2::CopyChunkUntrusted(
DeleteStaleEmptySequences();
}
+bool TraceBufferV2::supports_tracing_v2() const {
+ return true;
+}
+
+bool TraceBufferV2::CopyChunkV2Untrusted(
+ const PacketSequenceProperties& sequence,
+ const protozero::ConstBytes* fragments,
+ size_t num_fragments,
+ bool first_continues_from_prev,
+ bool last_continues_on_next) {
+ PERFETTO_CHECK(!read_only_);
+
+ if (PERFETTO_UNLIKELY(num_fragments == 0))
+ return false;
+
+ // Each rejection site updates its own stats. This only records the gap.
+ auto reject = [&] {
+ RecordChunkV2DataLoss(sequence.producer_id_trusted, sequence.writer_id);
+ return false;
+ };
+ auto reject_abi_violation = [&] {
+ stats_.set_abi_violations(stats_.abi_violations() + 1);
+ return reject();
+ };
+
+ if (PERFETTO_UNLIKELY(discard_writes_)) {
+ DiscardWrite();
+ return reject();
+ }
+
+ if (!fragments)
+ return reject_abi_violation();
+
+ // ProtoVM expects length-delimited protobuf on the overwrite path.
+ if (protovms_.HasProducer(sequence.producer_id_trusted)) {
+ stats_.set_chunks_discarded(stats_.chunks_discarded() + 1);
+ return reject();
+ }
+
+ // The batch becomes one TBChunk with the same payload layout as an SMB chunk,
+ // so readback uses FragIterator for both:
+ //
+ // +---------+-----------+--------+-----------+--------+-----+---------+
+ // | TBChunk | varint s0 | frag 0 | varint s1 | frag 1 | ... | padding |
+ // +---------+-----------+--------+-----------+--------+-----+---------+
+ // |<----------- total_payload <= kMaxSize ------->|
+ //
+ // Validate the entire batch before making space: a rejected batch must not
+ // evict any buffered packets. A batch larger than one TBChunk breaks the
+ // writer's chunk contract. Each addend is at most kMaxSize + 3, so
+ // |total_payload| cannot overflow.
+ size_t total_payload = 0;
+ for (size_t i = 0; i < num_fragments; i++) {
+ const size_t frag_size = fragments[i].size;
+ if ((frag_size && !fragments[i].data) || frag_size > TBChunk::kMaxSize)
+ return reject_abi_violation();
+ uint8_t varint[3]; // A varint up to TBChunk::kMaxSize takes 3 bytes.
+ const size_t varint_size = static_cast<size_t>(
+ proto_utils::WriteVarInt(frag_size, varint) - varint);
+ total_payload += varint_size + frag_size;
+ if (total_payload > TBChunk::kMaxSize)
+ return reject_abi_violation();
+ }
+
+ // As in CopyChunkUntrusted(): a chunk larger than the whole buffer. Rare,
+ // e.g. a 16 KB buffer and a 32 KB ring chunk.
+ const size_t tbchunk_outer_size = TBChunk::OuterSize(total_payload);
+ if (PERFETTO_UNLIKELY(tbchunk_outer_size > size_))
+ return reject_abi_violation();
+
+ auto seq_key =
+ MkProducerAndWriterID(sequence.producer_id_trusted, sequence.writer_id);
+ writer_stats_.Insert(seq_key, static_cast<HistValue>(total_payload));
+
+ auto [seq_it, seq_is_new] = sequences_.try_emplace(
+ seq_key, SequenceState(sequence.producer_id_trusted, sequence.writer_id,
+ sequence.client_identity_trusted));
+ SequenceState& seq = seq_it->second;
+ if (seq_is_new) {
+ seq.is_smb_v2 = true;
+ seq.age_for_gc = ++seq_age_;
+ ++empty_sequences_;
+ } else if (!seq.is_smb_v2) {
+ // As in CopyChunkUntrusted(), a sequence uses one input format. The SMB
+ // sequence belongs to another writer, so no loss is recorded on it.
+ return reject_abi_violation();
+ }
+
+ if (!MakeSpaceToWrite(tbchunk_outer_size)) {
+ DiscardWrite();
+ return reject();
+ }
+
+ TBChunk* chunk = CreateTBChunk(wr_, total_payload);
+ chunk->pri_wri_id = seq_key;
+ chunk->payload_size = static_cast<uint16_t>(total_payload);
+ chunk->payload_avail = static_cast<uint16_t>(total_payload);
+
+ uint8_t flags = 0;
+ if (PERFETTO_UNLIKELY(seq.pending_chunk_v2_data_loss)) {
+ flags |= kChunkLossBefore;
+ seq.pending_chunk_v2_data_loss = false;
+ }
+ if (first_continues_from_prev)
+ flags |= kFirstPacketContFromPrevChunk;
+ if (last_continues_on_next)
+ flags |= kLastPacketContOnNextChunk;
+ chunk->flags = flags;
+
+ // Copy fragment data into the chunk payload with varint length prefixes.
+ uint8_t* dst = chunk->fragments_begin();
+ for (size_t i = 0; i < num_fragments; i++) {
+ const size_t frag_size = fragments[i].size;
+ dst = protozero::proto_utils::WriteVarInt(frag_size, dst);
+ if (frag_size > 0) {
+ memcpy(dst, fragments[i].data, frag_size);
+ dst += frag_size;
+ }
+ }
+ PERFETTO_DCHECK(static_cast<size_t>(dst - chunk->fragments_begin()) ==
+ total_payload);
+
+ // Append after eviction, which can remove earlier chunks from this sequence.
+ auto& chunk_list = seq.chunks;
+ bool was_empty = chunk_list.empty();
+ chunk_list.emplace_back(wr_);
+ has_data_ = true;
+ if (was_empty) {
+ PERFETTO_DCHECK(empty_sequences_ > 0);
+ --empty_sequences_;
+ }
+
+ wr_ += tbchunk_outer_size;
+ PERFETTO_DCHECK(wr_ <= size_ && wr_ <= used_size_);
+
+ stats_.set_chunks_written(stats_.chunks_written() + 1);
+ stats_.set_bytes_written(stats_.bytes_written() + tbchunk_outer_size);
+
+ if (empty_sequences_ > kEmptySequencesGcTreshold)
+ DeleteStaleEmptySequences();
+
+ return true;
+}
+
+void TraceBufferV2::RecordChunkV2DataLoss(ProducerID producer_id,
+ WriterID writer_id) {
+ PERFETTO_CHECK(!read_only_);
+
+ // SMB v1 and SMB v2 writers share one WriterID space per producer. An SMB v1
+ // sequence with this key therefore belongs to another writer.
+ auto seq_it = sequences_.find(MkProducerAndWriterID(producer_id, writer_id));
+ if (seq_it != sequences_.end() && seq_it->second.is_smb_v2)
+ seq_it->second.pending_chunk_v2_data_loss = true;
+}
+
+void TraceBufferV2::RecordAbiViolation() {
+ PERFETTO_CHECK(!read_only_);
+ stats_.set_abi_violations(stats_.abi_violations() + 1);
+}
+
TraceBufferV2::TBChunk* TraceBufferV2::CreateTBChunk(size_t off, size_t size) {
DcheckIsAlignedAndWithinBounds(off);
size_t end = off + TBChunk::OuterSize(size);
@@ -64754,6 +73596,26 @@ TraceBufferV2::TBChunk* TraceBufferV2::CreateTBChunk(size_t off, size_t size) {
return new (chunk) TBChunk(off, size);
}
+bool TraceBufferV2::MakeSpaceToWrite(size_t size) {
+ PERFETTO_DCHECK(size <= size_);
+
+ // If the chunk does not fit at the end, clear the remaining tail and wrap.
+ // In discard mode, reaching the end stops all further writes.
+ const size_t tail_size = size_to_end();
+ if (PERFETTO_UNLIKELY(size > tail_size)) {
+ if (overwrite_policy_ == kDiscard)
+ return false;
+ // A previous write can land exactly at the end, leaving no tail to clear.
+ if (tail_size > 0)
+ DeleteNextChunksFor(tail_size);
+ wr_ = 0;
+ stats_.set_write_wrap_count(stats_.write_wrap_count() + 1);
+ PERFETTO_DCHECK(size_to_end() >= size);
+ }
+ DeleteNextChunksFor(size);
+ return true;
+}
+
// Deletes (by marking the record invalid and removing form the index) all
// chunks from wr_ to (wr_ + bytes_to_clear).
// Graphically, assume the initial situation is the following (|wptr_| = 10).
@@ -64782,8 +73644,9 @@ void TraceBufferV2::DeleteNextChunksFor(size_t bytes_to_clear) {
// This loop erases all the existing chunks in the clear range.
for (size_t off = wr_, next_off = 0; off < clear_end; off = next_off) {
if (PERFETTO_UNLIKELY(off >= used_size_)) {
- // This happens only on the first round of writing, when there are no
- // chunks in the buffer yet. There is nothing to delete here, easy.
+ // This happens on the first round of writing, or after MaybeCompact()
+ // shrinks |used_size_|, when there are no chunks in this range.
+ // There is nothing to delete here, easy.
break;
}
TBChunk* chunk = GetTBChunkAt(off);
@@ -64805,7 +73668,7 @@ void TraceBufferV2::DeleteNextChunksFor(size_t bytes_to_clear) {
// protovm. If not, we still need to do reads, but without having to
// accumulated data in a packet.
TracePacket* maybe_packet = nullptr;
- if (!protovms_.empty()) {
+ if (!protovms_.empty() && !csr.seq()->is_smb_v2) {
overwritten_packet_.Clear();
maybe_packet = &overwritten_packet_;
}
@@ -64813,8 +73676,8 @@ void TraceBufferV2::DeleteNextChunksFor(size_t bytes_to_clear) {
break;
}
if (maybe_packet) {
- MaybeProcessOverwrittenPacketWithProtoVm(*maybe_packet,
- csr.seq()->producer_id);
+ protovms_.MaybeProcessOverwrittenPacket(*maybe_packet,
+ csr.seq()->producer_id);
}
has_cleared_unconsumed_fragments = true;
}
@@ -64858,7 +73721,7 @@ bool TraceBufferV2::TryPatchChunkContents(ProducerID producer_id,
ProducerAndWriterID seq_key = MkProducerAndWriterID(producer_id, writer_id);
auto seq_it = sequences_.find(seq_key);
- if (seq_it == sequences_.end()) {
+ if (seq_it == sequences_.end() || seq_it->second.is_smb_v2) {
stats_.set_patches_failed(stats_.patches_failed() + 1);
return false;
}
@@ -64934,7 +73797,8 @@ void TraceBufferV2::DiscardWrite() {
// This is to avoid thrashing with a sort every time one sequence becomes empty.
// Also we have to defer the deletion of SequenceState outside of
// ReadNextTracePacket() calls, as that caches SequenceState* pointers in
-// seq_iter_. This is called only at the end of each CopyChunkUntrusted().
+// chunk_seq_reader_. This is called only at the end of CopyChunkUntrusted()
+// and CopyChunkV2Untrusted().
void TraceBufferV2::DeleteStaleEmptySequences() {
// Build a vector of iterators; sort it; delete the first size() - kThreshold.
using SeqIterator = decltype(sequences_)::iterator;
@@ -64953,6 +73817,11 @@ void TraceBufferV2::DeleteStaleEmptySequences() {
return a->second.age_for_gc < b->second.age_for_gc;
});
+ // TODO(sashwinbalaji): Pruning an SMB v2 sequence discards its
+ // pending_chunk_v2_data_loss. If that writer appends again, the loss is not
+ // reported. SMB sequences have the same limit: pruning discards
+ // last_chunk_consumed. Revisit if field traces show missed loss for writers
+ // that write rarely while many others churn.
size_t n_oldest = empty_seqs.size() - kKeepLastEmptySeq;
for (size_t i = 0; i < n_oldest; ++i) {
sequences_.erase(empty_seqs[i]);
@@ -64961,9 +73830,9 @@ void TraceBufferV2::DeleteStaleEmptySequences() {
// This is not really required in the current implementation and is here just
// to spot bugs while refactoring the code in future. This function is
- // only called by CopyChunkUntrusted(), but the chunk_seq_reader_ (which can
+ // called only by writes, but the chunk_seq_reader_ (which can
// hold onto a SequenceState* pointer) is reset by every BeginRead() call.
- // By design BeginRead()/ReadNextTracePacket() cannot overlap with CCU().
+ // By design BeginRead()/ReadNextTracePacket() cannot overlap with writes.
chunk_seq_reader_.reset();
}
@@ -64974,12 +73843,12 @@ std::unique_ptr<TraceBuffer> TraceBufferV2::CloneReadOnly() const {
return buf;
}
+TraceBufferProtoVms* TraceBufferV2::protovms() {
+ return &protovms_;
+}
+
size_t TraceBufferV2::GetMemoryUsageBytes() const {
- size_t total_bytes = size();
- for (const Vm& vm : protovms_) {
- total_bytes += vm.instance->GetMemoryUsageBytes();
- }
- return total_bytes;
+ return size() + protovms_.GetMemoryUsageBytes();
}
TraceBufferV2::TraceBufferV2(CloneCtor, const TraceBufferV2& src)
@@ -64995,6 +73864,7 @@ TraceBufferV2::TraceBufferV2(CloneCtor, const TraceBufferV2& src)
data_.EnsureCommitted(src.used_size_);
memcpy(data_.Get(), src.data_.Get(), src.used_size_);
used_size_ = src.used_size_;
+ has_data_ = src.has_data_;
wr_ = src.wr_;
stats_ = src.stats_;
@@ -65003,28 +73873,13 @@ TraceBufferV2::TraceBufferV2(CloneCtor, const TraceBufferV2& src)
stats_.set_readaheads_failed(0);
stats_.set_readaheads_succeeded(0);
- // Finally copy over the SequenceState map.
+ // Finally copy over the SequenceState map and WriterStats map. WriterStats
+ // must be copied because EmitTraceProvenance() derives the producer->sequence
+ // mapping from it, until b/568173038 is addressed.
sequences_ = src.sequences_;
+ writer_stats_ = src.writer_stats_;
- for (const auto& vm : src.protovms_) {
- auto vm_cloned = vm.CloneReadOnly();
- if (!vm_cloned.instance) {
- PERFETTO_ELOG("Failed to clone ProtoVMs");
- protovms_.clear();
- break;
- }
- protovms_.push_back(std::move(vm_cloned));
- }
-}
-
-TraceBufferV2::Vm TraceBufferV2::Vm::CloneReadOnly() const {
- Vm cloned_vm;
- cloned_vm.data_source_name = data_source_name;
- cloned_vm.program_hash = program_hash;
- cloned_vm.memory_limit_kb = memory_limit_kb;
- cloned_vm.producers = producers;
- cloned_vm.instance = instance->CloneReadOnly();
- return cloned_vm;
+ protovms_.CloneReadOnlyFrom(src.protovms_);
}
void TraceBufferV2::DumpForTesting() {
@@ -65044,8 +73899,8 @@ void TraceBufferV2::DumpForTesting() {
PERFETTO_DLOG(
"[%06zu-%06zu] size=%05u(%05u) id=%05u pr_wr=%08x flags=%08x", rd,
rd + c->outer_size(), c->payload_size,
- c->payload_size - c->payload_avail, c->chunk_id, c->pri_wri_id,
- c->flags);
+ static_cast<unsigned>(c->payload_size - c->payload_avail),
+ c->chunk_id, c->pri_wri_id, c->flags);
rd += c->outer_size();
continue;
}
@@ -65059,79 +73914,6 @@ void TraceBufferV2::DumpForTesting() {
PERFETTO_DLOG("------------------------------------------------------------");
}
-TraceBufferV2::Vm::Vm() = default;
-TraceBufferV2::Vm::~Vm() = default;
-TraceBufferV2::Vm::Vm(Vm&&) noexcept = default;
-
-void TraceBufferV2::MaybeSetUpProtoVm(const std::string& data_source_name,
- const std::string& program_bytes,
- uint32_t memory_limit_kb,
- ProducerID producer_id) {
- Vm* vm = nullptr;
- // Re-use existing ProtoVM instance, if any.
- uint64_t program_hash = base::MurmurHashValue(program_bytes);
- auto vm_it =
- std::find_if(protovms_.begin(), protovms_.end(), [&](const Vm& vm) {
- return vm.data_source_name == data_source_name &&
- vm.program_hash == program_hash;
- });
- if (vm_it != protovms_.end()) {
- vm = &(*vm_it);
- } else {
- // Otherwise instantiate new ProtoVM
- Vm new_vm;
- new_vm.data_source_name = data_source_name;
- new_vm.program_hash = program_hash;
- new_vm.memory_limit_kb = memory_limit_kb;
-
- protozero::ConstBytes program_bytes_view{
- reinterpret_cast<const uint8_t*>(program_bytes.data()),
- program_bytes.size()};
-
- new_vm.instance = std::make_unique<protovm::Vm>(
- program_bytes_view, new_vm.memory_limit_kb * 1024);
- if (!new_vm.instance) {
- PERFETTO_ELOG("Failed to allocate ProtoVM");
- return;
- }
-
- protovms_.push_back(std::move(new_vm));
- vm = &protovms_.back();
- }
- // Update ProtoVM's producer IDs
- vm->producers.insert(producer_id);
-}
-
-void TraceBufferV2::MaybeProcessOverwrittenPacketWithProtoVm(
- const TracePacket& packet,
- ProducerID producer) {
- protovm_patch_.clear();
-
- for (auto& vm : protovms_) {
- if (vm.producers.find(producer) == vm.producers.end()) {
- continue;
- }
- // TODO(keanmariotti): add an optimized path for the case
- // "packet.slices().size() == 1" (zero copy)
- if (protovm_patch_.empty()) {
- packet.GetRawBytes(&protovm_patch_);
- }
- protozero::ConstBytes bytes{
- reinterpret_cast<const uint8_t*>(protovm_patch_.data()),
- protovm_patch_.size()};
- auto status = vm.instance->ApplyPatch(bytes);
- if (status.IsOk()) {
- break;
- }
- if (status.IsAbort()) {
- // TODO(keanmariotti): consider doing something more here. Ideally
- // triggering a field upload containing the stacktrace.
- PERFETTO_ELOG("ProtoVM abort while applying patch. Stacktrace:\n%s",
- base::Join(status.stacktrace(), "\n").c_str());
- }
- }
-}
-
} // namespace perfetto
// gen_amalgamated begin source: src/tracing/service/tracing_service_endpoints_impl.cc
// gen_amalgamated begin header: src/tracing/service/tracing_service_endpoints_impl.h
@@ -65173,6 +73955,8 @@ void TraceBufferV2::MaybeProcessOverwrittenPacketWithProtoVm(
// gen_amalgamated expanded: #include "perfetto/ext/tracing/core/shared_memory_abi.h"
// gen_amalgamated expanded: #include "perfetto/ext/tracing/core/tracing_service.h"
// gen_amalgamated expanded: #include "perfetto/tracing/core/forward_decls.h"
+// gen_amalgamated expanded: #include "src/tracing/service/service_ring_buffer_drainer.h"
+// gen_amalgamated expanded: #include "src/tracing/v2/producer_ring_buffer_arbiter.h"
// This header contains the declarations for the 3 abtract classes
// (ProducerEndpointImpl, ConsumerEndpointImpl, RelayEndpointImpl).
@@ -65192,7 +73976,9 @@ struct TracingSession;
struct TriggerInfo;
// The implementation behind the service endpoint exposed to each producer.
-class ProducerEndpointImpl : public TracingService::ProducerEndpoint {
+class ProducerEndpointImpl
+ : public TracingService::ProducerEndpoint,
+ public tracing_v2::ServiceRingBufferDrainer::Delegate {
public:
ProducerEndpointImpl(ProducerID,
const ClientIdentity& client_identity,
@@ -65203,7 +73989,8 @@ class ProducerEndpointImpl : public TracingService::ProducerEndpoint {
const std::string& machine_name,
const std::string& sdk_version,
bool in_process,
- bool smb_scraping_enabled);
+ bool smb_scraping_enabled,
+ uint32_t protocol_abi_versions);
~ProducerEndpointImpl() override;
// TracingService::ProducerEndpoint implementation.
@@ -65221,6 +74008,9 @@ class ProducerEndpointImpl : public TracingService::ProducerEndpoint {
std::unique_ptr<TraceWriter> CreateTraceWriter(
BufferID,
BufferExhaustedPolicy) override;
+ std::unique_ptr<TraceWriter> CreateTraceWriterV2(
+ BufferID,
+ BufferExhaustedPolicy) override;
SharedMemoryArbiter* MaybeSharedMemoryArbiter() override;
bool IsShmemProvidedByProducer() const override;
void NotifyFlushComplete(FlushRequestID) override;
@@ -65252,6 +74042,24 @@ class ProducerEndpointImpl : public TracingService::ProducerEndpoint {
return std::nullopt;
}
+ // TracingService::ProducerEndpoint implementation for tracing v2.
+ void InitializeV2RingBuffer(const DataSourceConfig&) override;
+ void AttachV2RingBuffer(const std::shared_ptr<SharedMemory>&,
+ uint32_t chunk_size_bytes,
+ std::function<void(bool)>) override;
+ void DrainV2RingBuffer() override;
+
+ // tracing_v2::ServiceRingBufferDrainer::Delegate implementation.
+ TraceBuffer* GetV2RingBufferDestination(BufferID) override;
+ void ForEachV2RingBufferDestination(
+ const std::function<void(TraceBuffer&)>& callback) override;
+ void OnRingBufferChunksDiscarded(uint64_t count) override;
+
+ // Mapping size for the memory guardrail. Zero if no ring buffer is attached.
+ size_t ring_buffer_size_bytes() const {
+ return v2_ring_buffer_drainer_ ? v2_ring_buffer_drainer_->size_bytes() : 0;
+ }
+
bool IsShmemEmulated() { return shmem_abi_.use_shmem_emulation(); }
bool IsAndroidProcessFrozen();
@@ -65299,6 +74107,32 @@ class ProducerEndpointImpl : public TracingService::ProducerEndpoint {
// SharedMemoryArbiterImpl methods themselves are thread-safe.
std::unique_ptr<SharedMemoryArbiterImpl> inproc_shmem_arbiter_;
+ // Bitmask of the common versions supplied to ConnectProducer(). Fixed for
+ // the connection.
+ const uint32_t protocol_abi_versions_;
+
+ // Owns the ring buffer and creates v2 writers.
+ //
+ // States:
+ // - nullopt: initialization has not been attempted.
+ // - nullptr: sizing or allocation failed.
+ // Later InitializeV2RingBuffer() calls on the same connection do not retry
+ // initialization, to avoid changing the pointer while v2 writer threads
+ // read it without a lock.
+ // - Non-null pointer: the arbiter exists and tracks service attachment.
+ //
+ // Set by InitializeV2RingBuffer() when an instance selects v2, before the
+ // first in-process v2 writer.
+ // Writer threads then read it without a lock.
+ // For an IPC producer, the arbiter lives in the producer process.
+ std::optional<std::unique_ptr<tracing_v2::ProducerRingBufferArbiter>>
+ v2_ring_buffer_arbiter_;
+
+ // |v2_ring_buffer_drainer_| owns the reader and keeps the ring buffer mapped.
+ // The reader's destination checks use |allowed_target_buffers_|.
+ // DisconnectProducer() runs the final drain through |v2_ring_buffer_drainer_|
+ // before |allowed_target_buffers_| is destroyed.
+ std::unique_ptr<tracing_v2::ServiceRingBufferDrainer> v2_ring_buffer_drainer_;
PERFETTO_THREAD_CHECKER(thread_checker_)
base::WeakRunner weak_runner_;
};
@@ -65984,6 +74818,7 @@ struct TracingSession {
// gen_amalgamated expanded: #include "src/tracing/service/clock.h"
// gen_amalgamated expanded: #include "src/tracing/service/dependencies.h"
// gen_amalgamated expanded: #include "src/tracing/service/random.h"
+// gen_amalgamated expanded: #include "src/tracing/service/trace_buffer.h"
// gen_amalgamated expanded: #include "src/tracing/service/tracing_service_endpoints_impl.h"
// gen_amalgamated expanded: #include "src/tracing/service/tracing_service_session.h"
// gen_amalgamated expanded: #include "src/tracing/service/tracing_service_structs.h"
@@ -66007,14 +74842,12 @@ class Consumer;
class Producer;
class SharedMemory;
class SharedMemoryArbiterImpl;
-class TraceBuffer;
class TracePacket;
namespace tracing_service {
// The tracing service business logic.
class TracingServiceImpl : public TracingService {
public:
- static constexpr size_t kMaxShmSize = 32 * 1024 * 1024ul;
static constexpr uint8_t kSyncMarker[] = {0x82, 0x47, 0x7a, 0x76, 0xb2, 0x8d,
0x42, 0xba, 0x81, 0xdc, 0x33, 0x32,
0x6d, 0x57, 0xa0, 0x79};
@@ -66118,7 +74951,12 @@ class TracingServiceImpl : public TracingService {
size_t shared_memory_page_size_hint_bytes = 0,
std::unique_ptr<SharedMemory> shm = nullptr,
const std::string& sdk_version = {},
- const std::string& machine_name = {}) override;
+ const std::string& machine_name = {},
+ uint32_t protocol_abi_versions = kProtocolAbiV1) override;
+
+ // The endpoint reports discarded ring buffer chunks on the service
+ // sequence. Adds them to chunks_discarded.
+ void OnRingBufferChunksDiscarded(uint64_t count);
std::unique_ptr<TracingService::ConsumerEndpoint> ConnectConsumer(
Consumer*,
@@ -66239,6 +75077,7 @@ class TracingServiceImpl : public TracingService {
bool success);
void ScrapeSharedMemoryBuffers(TracingSession*, ProducerEndpointImpl*);
void PeriodicClearIncrementalStateTask(TracingSessionID, bool post_next_only);
+ // Returns nullptr if there is no buffer with this ID.
TraceBuffer* GetBufferByID(BufferID);
void FlushDataSourceInstances(
TracingSession*,
@@ -66287,8 +75126,11 @@ class TracingServiceImpl : public TracingService {
std::vector<TracePacket>* packets);
// If `*tracing_session` has compression enabled, compress `*packets`.
+ // `skip_compression_of_first_n_packets` is the number of packets to skip
+ // compression of (i.e. TraceConfig, UUID packets).
void MaybeCompressPackets(TracingSession* tracing_session,
- std::vector<TracePacket>* packets);
+ std::vector<TracePacket>* packets,
+ size_t skip_compression_of_first_n_packets);
// If `*tracing_session` is configured to write into a file, writes `packets`
// into the file.
@@ -66297,6 +75139,12 @@ class TracingServiceImpl : public TracingService {
// been an error), false otherwise.
bool WriteIntoFile(TracingSession* tracing_session,
std::vector<TracePacket> packets);
+
+ // Attempts to compact each buffer in `*tracing_session`.
+ // Call only after the ReadBuffers() packets are no longer in use, because
+ // compaction can move the data their slices reference.
+ void MaybeCompactBuffers(TracingSession* tracing_session);
+
void OnStartTriggersTimeout(TracingSessionID tsid);
void MaybeLogUploadEvent(const TraceConfig&,
const base::Uuid&,
@@ -66378,20 +75226,30 @@ class TracingServiceImpl : public TracingService {
*/
// gen_amalgamated expanded: #include "src/tracing/service/tracing_service_endpoints_impl.h"
+
+#include <cinttypes>
+
// gen_amalgamated expanded: #include "perfetto/base/task_runner.h"
// gen_amalgamated expanded: #include "perfetto/ext/base/file_utils.h"
// gen_amalgamated expanded: #include "perfetto/ext/base/metatrace.h"
+// gen_amalgamated expanded: #include "perfetto/ext/base/status_or.h"
// gen_amalgamated expanded: #include "perfetto/ext/base/string_utils.h"
// gen_amalgamated expanded: #include "perfetto/ext/base/string_view.h"
// gen_amalgamated expanded: #include "perfetto/ext/base/version.h"
// gen_amalgamated expanded: #include "perfetto/ext/tracing/core/consumer.h"
// gen_amalgamated expanded: #include "perfetto/ext/tracing/core/producer.h"
// gen_amalgamated expanded: #include "perfetto/ext/tracing/core/trace_writer.h"
+// gen_amalgamated expanded: #include "perfetto/tracing/core/data_source_config.h"
// gen_amalgamated expanded: #include "perfetto/tracing/core/tracing_service_capabilities.h"
// gen_amalgamated expanded: #include "perfetto/tracing/core/tracing_service_state.h"
+// gen_amalgamated expanded: #include "src/tracing/core/in_process_shared_memory.h"
+// gen_amalgamated expanded: #include "src/tracing/core/null_trace_writer.h"
// gen_amalgamated expanded: #include "src/tracing/core/shared_memory_arbiter_impl.h"
+// gen_amalgamated expanded: #include "src/tracing/service/service_ring_buffer_drainer.h"
+// gen_amalgamated expanded: #include "src/tracing/service/trace_buffer.h"
// gen_amalgamated expanded: #include "src/tracing/service/tracing_service_impl.h"
// gen_amalgamated expanded: #include "src/tracing/service/tracing_service_structs.h"
+// gen_amalgamated expanded: #include "src/tracing/v2/shared_ring_buffer_abi.h"
// gen_amalgamated expanded: #include "protos/perfetto/common/builtin_clock.pbzero.h"
@@ -66790,7 +75648,8 @@ ProducerEndpointImpl::ProducerEndpointImpl(
const std::string& machine_name,
const std::string& sdk_version,
bool in_process,
- bool smb_scraping_enabled)
+ bool smb_scraping_enabled,
+ uint32_t protocol_abi_versions)
: id_(id),
client_identity_(client_identity),
service_(service),
@@ -66800,6 +75659,7 @@ ProducerEndpointImpl::ProducerEndpointImpl(
sdk_version_(sdk_version),
in_process_(in_process),
smb_scraping_enabled_(smb_scraping_enabled),
+ protocol_abi_versions_(protocol_abi_versions),
weak_runner_(task_runner) {}
ProducerEndpointImpl::~ProducerEndpointImpl() {
@@ -67000,11 +75860,30 @@ bool ProducerEndpointImpl::IsShmemProvidedByProducer() const {
std::unique_ptr<TraceWriter> ProducerEndpointImpl::CreateTraceWriter(
BufferID buf_id,
BufferExhaustedPolicy buffer_exhausted_policy) {
+ if (!(protocol_abi_versions_ & kProtocolAbiV1)) {
+ PERFETTO_ELOG(
+ "Cannot create a v1 trace writer: v1 is not in the common protocol "
+ "mask (%x)",
+ protocol_abi_versions_);
+ return std::make_unique<NullTraceWriter>();
+ }
PERFETTO_DCHECK(MaybeSharedMemoryArbiter());
return MaybeSharedMemoryArbiter()->CreateTraceWriter(buf_id,
buffer_exhausted_policy);
}
+// Can be called on any thread.
+std::unique_ptr<TraceWriter> ProducerEndpointImpl::CreateTraceWriterV2(
+ BufferID buf_id,
+ BufferExhaustedPolicy buffer_exhausted_policy) {
+ auto* arbiter = v2_ring_buffer_arbiter_.has_value()
+ ? v2_ring_buffer_arbiter_->get()
+ : nullptr;
+ if (!arbiter)
+ return std::make_unique<NullTraceWriter>();
+ return arbiter->CreateTraceWriter(buf_id, buffer_exhausted_policy);
+}
+
void ProducerEndpointImpl::NotifyFlushComplete(FlushRequestID id) {
PERFETTO_DCHECK_THREAD(thread_checker_);
PERFETTO_DCHECK(MaybeSharedMemoryArbiter());
@@ -67116,6 +75995,100 @@ bool ProducerEndpointImpl::IsAndroidProcessFrozen() {
return false;
}
+void ProducerEndpointImpl::InitializeV2RingBuffer(
+ const DataSourceConfig& config) {
+ PERFETTO_DCHECK_THREAD(thread_checker_);
+ if (v2_ring_buffer_arbiter_.has_value() || !in_process_ ||
+ !(protocol_abi_versions_ & kProtocolAbiV2)) {
+ return;
+ }
+
+ auto arbiter_or = tracing_v2::ProducerRingBufferArbiter::Create(
+ weak_runner_.task_runner(), this, config, shmem_size_hint_bytes_,
+ [](size_t size) -> base::StatusOr<std::shared_ptr<SharedMemory>> {
+ return std::shared_ptr<SharedMemory>(
+ InProcessSharedMemory::Create(size));
+ });
+ if (!arbiter_or.ok()) {
+ PERFETTO_ELOG("tracing v2: cannot create ring buffer: %s",
+ arbiter_or.status().c_message());
+ v2_ring_buffer_arbiter_ = nullptr;
+ return;
+ }
+ v2_ring_buffer_arbiter_ = std::move(*arbiter_or);
+
+ auto* arbiter = v2_ring_buffer_arbiter_->get();
+ AttachV2RingBuffer(
+ arbiter->memory(), arbiter->ring_buffer()->chunk_size(),
+ [weak_arbiter = arbiter->GetWeakPtr()](bool reader_attached) {
+ if (weak_arbiter)
+ weak_arbiter->OnReaderAttachReply(reader_attached);
+ });
+}
+
+void ProducerEndpointImpl::AttachV2RingBuffer(
+ const std::shared_ptr<SharedMemory>& memory,
+ uint32_t chunk_size_bytes,
+ std::function<void(bool)> callback) {
+ PERFETTO_DCHECK_THREAD(thread_checker_);
+
+ base::Status status;
+ if (!(protocol_abi_versions_ & kProtocolAbiV2)) {
+ status = base::ErrStatus("the connection has no tracing v2");
+ } else if (v2_ring_buffer_drainer_) {
+ status = base::ErrStatus("a ring buffer is already attached");
+ } else if (!memory || memory->size() > TracingService::kMaxShmSize) {
+ status = base::ErrStatus("no mapping, or the mapping is too large");
+ } else {
+ status = tracing_v2::NumChunksForRingBufferLayout(
+ memory->start(), memory->size(), chunk_size_bytes)
+ .status();
+ }
+ if (!status.ok()) {
+ PERFETTO_DLOG("Producer %" PRIu16 " \"%s\": ring buffer rejected: %s", id_,
+ name_.c_str(), status.c_message());
+ callback(false);
+ return;
+ }
+
+ v2_ring_buffer_drainer_ =
+ std::make_unique<tracing_v2::ServiceRingBufferDrainer>(
+ memory, chunk_size_bytes, id_, client_identity_, this,
+ weak_runner_.task_runner());
+ service_->UpdateMemoryGuardrail();
+ DrainV2RingBuffer();
+ callback(true);
+}
+
+void ProducerEndpointImpl::DrainV2RingBuffer() {
+ PERFETTO_DCHECK_THREAD(thread_checker_);
+ if (v2_ring_buffer_drainer_)
+ v2_ring_buffer_drainer_->Drain();
+}
+
+TraceBuffer* ProducerEndpointImpl::GetV2RingBufferDestination(BufferID id) {
+ if (!is_allowed_target_buffer(id))
+ return nullptr;
+
+ // The producer supplies |id| through shared memory. Check that the
+ // destination buffer supports tracing v2 otherwise return nullptr.
+ TraceBuffer* buffer = service_->GetBufferByID(id);
+ return buffer && buffer->supports_tracing_v2() ? buffer : nullptr;
+}
+
+void ProducerEndpointImpl::ForEachV2RingBufferDestination(
+ const std::function<void(TraceBuffer&)>& callback) {
+ for (BufferID id : allowed_target_buffers_) {
+ TraceBuffer* buffer = service_->GetBufferByID(id);
+ if (buffer && buffer->supports_tracing_v2())
+ callback(*buffer);
+ }
+}
+
+void ProducerEndpointImpl::OnRingBufferChunksDiscarded(uint64_t count) {
+ service_->OnRingBufferChunksDiscarded(count);
+}
+
////////////////////////////////////////////////////////////////////////////////
// RelayEndpointImpl implementation
////////////////////////////////////////////////////////////////////////////////
@@ -67308,11 +76281,13 @@ inline base::StatusOr<base::SchedPolicyAndPrio> CreateSchedPolicyFromConfig(
// gen_amalgamated expanded: #include "src/tracing/service/packet_stream_validator.h"
// gen_amalgamated expanded: #include "src/tracing/service/random.h"
// gen_amalgamated expanded: #include "src/tracing/service/trace_buffer.h"
+// gen_amalgamated expanded: #include "src/tracing/service/trace_buffer_protovms.h"
// gen_amalgamated expanded: #include "src/tracing/service/trace_buffer_v1.h"
// gen_amalgamated expanded: #include "src/tracing/service/trace_buffer_v2.h"
// gen_amalgamated expanded: #include "src/tracing/service/tracing_service_endpoints_impl.h"
// gen_amalgamated expanded: #include "src/tracing/service/tracing_service_session.h"
// gen_amalgamated expanded: #include "src/tracing/service/tracing_service_structs.h"
+// gen_amalgamated expanded: #include "src/tracing/v2/shared_ring_buffer_abi.h"
#if PERFETTO_BUILDFLAG(PERFETTO_ZLIB)
// gen_amalgamated expanded: #include "src/tracing/service/zlib_compressor.h"
#endif
@@ -67441,7 +76416,7 @@ std::tuple<size_t /*shm_size*/, size_t /*page_size*/> EnsureValidShmSizes(
shm_size = TracingServiceImpl::kDefaultShmSize;
page_size = std::min<size_t>(page_size, kMaxPageSize);
- shm_size = std::min<size_t>(shm_size, TracingServiceImpl::kMaxShmSize);
+ shm_size = std::min<size_t>(shm_size, TracingService::kMaxShmSize);
// The tracing page size has to be multiple of 4K. On some systems (e.g. Mac
// on Arm64) the system page size can be larger (e.g., 16K). That doesn't
@@ -67545,6 +76520,21 @@ void AppendOwnedSlicesToPacket(std::unique_ptr<uint8_t[]> data,
}
}
+// Creates an empty trace buffer of the given implementation.
+// Returns nullptr if the memory allocation fails.
+std::unique_ptr<TraceBuffer> CreateTraceBuffer(
+ TraceBuffer::BufType type,
+ size_t size_in_bytes,
+ TraceBuffer::OverwritePolicy policy) {
+ switch (type) {
+ case TraceBuffer::kV1:
+ return TraceBufferV1::Create(size_in_bytes, policy);
+ case TraceBuffer::kV2:
+ return TraceBufferV2::Create(size_in_bytes, policy);
+ }
+ return nullptr;
+}
+
// Shmem emulation is only for relay (remote-host) producers whose SMB is copied
// over IPC. An in-process producer always has a real shared SMB, so it must use
// kDefault even when it carries a non-default machine id.
@@ -67586,9 +76576,18 @@ TracingServiceImpl::ConnectProducer(Producer* producer,
size_t shared_memory_page_size_hint_bytes,
std::unique_ptr<SharedMemory> shm,
const std::string& sdk_version,
- const std::string& machine_name) {
+ const std::string& machine_name,
+ uint32_t protocol_abi_versions) {
PERFETTO_DCHECK_THREAD(thread_checker_);
+ if (!protocol_abi_versions) {
+ PERFETTO_ELOG(
+ "Failed to negotiate a valid tracing protocol version with the tracing "
+ "service: producer=\"%s\"",
+ producer_name.c_str());
+ return nullptr;
+ }
+
auto uid = client_identity.uid();
if (lockdown_mode_ && uid != base::GetCurrentUserId()) {
PERFETTO_DLOG("Lockdown mode. Rejecting producer with UID %lu",
@@ -67618,7 +76617,7 @@ TracingServiceImpl::ConnectProducer(Producer* producer,
std::unique_ptr<ProducerEndpointImpl> endpoint(new ProducerEndpointImpl(
id, client_identity, this, weak_runner_.task_runner(), producer,
producer_name, machine_name, sdk_version, in_process,
- smb_scraping_enabled));
+ smb_scraping_enabled, protocol_abi_versions));
auto it_and_inserted = producers_.emplace(id, endpoint.get());
PERFETTO_DCHECK(it_and_inserted.second);
@@ -68003,11 +77002,35 @@ base::Status TracingServiceImpl::EnableTracing(ConsumerEndpointImpl* consumer,
}
}
+ // For each buffer: the name of a data source with a ProtoVM, and of one
+ // that can use tracing v2.
+ // Tracing v2 does not support ProtoVM on the same buffer yet.
+ std::vector<const std::string*> protovm_source(num_buffers);
+ std::vector<const std::string*> tracing_v2_source(num_buffers);
+
// Check that the config specifies all buffers for its data sources. This
// is also checked in SetupDataSource, but it is simpler to return a proper
// error to the consumer from here (and there will be less state to undo).
for (const TraceConfig::DataSource& cfg_data_source : cfg.data_sources()) {
const auto& ds_config = cfg_data_source.config();
+ const auto& tracing_v2_config = ds_config.experimental_tracing_v2();
+ if (tracing_v2_config.use_v2_probability_percent() > 100) {
+ return PERFETTO_SVC_ERR(
+ "experimental_tracing_v2.use_v2_probability_percent must be at most "
+ "100");
+ }
+ if (tracing_v2_config.drain_occupancy_percent() < -1 ||
+ tracing_v2_config.drain_occupancy_percent() > 100) {
+ return PERFETTO_SVC_ERR(
+ "experimental_tracing_v2.drain_occupancy_percent must be -1 to 100");
+ }
+ for (const auto& option : tracing_v2_config.chunk_size_options()) {
+ if (!tracing_v2::IsValidChunkSize(option.size_bytes())) {
+ return PERFETTO_SVC_ERR(
+ "experimental_tracing_v2.chunk_size_options: invalid size %u",
+ option.size_bytes());
+ }
+ }
// Resolve target buffer: if target_buffer_name is set, look it up.
size_t target_buffer = ds_config.target_buffer();
@@ -68050,6 +77073,19 @@ base::Status TracingServiceImpl::EnableTracing(ConsumerEndpointImpl* consumer,
"%zu)",
ds_config.name().c_str(), target_buffer, num_buffers);
}
+
+ if (ds_config.has_protovm_config())
+ protovm_source[target_buffer] = &ds_config.name();
+ if (tracing_v2_config.use_v2_probability_percent() > 0)
+ tracing_v2_source[target_buffer] = &ds_config.name();
+ if (protovm_source[target_buffer] && tracing_v2_source[target_buffer]) {
+ return PERFETTO_SVC_ERR(
+ "Data source \"%s\" has a ProtoVM and data source \"%s\" has "
+ "experimental_tracing_v2 on the same buffer %zu. Tracing v2 does not "
+ "support ProtoVM",
+ protovm_source[target_buffer]->c_str(),
+ tracing_v2_source[target_buffer]->c_str(), target_buffer);
+ }
}
uint32_t current_exclusive_prio = 0;
@@ -68427,10 +77463,10 @@ base::Status TracingServiceImpl::EnableTracing(ConsumerEndpointImpl* consumer,
std::unique_ptr<TraceBuffer> new_buffer;
switch (buffer_cfg.experimental_mode()) {
case TraceConfig::BufferConfig::TRACE_BUFFER_V2:
- new_buffer = TraceBufferV2::Create(buf_size, policy);
+ new_buffer = CreateTraceBuffer(TraceBuffer::kV2, buf_size, policy);
break;
case TraceConfig::BufferConfig::MODE_UNSPECIFIED:
- new_buffer = TraceBufferV1::Create(buf_size, policy);
+ new_buffer = CreateTraceBuffer(TraceBuffer::kV1, buf_size, policy);
break;
}
auto it_and_inserted = buffers_.emplace(global_id, std::move(new_buffer));
@@ -69521,13 +78557,6 @@ void TracingServiceImpl::CompleteFlush(TracingSessionID tsid,
void TracingServiceImpl::ScrapeSharedMemoryBuffers(
TracingSession* tracing_session,
ProducerEndpointImpl* producer) {
- if (!producer->smb_scraping_enabled_ || producer->IsShmemEmulated())
- return;
-
- // Can't copy chunks if we don't know about any trace writers.
- if (producer->writers_.empty())
- return;
-
// Performance optimization: On flush or session disconnect, this method is
// called for each producer. If the producer doesn't participate in the
// session, there's no need to scrape its chunks right now. We can tell if a
@@ -69542,6 +78571,16 @@ void TracingServiceImpl::ScrapeSharedMemoryBuffers(
if (!producer_in_session)
return;
+ // Drain v2 data even when v1 SMB scraping is disabled.
+ producer->DrainV2RingBuffer();
+
+ if (!producer->smb_scraping_enabled_ || producer->IsShmemEmulated())
+ return;
+
+ // Can't copy chunks if we don't know about any trace writers.
+ if (producer->writers_.empty())
+ return;
+
PERFETTO_DLOG("Scraping SMB for producer %" PRIu16, producer->id_);
// Find and copy any uncommitted chunks from the SMB.
@@ -69749,6 +78788,26 @@ bool TracingServiceImpl::ReadBuffersIntoConsumer(
return;
ReadBuffersIntoConsumer(tsid, weak_consumer.get());
});
+ } else {
+ // Compact only once ReadBuffers() has nothing more to read
+ // (has_more == false).
+ // By then the read has consumed as much data as it can, so compaction has
+ // the fewest chunks to memmove.
+ // If we compacted after every batch, we would move the unread chunks again
+ // each time and end up with the same layout.
+ //
+ // The packets passed to OnTraceData() point into the buffer, so compaction
+ // has to wait until it returns.
+ // But we can't compact inline after it, because the consumer's
+ // OnTraceData() can call FreeBuffers() or destroy the service.
+ // So we post a task.
+ // The task looks up the session again in case FreeBuffers() removed it,
+ // and weak_runner_ drops the task if the service is destroyed.
+ weak_runner_.PostTask([this, tsid] {
+ TracingSession* tracing_session = GetTracingSession(tsid);
+ if (tracing_session)
+ MaybeCompactBuffers(tracing_session);
+ });
}
// Keep this as tail call, just in case the consumer re-enters.
@@ -69808,6 +78867,8 @@ bool TracingServiceImpl::ReadBuffersIntoFile(
return;
}
+ MaybeCompactBuffers(tracing_session);
+
if (tracing_session->fflush_post_write) {
// Ensure all data was written to the file.
base::FlushFile(tracing_session->write_into_file.get());
@@ -69890,6 +78951,19 @@ std::vector<TracePacket> TracingServiceImpl::ReadBuffers(
&packets);
}
+ if (!tracing_session->config.builtin_data_sources().disable_trace_config()) {
+ MaybeEmitTraceConfig(tracing_session, &packets);
+ }
+ if (!tracing_session->did_emit_initial_packets) {
+ EmitUuid(tracing_session, &packets);
+ }
+
+ // All packets emitted above (clock snapshot, trace config, uuid) will not be
+ // compressed, regardless of the config. This is to allow services that
+ // consume the trace on-device to take decisions based on the metadata of the
+ // trace, without having to uncompress.
+ const size_t skip_compression_of_first_n_packets = packets.size();
+
for (auto& snapshot : tracing_session->clock_snapshot_ring_buffer) {
PERFETTO_DCHECK(!snapshot.empty());
EmitClockSnapshot(tracing_session, std::move(snapshot), &packets);
@@ -69902,12 +78976,10 @@ std::vector<TracePacket> TracingServiceImpl::ReadBuffers(
}
if (!tracing_session->config.builtin_data_sources().disable_trace_config()) {
- MaybeEmitTraceConfig(tracing_session, &packets);
MaybeEmitCloneTrigger(tracing_session, &packets);
MaybeEmitReceivedTriggers(tracing_session, &packets);
}
if (!tracing_session->did_emit_initial_packets) {
- EmitUuid(tracing_session, &packets);
if (!tracing_session->config.builtin_data_sources()
.disable_extension_descriptors()) {
EmitExtensionDescriptors(tracing_session, &packets);
@@ -70061,7 +79133,8 @@ std::vector<TracePacket> TracingServiceImpl::ReadBuffers(
}
}
- MaybeCompressPackets(tracing_session, &packets);
+ MaybeCompressPackets(tracing_session, &packets,
+ skip_compression_of_first_n_packets);
if (!*has_more) {
// We've observed some extremely high memory usage by scudo after
@@ -70136,7 +79209,28 @@ void TracingServiceImpl::MaybeFilterPackets(TracingSession* tracing_session,
void TracingServiceImpl::MaybeCompressPackets(
TracingSession* tracing_session,
- [[maybe_unused]] std::vector<TracePacket>* packets) {
+ [[maybe_unused]] std::vector<TracePacket>* packets,
+ [[maybe_unused]] size_t skip_compression_of_first_n_packets) {
+ [[maybe_unused]] auto compress_with_fn = [&](auto compress_fn) {
+ if (skip_compression_of_first_n_packets == 0) {
+ compress_fn(packets);
+ return;
+ }
+ if (skip_compression_of_first_n_packets >= packets->size()) {
+ return;
+ }
+ const auto nskip =
+ static_cast<ssize_t>(skip_compression_of_first_n_packets);
+ std::vector<TracePacket> packets_to_compress(
+ std::make_move_iterator(packets->begin() + nskip),
+ std::make_move_iterator(packets->end()));
+ packets->erase(packets->begin() + nskip, packets->end());
+ compress_fn(&packets_to_compress);
+ packets->insert(packets->end(),
+ std::make_move_iterator(packets_to_compress.begin()),
+ std::make_move_iterator(packets_to_compress.end()));
+ };
+
// Compress with the codec the config selects, preferring the newest (highest
// proto field number) this build supports. Leaves the packets uncompressed if
// none is available.
@@ -70147,7 +79241,9 @@ void TracingServiceImpl::MaybeCompressPackets(
tracing_session->config.compression();
#if PERFETTO_BUILDFLAG(PERFETTO_ZSTD)
if (compression.has_zstd()) {
- ZstdCompressFn(packets, compression.zstd().level());
+ compress_with_fn([&](std::vector<TracePacket>* target) {
+ ZstdCompressFn(target, compression.zstd().level());
+ });
return;
}
#endif
@@ -70156,7 +79252,8 @@ void TracingServiceImpl::MaybeCompressPackets(
// predating `compression` still get compressed.
if (compression.has_deflate() || tracing_session->config.compression_type() ==
TraceConfig::COMPRESSION_TYPE_DEFLATE) {
- ZlibCompressFn(packets);
+ compress_with_fn(
+ [](std::vector<TracePacket>* target) { ZlibCompressFn(target); });
return;
}
#endif
@@ -70233,6 +79330,18 @@ bool TracingServiceImpl::WriteIntoFile(TracingSession* tracing_session,
return stop_writing_into_file;
}
+void TracingServiceImpl::MaybeCompactBuffers(TracingSession* tracing_session) {
+ PERFETTO_DCHECK_THREAD(thread_checker_);
+ if (!tracing_session->config.experimental_trace_buffer_v2_compaction())
+ return;
+
+ for (BufferID buf_id : tracing_session->buffers_index) {
+ auto tbuf_iter = buffers_.find(buf_id);
+ if (tbuf_iter != buffers_.end())
+ tbuf_iter->second->MaybeCompact();
+ }
+}
+
void TracingServiceImpl::FreeBuffers(TracingSessionID tsid,
const std::string& error) {
PERFETTO_DCHECK_THREAD(thread_checker_);
@@ -70307,12 +79416,12 @@ void TracingServiceImpl::MaybeSetUpProtoVm(
const RegisteredDataSource& ds_instance,
BufferID buffer_id) {
if (!ds_config.has_protovm_config() &&
- !ds_instance.descriptor.has_protovm_program()) {
+ ds_instance.descriptor.protovm_program_raw().empty()) {
return; // Data source has no ProtoVM
}
// TODO(keanmariotti): report the errors below in a trace packet as well, so
// that we can surface them on the UI.
- if (!ds_instance.descriptor.has_protovm_program()) {
+ if (ds_instance.descriptor.protovm_program_raw().empty()) {
PERFETTO_ELOG(
"ProtoVM config for data source %s specifies a ProtoVM, but the data "
"source instance (ProducerID: %d) doesn't specify a ProtoVM program",
@@ -70335,17 +79444,16 @@ void TracingServiceImpl::MaybeSetUpProtoVm(
}
auto it = buffers_.find(buffer_id);
PERFETTO_CHECK(it != buffers_.cend());
- if (it->second->buf_type() != TraceBuffer::BufType::kV2) {
+ TraceBufferProtoVms* protovms = it->second->protovms();
+ if (!protovms) {
PERFETTO_ELOG(
"Data source %s is configured to run a ProtoVM, but the corresponding "
- "buffer is not of type V2",
+ "buffer is of type V1, which cannot run one.",
ds_config.name().c_str());
return;
}
- auto* buffer = static_cast<TraceBufferV2*>(it->second.get());
- buffer->MaybeSetUpProtoVm(
- ds_config.name(),
- ds_instance.descriptor.protovm_program().SerializeAsString(),
+ protovms->MaybeSetUp(
+ ds_config.name(), ds_instance.descriptor.protovm_program_raw(),
ds_config.protovm_config().memory_limit_kb(), ds_instance.producer_id);
}
@@ -70628,6 +79736,22 @@ DataSourceInstance* TracingServiceImpl::SetupDataSource(
return nullptr;
}
+ const BufferID global_id = tracing_session->buffers_index[relative_buffer_id];
+ PERFETTO_DCHECK(global_id);
+
+ const TraceBuffer* target_buffer = GetBufferByID(global_id);
+ const bool supports_tracing_v2 =
+ (producer->protocol_abi_versions_ & kProtocolAbiV2) && target_buffer &&
+ target_buffer->supports_tracing_v2();
+ if (!(producer->protocol_abi_versions_ & kProtocolAbiV1) &&
+ !supports_tracing_v2) {
+ PERFETTO_ELOG(
+ "Cannot set up data source \"%s\" on producer \"%s\": "
+ "target_buffer %u supports no common protocol version",
+ ds_cfg.name().c_str(), producer->name_.c_str(), relative_buffer_id);
+ return nullptr;
+ }
+
// Create a copy of the DataSourceConfig specified in the trace config. This
// will be passed to the producer after translating the |target_buffer| id.
// The |target_buffer| parameter passed by the consumer in the trace config is
@@ -70656,6 +79780,14 @@ DataSourceInstance* TracingServiceImpl::SetupDataSource(
}
DataSourceConfig& ds_config = ds_instance->config;
+ // When v2 is unavailable, keep an absent field unset so startup configs
+ // still match in older SDKs.
+ //
+ // If the consumer supplied a value, overwrite it with the service's decision
+ // about whether this data source can use v2.
+ if (supports_tracing_v2 || ds_config.has_supports_tracing_v2())
+ ds_config.set_supports_tracing_v2(supports_tracing_v2);
+
ds_config.set_trace_duration_ms(tracing_session->config.duration_ms());
// Rationale for `if (prefer) set_prefer(true)`, rather than `set(prefer)`:
@@ -70680,8 +79812,6 @@ DataSourceInstance* TracingServiceImpl::SetupDataSource(
DataSourceConfig::SESSION_INITIATOR_UNSPECIFIED);
}
ds_config.set_tracing_session_id(tracing_session->id);
- BufferID global_id = tracing_session->buffers_index[relative_buffer_id];
- PERFETTO_DCHECK(global_id);
ds_config.set_target_buffer(global_id);
MaybeSetUpProtoVm(ds_config, data_source, global_id);
@@ -70928,6 +80058,11 @@ ProducerID TracingServiceImpl::GetNextProducerID() {
return last_producer_id_;
}
+void TracingServiceImpl::OnRingBufferChunksDiscarded(uint64_t count) {
+ PERFETTO_DCHECK_THREAD(thread_checker_);
+ chunks_discarded_ += count;
+}
+
TraceBuffer* TracingServiceImpl::GetBufferByID(BufferID buffer_id) {
auto buf_iter = buffers_.find(buffer_id);
if (buf_iter == buffers_.end())
@@ -70967,6 +80102,7 @@ void TracingServiceImpl::UpdateMemoryGuardrail() {
for (const auto& id_to_producer : producers_) {
if (id_to_producer.second->shared_memory())
total_buffer_bytes += id_to_producer.second->shared_memory()->size();
+ total_buffer_bytes += id_to_producer.second->ring_buffer_size_bytes();
}
// Sum up all the trace buffers.
@@ -70987,7 +80123,7 @@ void TracingServiceImpl::UpdateMemoryGuardrail() {
}
}
- // Set the guard rail to 64MB + the sum of all the buffers over a 30 second
+ // Set the guard rail to 32MB + the sum of all the buffers over a 30 second
// interval.
uint64_t guardrail = base::kWatchdogDefaultMemorySlack + total_buffer_bytes;
base::Watchdog::GetInstance()->SetMemoryLimit(guardrail, 30 * 1000);
@@ -71148,6 +80284,12 @@ void TracingServiceImpl::SetServiceTracePacketHeader(
protos::pbzero::TracePacket* tp) {
tp->set_trusted_uid(static_cast<int32_t>(uid_));
tp->set_trusted_packet_sequence_id(kServicePacketSequenceID);
+ // Every timestamp the service stamps on its own packets comes from
+ // GetBootTimeNs(), so declare the clock domain explicitly. Without this,
+ // Trace Processor's "no clock id" fallback resolves to the trace's primary
+ // clock, which is not BOOTTIME in general
+ // (https://github.com/google/perfetto/discussions/7112).
+ tp->set_timestamp_clock_id(protos::pbzero::BUILTIN_CLOCK_BOOTTIME);
// When a local machine was adopted (an in-process producer with a non-default
// machine id; see ConnectProducer), attribute the service's own packets to it
// so the trace has no separate host machine. Host and relay sessions leave
@@ -71359,6 +80501,9 @@ void TracingServiceImpl::EmitSystemInfo(std::vector<TracePacket>* packets) {
info->set_android_storage_model(sys_info.android_storage_model);
if (!sys_info.android_ram_model.empty())
info->set_android_ram_model(sys_info.android_ram_model);
+ for (const auto& compatible : sys_info.device_tree_compatibles) {
+ info->add_device_tree_compatibles(compatible);
+ }
if (!sys_info.android_serial_console.empty())
info->set_android_serial_console(sys_info.android_serial_console);
@@ -71377,6 +80522,8 @@ void TracingServiceImpl::EmitTraceProvenance(
TraceBuffer* buf = GetBufferByID(buf_id);
if (!buf)
continue;
+ // TODO(b/568173038): derive sequences from the buffer's own sequence
+ // tracking instead of writer_stats() once TraceBufferV1 is gone.
for (auto it = buf->writer_stats().GetIterator(); it; ++it) {
ProducerID producer_id;
WriterID writer_id;
@@ -71646,11 +80793,10 @@ void TracingServiceImpl::MaybeEmitProtoVmInstances(
for (auto buffer_id : tracing_session->buffers_index) {
auto it = buffers_.find(buffer_id);
PERFETTO_CHECK(it != buffers_.cend());
- if (it->second->buf_type() != TraceBuffer::BufType::kV2) {
+ const TraceBufferProtoVms* protovms = it->second->protovms();
+ if (!protovms)
continue;
- }
- auto* buffer = static_cast<TraceBufferV2*>(it->second.get());
- for (const TraceBufferV2::Vm& vm : buffer->GetProtoVmInstances()) {
+ for (const TraceBufferProtoVms::Vm& vm : protovms->instances()) {
auto* vm_instance = get_packet_protovms()->add_instance();
vm_instance->AppendString(
protos::pbzero::TracePacket::ProtoVms::Instance::kProgramFieldNumber,
@@ -71874,18 +81020,9 @@ base::Status TracingServiceImpl::FlushAndCloneSession(
continue;
// Some leftover data was left in the buffer. Recreate it to empty it.
- const auto buf_policy = buf->overwrite_policy();
- const auto buf_size = buf->size();
- const auto buf_type = buf->buf_type();
std::unique_ptr<TraceBuffer> old_buf = std::move(buf);
- switch (buf_type) {
- case TraceBuffer::kV1:
- buf = TraceBufferV1::Create(buf_size, buf_policy);
- break;
- case TraceBuffer::kV2:
- buf = TraceBufferV2::Create(buf_size, buf_policy);
- break;
- }
+ buf = CreateTraceBuffer(old_buf->buf_type(), old_buf->size(),
+ old_buf->overwrite_policy());
if (!buf) {
// This is extremely rare but could happen on 32-bit. If the new buffer
// allocation failed, put back the buffer where it was and fail the clone.
@@ -72054,18 +81191,9 @@ bool TracingServiceImpl::DoCloneBuffers(const TracingSession& src,
std::unique_ptr<TraceBuffer>& src_buf = buf_iter->second;
std::unique_ptr<TraceBuffer> new_buf;
if (src.config.buffers()[buf_idx].transfer_on_clone()) {
- const auto buf_policy = src_buf->overwrite_policy();
- const auto buf_size = src_buf->size();
- const auto buf_type = src_buf->buf_type();
new_buf = std::move(src_buf);
- switch (buf_type) {
- case TraceBuffer::kV1:
- src_buf = TraceBufferV1::Create(buf_size, buf_policy);
- break;
- case TraceBuffer::kV2:
- src_buf = TraceBufferV2::Create(buf_size, buf_policy);
- break;
- }
+ src_buf = CreateTraceBuffer(new_buf->buf_type(), new_buf->size(),
+ new_buf->overwrite_policy());
if (!src_buf) {
// If the allocation fails put the buffer back and let the code below
// handle the failure gracefully.
@@ -72395,7 +81523,9 @@ std::unique_ptr<ProducerEndpoint> InProcessTracingBackend::ConnectProducer(
args.producer_name, args.shmem_size_hint_bytes,
/*in_process=*/true,
TracingService::ProducerSMBScrapingMode::kEnabled,
- args.shmem_page_size_hint_bytes);
+ args.shmem_page_size_hint_bytes, /*shm=*/nullptr,
+ /*sdk_version=*/{}, /*machine_name=*/{},
+ kProtocolAbiV1 | kProtocolAbiV2);
}
std::unique_ptr<ConsumerEndpoint> InProcessTracingBackend::ConnectConsumer(
@@ -72436,16 +81566,18 @@ TracingService* InProcessTracingBackend::GetOrCreateService(
// gen_amalgamated expanded: #include "protos/perfetto/config/data_source_config.gen.h"
// gen_amalgamated expanded: #include "protos/perfetto/config/qnx/qnx_config.gen.h"
// gen_amalgamated expanded: #include "protos/perfetto/config/linux/journald_config.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/config/chrome/stack_sampling_profiler.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/config/chrome/sampling_heap_profiler.gen.h"
// gen_amalgamated expanded: #include "protos/perfetto/config/chrome/histogram_samples.gen.h"
// gen_amalgamated expanded: #include "protos/perfetto/config/system_info/system_info_config.gen.h"
// gen_amalgamated expanded: #include "protos/perfetto/config/track_event/track_event_config.gen.h"
// gen_amalgamated expanded: #include "protos/perfetto/config/test_config.gen.h"
// gen_amalgamated expanded: #include "protos/perfetto/config/sys_stats/sys_stats_config.gen.h"
// gen_amalgamated expanded: #include "protos/perfetto/common/sys_stats_counters.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/config/profiling/smaps_config.gen.h"
// gen_amalgamated expanded: #include "protos/perfetto/config/profiling/perf_event_config.gen.h"
// gen_amalgamated expanded: #include "protos/perfetto/common/perf_events.gen.h"
// gen_amalgamated expanded: #include "protos/perfetto/config/profiling/java_hprof_config.gen.h"
-// gen_amalgamated expanded: #include "protos/perfetto/config/profiling/smaps_config.gen.h"
// gen_amalgamated expanded: #include "protos/perfetto/config/profiling/heapprofd_config.gen.h"
// gen_amalgamated expanded: #include "protos/perfetto/config/process_stats/process_stats_config.gen.h"
// gen_amalgamated expanded: #include "protos/perfetto/config/statsd/statsd_tracing_config.gen.h"
@@ -72479,6 +81611,7 @@ TracingService* InProcessTracingBackend::GetOrCreateService(
// gen_amalgamated expanded: #include "protos/perfetto/config/android/app_wakelock_config.gen.h"
// gen_amalgamated expanded: #include "protos/perfetto/config/android/android_sdk_sysprop_guard_config.gen.h"
// gen_amalgamated expanded: #include "protos/perfetto/config/android/android_system_property_config.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/config/android/android_process_state_config.gen.h"
// gen_amalgamated expanded: #include "protos/perfetto/config/android/android_polled_state_config.gen.h"
// gen_amalgamated expanded: #include "protos/perfetto/config/android/android_log_config.gen.h"
// gen_amalgamated expanded: #include "protos/perfetto/common/android_log_constants.gen.h"
@@ -74287,16 +83420,18 @@ void EnableTracingRequest::Serialize(::protozero::Message* msg) const {
// gen_amalgamated expanded: #include "protos/perfetto/config/data_source_config.gen.h"
// gen_amalgamated expanded: #include "protos/perfetto/config/qnx/qnx_config.gen.h"
// gen_amalgamated expanded: #include "protos/perfetto/config/linux/journald_config.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/config/chrome/stack_sampling_profiler.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/config/chrome/sampling_heap_profiler.gen.h"
// gen_amalgamated expanded: #include "protos/perfetto/config/chrome/histogram_samples.gen.h"
// gen_amalgamated expanded: #include "protos/perfetto/config/system_info/system_info_config.gen.h"
// gen_amalgamated expanded: #include "protos/perfetto/config/track_event/track_event_config.gen.h"
// gen_amalgamated expanded: #include "protos/perfetto/config/test_config.gen.h"
// gen_amalgamated expanded: #include "protos/perfetto/config/sys_stats/sys_stats_config.gen.h"
// gen_amalgamated expanded: #include "protos/perfetto/common/sys_stats_counters.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/config/profiling/smaps_config.gen.h"
// gen_amalgamated expanded: #include "protos/perfetto/config/profiling/perf_event_config.gen.h"
// gen_amalgamated expanded: #include "protos/perfetto/common/perf_events.gen.h"
// gen_amalgamated expanded: #include "protos/perfetto/config/profiling/java_hprof_config.gen.h"
-// gen_amalgamated expanded: #include "protos/perfetto/config/profiling/smaps_config.gen.h"
// gen_amalgamated expanded: #include "protos/perfetto/config/profiling/heapprofd_config.gen.h"
// gen_amalgamated expanded: #include "protos/perfetto/config/process_stats/process_stats_config.gen.h"
// gen_amalgamated expanded: #include "protos/perfetto/config/priority_boost/priority_boost_config.gen.h"
@@ -74331,6 +83466,7 @@ void EnableTracingRequest::Serialize(::protozero::Message* msg) const {
// gen_amalgamated expanded: #include "protos/perfetto/config/android/app_wakelock_config.gen.h"
// gen_amalgamated expanded: #include "protos/perfetto/config/android/android_sdk_sysprop_guard_config.gen.h"
// gen_amalgamated expanded: #include "protos/perfetto/config/android/android_system_property_config.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/config/android/android_process_state_config.gen.h"
// gen_amalgamated expanded: #include "protos/perfetto/config/android/android_polled_state_config.gen.h"
// gen_amalgamated expanded: #include "protos/perfetto/config/android/android_log_config.gen.h"
// gen_amalgamated expanded: #include "protos/perfetto/common/android_log_constants.gen.h"
@@ -75834,6 +84970,199 @@ void RegisterDataSourceRequest::Serialize(::protozero::Message* msg) const {
}
+DrainV2RingBufferResponse::DrainV2RingBufferResponse() = default;
+DrainV2RingBufferResponse::~DrainV2RingBufferResponse() = default;
+DrainV2RingBufferResponse::DrainV2RingBufferResponse(const DrainV2RingBufferResponse&) = default;
+DrainV2RingBufferResponse& DrainV2RingBufferResponse::operator=(const DrainV2RingBufferResponse&) = default;
+DrainV2RingBufferResponse::DrainV2RingBufferResponse(DrainV2RingBufferResponse&&) noexcept = default;
+DrainV2RingBufferResponse& DrainV2RingBufferResponse::operator=(DrainV2RingBufferResponse&&) = default;
+
+bool DrainV2RingBufferResponse::operator==(const DrainV2RingBufferResponse& other) const {
+ return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_);
+}
+
+bool DrainV2RingBufferResponse::ParseFromArray(const void* raw, size_t size) {
+ unknown_fields_.clear();
+ bool packed_error = false;
+
+ ::protozero::ProtoDecoder dec(raw, size);
+ for (auto field = dec.ReadField(); field.valid(); field = dec.ReadField()) {
+ if (field.id() < _has_field_.size()) {
+ _has_field_.set(field.id());
+ }
+ switch (field.id()) {
+ default:
+ field.SerializeAndAppendTo(&unknown_fields_);
+ break;
+ }
+ }
+ return !packed_error && !dec.bytes_left();
+}
+
+std::string DrainV2RingBufferResponse::SerializeAsString() const {
+ ::protozero::internal::gen_helpers::MessageSerializer msg;
+ Serialize(msg.get());
+ return msg.SerializeAsString();
+}
+
+std::vector<uint8_t> DrainV2RingBufferResponse::SerializeAsArray() const {
+ ::protozero::internal::gen_helpers::MessageSerializer msg;
+ Serialize(msg.get());
+ return msg.SerializeAsArray();
+}
+
+void DrainV2RingBufferResponse::Serialize(::protozero::Message* msg) const {
+ protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
+}
+
+
+DrainV2RingBufferRequest::DrainV2RingBufferRequest() = default;
+DrainV2RingBufferRequest::~DrainV2RingBufferRequest() = default;
+DrainV2RingBufferRequest::DrainV2RingBufferRequest(const DrainV2RingBufferRequest&) = default;
+DrainV2RingBufferRequest& DrainV2RingBufferRequest::operator=(const DrainV2RingBufferRequest&) = default;
+DrainV2RingBufferRequest::DrainV2RingBufferRequest(DrainV2RingBufferRequest&&) noexcept = default;
+DrainV2RingBufferRequest& DrainV2RingBufferRequest::operator=(DrainV2RingBufferRequest&&) = default;
+
+bool DrainV2RingBufferRequest::operator==(const DrainV2RingBufferRequest& other) const {
+ return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_);
+}
+
+bool DrainV2RingBufferRequest::ParseFromArray(const void* raw, size_t size) {
+ unknown_fields_.clear();
+ bool packed_error = false;
+
+ ::protozero::ProtoDecoder dec(raw, size);
+ for (auto field = dec.ReadField(); field.valid(); field = dec.ReadField()) {
+ if (field.id() < _has_field_.size()) {
+ _has_field_.set(field.id());
+ }
+ switch (field.id()) {
+ default:
+ field.SerializeAndAppendTo(&unknown_fields_);
+ break;
+ }
+ }
+ return !packed_error && !dec.bytes_left();
+}
+
+std::string DrainV2RingBufferRequest::SerializeAsString() const {
+ ::protozero::internal::gen_helpers::MessageSerializer msg;
+ Serialize(msg.get());
+ return msg.SerializeAsString();
+}
+
+std::vector<uint8_t> DrainV2RingBufferRequest::SerializeAsArray() const {
+ ::protozero::internal::gen_helpers::MessageSerializer msg;
+ Serialize(msg.get());
+ return msg.SerializeAsArray();
+}
+
+void DrainV2RingBufferRequest::Serialize(::protozero::Message* msg) const {
+ protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
+}
+
+
+AttachV2RingBufferResponse::AttachV2RingBufferResponse() = default;
+AttachV2RingBufferResponse::~AttachV2RingBufferResponse() = default;
+AttachV2RingBufferResponse::AttachV2RingBufferResponse(const AttachV2RingBufferResponse&) = default;
+AttachV2RingBufferResponse& AttachV2RingBufferResponse::operator=(const AttachV2RingBufferResponse&) = default;
+AttachV2RingBufferResponse::AttachV2RingBufferResponse(AttachV2RingBufferResponse&&) noexcept = default;
+AttachV2RingBufferResponse& AttachV2RingBufferResponse::operator=(AttachV2RingBufferResponse&&) = default;
+
+bool AttachV2RingBufferResponse::operator==(const AttachV2RingBufferResponse& other) const {
+ return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_);
+}
+
+bool AttachV2RingBufferResponse::ParseFromArray(const void* raw, size_t size) {
+ unknown_fields_.clear();
+ bool packed_error = false;
+
+ ::protozero::ProtoDecoder dec(raw, size);
+ for (auto field = dec.ReadField(); field.valid(); field = dec.ReadField()) {
+ if (field.id() < _has_field_.size()) {
+ _has_field_.set(field.id());
+ }
+ switch (field.id()) {
+ default:
+ field.SerializeAndAppendTo(&unknown_fields_);
+ break;
+ }
+ }
+ return !packed_error && !dec.bytes_left();
+}
+
+std::string AttachV2RingBufferResponse::SerializeAsString() const {
+ ::protozero::internal::gen_helpers::MessageSerializer msg;
+ Serialize(msg.get());
+ return msg.SerializeAsString();
+}
+
+std::vector<uint8_t> AttachV2RingBufferResponse::SerializeAsArray() const {
+ ::protozero::internal::gen_helpers::MessageSerializer msg;
+ Serialize(msg.get());
+ return msg.SerializeAsArray();
+}
+
+void AttachV2RingBufferResponse::Serialize(::protozero::Message* msg) const {
+ protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
+}
+
+
+AttachV2RingBufferRequest::AttachV2RingBufferRequest() = default;
+AttachV2RingBufferRequest::~AttachV2RingBufferRequest() = default;
+AttachV2RingBufferRequest::AttachV2RingBufferRequest(const AttachV2RingBufferRequest&) = default;
+AttachV2RingBufferRequest& AttachV2RingBufferRequest::operator=(const AttachV2RingBufferRequest&) = default;
+AttachV2RingBufferRequest::AttachV2RingBufferRequest(AttachV2RingBufferRequest&&) noexcept = default;
+AttachV2RingBufferRequest& AttachV2RingBufferRequest::operator=(AttachV2RingBufferRequest&&) = default;
+
+bool AttachV2RingBufferRequest::operator==(const AttachV2RingBufferRequest& other) const {
+ return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
+ && ::protozero::internal::gen_helpers::EqualsField(chunk_size_bytes_, other.chunk_size_bytes_);
+}
+
+bool AttachV2RingBufferRequest::ParseFromArray(const void* raw, size_t size) {
+ unknown_fields_.clear();
+ bool packed_error = false;
+
+ ::protozero::ProtoDecoder dec(raw, size);
+ for (auto field = dec.ReadField(); field.valid(); field = dec.ReadField()) {
+ if (field.id() < _has_field_.size()) {
+ _has_field_.set(field.id());
+ }
+ switch (field.id()) {
+ case 1 /* chunk_size_bytes */:
+ field.get(&chunk_size_bytes_);
+ break;
+ default:
+ field.SerializeAndAppendTo(&unknown_fields_);
+ break;
+ }
+ }
+ return !packed_error && !dec.bytes_left();
+}
+
+std::string AttachV2RingBufferRequest::SerializeAsString() const {
+ ::protozero::internal::gen_helpers::MessageSerializer msg;
+ Serialize(msg.get());
+ return msg.SerializeAsString();
+}
+
+std::vector<uint8_t> AttachV2RingBufferRequest::SerializeAsArray() const {
+ ::protozero::internal::gen_helpers::MessageSerializer msg;
+ Serialize(msg.get());
+ return msg.SerializeAsArray();
+}
+
+void AttachV2RingBufferRequest::Serialize(::protozero::Message* msg) const {
+ // Field 1: chunk_size_bytes
+ if (_has_field_[1]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(1, chunk_size_bytes_, msg);
+ }
+
+ protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
+}
+
+
InitializeConnectionResponse::InitializeConnectionResponse() = default;
InitializeConnectionResponse::~InitializeConnectionResponse() = default;
InitializeConnectionResponse::InitializeConnectionResponse(const InitializeConnectionResponse&) = default;
@@ -75845,7 +85174,8 @@ bool InitializeConnectionResponse::operator==(const InitializeConnectionResponse
return ::protozero::internal::gen_helpers::EqualsField(unknown_fields_, other.unknown_fields_)
&& ::protozero::internal::gen_helpers::EqualsField(using_shmem_provided_by_producer_, other.using_shmem_provided_by_producer_)
&& ::protozero::internal::gen_helpers::EqualsField(direct_smb_patching_supported_, other.direct_smb_patching_supported_)
- && ::protozero::internal::gen_helpers::EqualsField(use_shmem_emulation_, other.use_shmem_emulation_);
+ && ::protozero::internal::gen_helpers::EqualsField(use_shmem_emulation_, other.use_shmem_emulation_)
+ && ::protozero::internal::gen_helpers::EqualsField(protocol_abi_versions_, other.protocol_abi_versions_);
}
bool InitializeConnectionResponse::ParseFromArray(const void* raw, size_t size) {
@@ -75867,6 +85197,9 @@ bool InitializeConnectionResponse::ParseFromArray(const void* raw, size_t size)
case 3 /* use_shmem_emulation */:
field.get(&use_shmem_emulation_);
break;
+ case 4 /* protocol_abi_versions */:
+ field.get(&protocol_abi_versions_);
+ break;
default:
field.SerializeAndAppendTo(&unknown_fields_);
break;
@@ -75903,6 +85236,11 @@ void InitializeConnectionResponse::Serialize(::protozero::Message* msg) const {
::protozero::internal::gen_helpers::SerializeTinyVarInt(3, use_shmem_emulation_, msg);
}
+ // Field 4: protocol_abi_versions
+ if (_has_field_[4]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(4, protocol_abi_versions_, msg);
+ }
+
protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
}
@@ -75922,7 +85260,8 @@ bool InitializeConnectionRequest::operator==(const InitializeConnectionRequest&
&& ::protozero::internal::gen_helpers::EqualsField(smb_scraping_mode_, other.smb_scraping_mode_)
&& ::protozero::internal::gen_helpers::EqualsField(producer_provided_shmem_, other.producer_provided_shmem_)
&& ::protozero::internal::gen_helpers::EqualsField(sdk_version_, other.sdk_version_)
- && ::protozero::internal::gen_helpers::EqualsField(shm_key_windows_, other.shm_key_windows_);
+ && ::protozero::internal::gen_helpers::EqualsField(shm_key_windows_, other.shm_key_windows_)
+ && ::protozero::internal::gen_helpers::EqualsField(supported_protocol_abi_versions_, other.supported_protocol_abi_versions_);
}
bool InitializeConnectionRequest::ParseFromArray(const void* raw, size_t size) {
@@ -75956,6 +85295,9 @@ bool InitializeConnectionRequest::ParseFromArray(const void* raw, size_t size) {
case 7 /* shm_key_windows */:
::protozero::internal::gen_helpers::DeserializeString(field, &shm_key_windows_);
break;
+ case 9 /* supported_protocol_abi_versions */:
+ field.get(&supported_protocol_abi_versions_);
+ break;
default:
field.SerializeAndAppendTo(&unknown_fields_);
break;
@@ -76012,6 +85354,11 @@ void InitializeConnectionRequest::Serialize(::protozero::Message* msg) const {
::protozero::internal::gen_helpers::SerializeString(7, shm_key_windows_, msg);
}
+ // Field 9: supported_protocol_abi_versions
+ if (_has_field_[9]) {
+ ::protozero::internal::gen_helpers::SerializeVarInt(9, supported_protocol_abi_versions_, msg);
+ }
+
protozero::internal::gen_helpers::SerializeUnknownFields(unknown_fields_, msg);
}
@@ -78869,62 +88216,6 @@ std::unique_ptr<LinuxFileWatch> WatchUnixSocketCreation(
} // namespace perfetto
// gen_amalgamated begin source: src/ipc/buffered_frame_deserializer.cc
// gen_amalgamated begin header: src/ipc/buffered_frame_deserializer.h
-// gen_amalgamated begin header: include/perfetto/ext/ipc/basic_types.h
-/*
- * 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.
- */
-
-#ifndef INCLUDE_PERFETTO_EXT_IPC_BASIC_TYPES_H_
-#define INCLUDE_PERFETTO_EXT_IPC_BASIC_TYPES_H_
-
-#include <stddef.h>
-#include <stdint.h>
-#include <sys/types.h>
-
-// gen_amalgamated expanded: #include "perfetto/ext/base/utils.h"
-// gen_amalgamated expanded: #include "perfetto/protozero/cpp_message_obj.h"
-
-namespace perfetto {
-namespace ipc {
-
-using ProtoMessage = ::protozero::CppMessageObj;
-using ServiceID = uint32_t;
-using MethodID = uint32_t;
-using ClientID = uint64_t;
-using RequestID = uint64_t;
-
-#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
-// AF_UNIX on Windows is supported only on Windows 10 from build 17063.
-// Also it doesn't bring major advantages compared to a TCP socket.
-// See go/perfetto-win .
-constexpr bool kUseTCPSocket = true;
-#else
-// Android, Linux, Mac, Fuchsia use local sockets.
-constexpr bool kUseTCPSocket = false;
-#endif
-
-// This determines the maximum size allowed for an IPC message. Trying to send
-// or receive a larger message will hit DCHECK(s) and auto-disconnect.
-constexpr size_t kIPCBufferSize = 128 * 1024;
-
-constexpr uid_t kInvalidUid = static_cast<uid_t>(-1);
-
-} // namespace ipc
-} // namespace perfetto
-
-#endif // INCLUDE_PERFETTO_EXT_IPC_BASIC_TYPES_H_
/*
* Copyright (C) 2017 The Android Open Source Project
*
@@ -79123,8 +88414,7 @@ BufferedFrameDeserializer::BeginReceive() {
// Surely we are going to use at least the first page, but we may not need
// the rest for a bit.
- const auto page_size = base::GetSysPageSize();
- buf_.AdviseDontNeed(buf() + page_size, capacity_ - page_size);
+ buf_.AdviseDontNeedAfter(base::GetSysPageSize());
}
PERFETTO_CHECK(capacity_ > size_);
@@ -79211,11 +88501,8 @@ bool BufferedFrameDeserializer::EndReceive(size_t recv_size) {
if (consumed_size > page_size) {
size_t size_rounded_up = (size_ / page_size + 1) * page_size;
if (size_rounded_up < capacity_) {
- char* madvise_begin = buf() + size_rounded_up;
- const size_t madvise_size = capacity_ - size_rounded_up;
- PERFETTO_CHECK(madvise_begin > buf() + size_);
- PERFETTO_CHECK(madvise_begin + madvise_size <= buf() + capacity_);
- buf_.AdviseDontNeed(madvise_begin, madvise_size);
+ PERFETTO_CHECK(size_rounded_up > size_);
+ buf_.AdviseDontNeedAfter(size_rounded_up);
}
}
}
@@ -81680,1188 +90967,494 @@ void ConsumerPortProxy::Attach(const AttachRequest& request, DeferredAttachRespo
fd);
}
-void ConsumerPortProxy::GetTraceStats(const GetTraceStatsRequest& request, DeferredGetTraceStatsResponse reply, int fd) {
- BeginInvoke("GetTraceStats", request, ::perfetto::ipc::DeferredBase(std::move(reply)),
- fd);
-}
-
-void ConsumerPortProxy::ObserveEvents(const ObserveEventsRequest& request, DeferredObserveEventsResponse reply, int fd) {
- BeginInvoke("ObserveEvents", request, ::perfetto::ipc::DeferredBase(std::move(reply)),
- fd);
-}
-
-void ConsumerPortProxy::QueryServiceState(const QueryServiceStateRequest& request, DeferredQueryServiceStateResponse reply, int fd) {
- BeginInvoke("QueryServiceState", request, ::perfetto::ipc::DeferredBase(std::move(reply)),
- fd);
-}
-
-void ConsumerPortProxy::QueryCapabilities(const QueryCapabilitiesRequest& request, DeferredQueryCapabilitiesResponse reply, int fd) {
- BeginInvoke("QueryCapabilities", request, ::perfetto::ipc::DeferredBase(std::move(reply)),
- fd);
-}
-
-void ConsumerPortProxy::SaveTraceForBugreport(const SaveTraceForBugreportRequest& request, DeferredSaveTraceForBugreportResponse reply, int fd) {
- BeginInvoke("SaveTraceForBugreport", request, ::perfetto::ipc::DeferredBase(std::move(reply)),
- fd);
-}
-
-void ConsumerPortProxy::CloneSession(const CloneSessionRequest& request, DeferredCloneSessionResponse reply, int fd) {
- BeginInvoke("CloneSession", request, ::perfetto::ipc::DeferredBase(std::move(reply)),
- fd);
-}
-} // namespace perfetto
-} // namespace protos
-} // namespace gen
-// gen_amalgamated begin source: gen/protos/perfetto/ipc/producer_port.ipc.cc
-// gen_amalgamated begin header: gen/protos/perfetto/ipc/producer_port.ipc.h
-// DO NOT EDIT. Autogenerated by Perfetto IPC
-#ifndef PERFETTO_PROTOS_PROTOS_PERFETTO_IPC_PRODUCER_PORT_PROTO_H_
-#define PERFETTO_PROTOS_PROTOS_PERFETTO_IPC_PRODUCER_PORT_PROTO_H_
-
-// gen_amalgamated expanded: #include "perfetto/ext/ipc/deferred.h"
-// gen_amalgamated expanded: #include "perfetto/ext/ipc/service.h"
-// gen_amalgamated expanded: #include "perfetto/ext/ipc/service_descriptor.h"
-// gen_amalgamated expanded: #include "perfetto/ext/ipc/service_proxy.h"
-
-// gen_amalgamated expanded: #include "protos/perfetto/ipc/producer_port.gen.h"
-// gen_amalgamated expanded: #include "protos/perfetto/common/commit_data_request.gen.h"
-// gen_amalgamated expanded: #include "protos/perfetto/config/data_source_config.gen.h"
-// gen_amalgamated expanded: #include "protos/perfetto/common/data_source_descriptor.gen.h"
-
-namespace perfetto {
-namespace protos {
-namespace gen {
-
-class ProducerPort : public ::perfetto::ipc::Service {
- private:
- static ::perfetto::ipc::ServiceDescriptor* NewDescriptor();
-
- public:
- ~ProducerPort() override;
-
- static const ::perfetto::ipc::ServiceDescriptor& GetDescriptorStatic();
-
- // Service implementation.
- const ::perfetto::ipc::ServiceDescriptor& GetDescriptor() override;
-
- // Methods from the .proto file
- using DeferredInitializeConnectionResponse = ::perfetto::ipc::Deferred<InitializeConnectionResponse>;
- virtual void InitializeConnection(const InitializeConnectionRequest&, DeferredInitializeConnectionResponse) = 0;
-
- using DeferredRegisterDataSourceResponse = ::perfetto::ipc::Deferred<RegisterDataSourceResponse>;
- virtual void RegisterDataSource(const RegisterDataSourceRequest&, DeferredRegisterDataSourceResponse) = 0;
-
- using DeferredUnregisterDataSourceResponse = ::perfetto::ipc::Deferred<UnregisterDataSourceResponse>;
- virtual void UnregisterDataSource(const UnregisterDataSourceRequest&, DeferredUnregisterDataSourceResponse) = 0;
-
- using DeferredCommitDataResponse = ::perfetto::ipc::Deferred<CommitDataResponse>;
- virtual void CommitData(const CommitDataRequest&, DeferredCommitDataResponse) = 0;
-
- using DeferredGetAsyncCommandResponse = ::perfetto::ipc::Deferred<GetAsyncCommandResponse>;
- virtual void GetAsyncCommand(const GetAsyncCommandRequest&, DeferredGetAsyncCommandResponse) = 0;
-
- using DeferredRegisterTraceWriterResponse = ::perfetto::ipc::Deferred<RegisterTraceWriterResponse>;
- virtual void RegisterTraceWriter(const RegisterTraceWriterRequest&, DeferredRegisterTraceWriterResponse) = 0;
-
- using DeferredUnregisterTraceWriterResponse = ::perfetto::ipc::Deferred<UnregisterTraceWriterResponse>;
- virtual void UnregisterTraceWriter(const UnregisterTraceWriterRequest&, DeferredUnregisterTraceWriterResponse) = 0;
-
- using DeferredNotifyDataSourceStartedResponse = ::perfetto::ipc::Deferred<NotifyDataSourceStartedResponse>;
- virtual void NotifyDataSourceStarted(const NotifyDataSourceStartedRequest&, DeferredNotifyDataSourceStartedResponse) = 0;
-
- using DeferredNotifyDataSourceStoppedResponse = ::perfetto::ipc::Deferred<NotifyDataSourceStoppedResponse>;
- virtual void NotifyDataSourceStopped(const NotifyDataSourceStoppedRequest&, DeferredNotifyDataSourceStoppedResponse) = 0;
-
- using DeferredActivateTriggersResponse = ::perfetto::ipc::Deferred<ActivateTriggersResponse>;
- virtual void ActivateTriggers(const ActivateTriggersRequest&, DeferredActivateTriggersResponse) = 0;
-
- using DeferredSyncResponse = ::perfetto::ipc::Deferred<SyncResponse>;
- virtual void Sync(const SyncRequest&, DeferredSyncResponse) = 0;
-
- using DeferredUpdateDataSourceResponse = ::perfetto::ipc::Deferred<UpdateDataSourceResponse>;
- virtual void UpdateDataSource(const UpdateDataSourceRequest&, DeferredUpdateDataSourceResponse) = 0;
-
-};
-
-
-class ProducerPortProxy : public ::perfetto::ipc::ServiceProxy {
- public:
- explicit ProducerPortProxy(::perfetto::ipc::ServiceProxy::EventListener*);
- ~ProducerPortProxy() override;
-
- // ServiceProxy implementation.
- const ::perfetto::ipc::ServiceDescriptor& GetDescriptor() override;
-
- // Methods from the .proto file
- using DeferredInitializeConnectionResponse = ::perfetto::ipc::Deferred<InitializeConnectionResponse>;
- void InitializeConnection(const InitializeConnectionRequest&, DeferredInitializeConnectionResponse, int fd = -1);
-
- using DeferredRegisterDataSourceResponse = ::perfetto::ipc::Deferred<RegisterDataSourceResponse>;
- void RegisterDataSource(const RegisterDataSourceRequest&, DeferredRegisterDataSourceResponse, int fd = -1);
-
- using DeferredUnregisterDataSourceResponse = ::perfetto::ipc::Deferred<UnregisterDataSourceResponse>;
- void UnregisterDataSource(const UnregisterDataSourceRequest&, DeferredUnregisterDataSourceResponse, int fd = -1);
-
- using DeferredCommitDataResponse = ::perfetto::ipc::Deferred<CommitDataResponse>;
- void CommitData(const CommitDataRequest&, DeferredCommitDataResponse, int fd = -1);
-
- using DeferredGetAsyncCommandResponse = ::perfetto::ipc::Deferred<GetAsyncCommandResponse>;
- void GetAsyncCommand(const GetAsyncCommandRequest&, DeferredGetAsyncCommandResponse, int fd = -1);
-
- using DeferredRegisterTraceWriterResponse = ::perfetto::ipc::Deferred<RegisterTraceWriterResponse>;
- void RegisterTraceWriter(const RegisterTraceWriterRequest&, DeferredRegisterTraceWriterResponse, int fd = -1);
-
- using DeferredUnregisterTraceWriterResponse = ::perfetto::ipc::Deferred<UnregisterTraceWriterResponse>;
- void UnregisterTraceWriter(const UnregisterTraceWriterRequest&, DeferredUnregisterTraceWriterResponse, int fd = -1);
-
- using DeferredNotifyDataSourceStartedResponse = ::perfetto::ipc::Deferred<NotifyDataSourceStartedResponse>;
- void NotifyDataSourceStarted(const NotifyDataSourceStartedRequest&, DeferredNotifyDataSourceStartedResponse, int fd = -1);
-
- using DeferredNotifyDataSourceStoppedResponse = ::perfetto::ipc::Deferred<NotifyDataSourceStoppedResponse>;
- void NotifyDataSourceStopped(const NotifyDataSourceStoppedRequest&, DeferredNotifyDataSourceStoppedResponse, int fd = -1);
-
- using DeferredActivateTriggersResponse = ::perfetto::ipc::Deferred<ActivateTriggersResponse>;
- void ActivateTriggers(const ActivateTriggersRequest&, DeferredActivateTriggersResponse, int fd = -1);
-
- using DeferredSyncResponse = ::perfetto::ipc::Deferred<SyncResponse>;
- void Sync(const SyncRequest&, DeferredSyncResponse, int fd = -1);
-
- using DeferredUpdateDataSourceResponse = ::perfetto::ipc::Deferred<UpdateDataSourceResponse>;
- void UpdateDataSource(const UpdateDataSourceRequest&, DeferredUpdateDataSourceResponse, int fd = -1);
-
-};
-
-} // namespace perfetto
-} // namespace protos
-} // namespace gen
-
-#endif // PERFETTO_PROTOS_PROTOS_PERFETTO_IPC_PRODUCER_PORT_PROTO_H_
-// DO NOT EDIT. Autogenerated by Perfetto IPC
-// gen_amalgamated expanded: #include "protos/perfetto/ipc/producer_port.ipc.h"
-// gen_amalgamated expanded: #include "perfetto/ext/ipc/codegen_helpers.h"
-
-#include <memory>
-
-namespace perfetto {
-namespace protos {
-namespace gen {
-::perfetto::ipc::ServiceDescriptor* ProducerPort::NewDescriptor() {
- auto* desc = new ::perfetto::ipc::ServiceDescriptor();
- desc->service_name = "ProducerPort";
-
- desc->methods.emplace_back(::perfetto::ipc::ServiceDescriptor::Method{
- "InitializeConnection",
- &_IPC_Decoder<InitializeConnectionRequest>,
- &_IPC_Decoder<InitializeConnectionResponse>,
- &_IPC_Invoker<ProducerPort, InitializeConnectionRequest, InitializeConnectionResponse, &ProducerPort::InitializeConnection>});
-
- desc->methods.emplace_back(::perfetto::ipc::ServiceDescriptor::Method{
- "RegisterDataSource",
- &_IPC_Decoder<RegisterDataSourceRequest>,
- &_IPC_Decoder<RegisterDataSourceResponse>,
- &_IPC_Invoker<ProducerPort, RegisterDataSourceRequest, RegisterDataSourceResponse, &ProducerPort::RegisterDataSource>});
-
- desc->methods.emplace_back(::perfetto::ipc::ServiceDescriptor::Method{
- "UnregisterDataSource",
- &_IPC_Decoder<UnregisterDataSourceRequest>,
- &_IPC_Decoder<UnregisterDataSourceResponse>,
- &_IPC_Invoker<ProducerPort, UnregisterDataSourceRequest, UnregisterDataSourceResponse, &ProducerPort::UnregisterDataSource>});
-
- desc->methods.emplace_back(::perfetto::ipc::ServiceDescriptor::Method{
- "CommitData",
- &_IPC_Decoder<CommitDataRequest>,
- &_IPC_Decoder<CommitDataResponse>,
- &_IPC_Invoker<ProducerPort, CommitDataRequest, CommitDataResponse, &ProducerPort::CommitData>});
-
- desc->methods.emplace_back(::perfetto::ipc::ServiceDescriptor::Method{
- "GetAsyncCommand",
- &_IPC_Decoder<GetAsyncCommandRequest>,
- &_IPC_Decoder<GetAsyncCommandResponse>,
- &_IPC_Invoker<ProducerPort, GetAsyncCommandRequest, GetAsyncCommandResponse, &ProducerPort::GetAsyncCommand>});
-
- desc->methods.emplace_back(::perfetto::ipc::ServiceDescriptor::Method{
- "RegisterTraceWriter",
- &_IPC_Decoder<RegisterTraceWriterRequest>,
- &_IPC_Decoder<RegisterTraceWriterResponse>,
- &_IPC_Invoker<ProducerPort, RegisterTraceWriterRequest, RegisterTraceWriterResponse, &ProducerPort::RegisterTraceWriter>});
-
- desc->methods.emplace_back(::perfetto::ipc::ServiceDescriptor::Method{
- "UnregisterTraceWriter",
- &_IPC_Decoder<UnregisterTraceWriterRequest>,
- &_IPC_Decoder<UnregisterTraceWriterResponse>,
- &_IPC_Invoker<ProducerPort, UnregisterTraceWriterRequest, UnregisterTraceWriterResponse, &ProducerPort::UnregisterTraceWriter>});
-
- desc->methods.emplace_back(::perfetto::ipc::ServiceDescriptor::Method{
- "NotifyDataSourceStarted",
- &_IPC_Decoder<NotifyDataSourceStartedRequest>,
- &_IPC_Decoder<NotifyDataSourceStartedResponse>,
- &_IPC_Invoker<ProducerPort, NotifyDataSourceStartedRequest, NotifyDataSourceStartedResponse, &ProducerPort::NotifyDataSourceStarted>});
-
- desc->methods.emplace_back(::perfetto::ipc::ServiceDescriptor::Method{
- "NotifyDataSourceStopped",
- &_IPC_Decoder<NotifyDataSourceStoppedRequest>,
- &_IPC_Decoder<NotifyDataSourceStoppedResponse>,
- &_IPC_Invoker<ProducerPort, NotifyDataSourceStoppedRequest, NotifyDataSourceStoppedResponse, &ProducerPort::NotifyDataSourceStopped>});
-
- desc->methods.emplace_back(::perfetto::ipc::ServiceDescriptor::Method{
- "ActivateTriggers",
- &_IPC_Decoder<ActivateTriggersRequest>,
- &_IPC_Decoder<ActivateTriggersResponse>,
- &_IPC_Invoker<ProducerPort, ActivateTriggersRequest, ActivateTriggersResponse, &ProducerPort::ActivateTriggers>});
-
- desc->methods.emplace_back(::perfetto::ipc::ServiceDescriptor::Method{
- "Sync",
- &_IPC_Decoder<SyncRequest>,
- &_IPC_Decoder<SyncResponse>,
- &_IPC_Invoker<ProducerPort, SyncRequest, SyncResponse, &ProducerPort::Sync>});
-
- desc->methods.emplace_back(::perfetto::ipc::ServiceDescriptor::Method{
- "UpdateDataSource",
- &_IPC_Decoder<UpdateDataSourceRequest>,
- &_IPC_Decoder<UpdateDataSourceResponse>,
- &_IPC_Invoker<ProducerPort, UpdateDataSourceRequest, UpdateDataSourceResponse, &ProducerPort::UpdateDataSource>});
- desc->methods.shrink_to_fit();
- return desc;
-}
-
-
-const ::perfetto::ipc::ServiceDescriptor& ProducerPort::GetDescriptorStatic() {
- static auto* instance = NewDescriptor();
- return *instance;
-}
-
-// Host-side definitions.
-ProducerPort::~ProducerPort() = default;
-
-const ::perfetto::ipc::ServiceDescriptor& ProducerPort::GetDescriptor() {
- return GetDescriptorStatic();
-}
-
-// Client-side definitions.
-ProducerPortProxy::ProducerPortProxy(::perfetto::ipc::ServiceProxy::EventListener* event_listener)
- : ::perfetto::ipc::ServiceProxy(event_listener) {}
-
-ProducerPortProxy::~ProducerPortProxy() = default;
-
-const ::perfetto::ipc::ServiceDescriptor& ProducerPortProxy::GetDescriptor() {
- return ProducerPort::GetDescriptorStatic();
-}
-
-void ProducerPortProxy::InitializeConnection(const InitializeConnectionRequest& request, DeferredInitializeConnectionResponse reply, int fd) {
- BeginInvoke("InitializeConnection", request, ::perfetto::ipc::DeferredBase(std::move(reply)),
- fd);
-}
-
-void ProducerPortProxy::RegisterDataSource(const RegisterDataSourceRequest& request, DeferredRegisterDataSourceResponse reply, int fd) {
- BeginInvoke("RegisterDataSource", request, ::perfetto::ipc::DeferredBase(std::move(reply)),
- fd);
-}
-
-void ProducerPortProxy::UnregisterDataSource(const UnregisterDataSourceRequest& request, DeferredUnregisterDataSourceResponse reply, int fd) {
- BeginInvoke("UnregisterDataSource", request, ::perfetto::ipc::DeferredBase(std::move(reply)),
- fd);
-}
-
-void ProducerPortProxy::CommitData(const CommitDataRequest& request, DeferredCommitDataResponse reply, int fd) {
- BeginInvoke("CommitData", request, ::perfetto::ipc::DeferredBase(std::move(reply)),
- fd);
-}
-
-void ProducerPortProxy::GetAsyncCommand(const GetAsyncCommandRequest& request, DeferredGetAsyncCommandResponse reply, int fd) {
- BeginInvoke("GetAsyncCommand", request, ::perfetto::ipc::DeferredBase(std::move(reply)),
- fd);
-}
-
-void ProducerPortProxy::RegisterTraceWriter(const RegisterTraceWriterRequest& request, DeferredRegisterTraceWriterResponse reply, int fd) {
- BeginInvoke("RegisterTraceWriter", request, ::perfetto::ipc::DeferredBase(std::move(reply)),
- fd);
-}
-
-void ProducerPortProxy::UnregisterTraceWriter(const UnregisterTraceWriterRequest& request, DeferredUnregisterTraceWriterResponse reply, int fd) {
- BeginInvoke("UnregisterTraceWriter", request, ::perfetto::ipc::DeferredBase(std::move(reply)),
- fd);
-}
-
-void ProducerPortProxy::NotifyDataSourceStarted(const NotifyDataSourceStartedRequest& request, DeferredNotifyDataSourceStartedResponse reply, int fd) {
- BeginInvoke("NotifyDataSourceStarted", request, ::perfetto::ipc::DeferredBase(std::move(reply)),
- fd);
-}
-
-void ProducerPortProxy::NotifyDataSourceStopped(const NotifyDataSourceStoppedRequest& request, DeferredNotifyDataSourceStoppedResponse reply, int fd) {
- BeginInvoke("NotifyDataSourceStopped", request, ::perfetto::ipc::DeferredBase(std::move(reply)),
- fd);
-}
-
-void ProducerPortProxy::ActivateTriggers(const ActivateTriggersRequest& request, DeferredActivateTriggersResponse reply, int fd) {
- BeginInvoke("ActivateTriggers", request, ::perfetto::ipc::DeferredBase(std::move(reply)),
- fd);
-}
-
-void ProducerPortProxy::Sync(const SyncRequest& request, DeferredSyncResponse reply, int fd) {
- BeginInvoke("Sync", request, ::perfetto::ipc::DeferredBase(std::move(reply)),
- fd);
-}
-
-void ProducerPortProxy::UpdateDataSource(const UpdateDataSourceRequest& request, DeferredUpdateDataSourceResponse reply, int fd) {
- BeginInvoke("UpdateDataSource", request, ::perfetto::ipc::DeferredBase(std::move(reply)),
- fd);
-}
-} // namespace perfetto
-} // namespace protos
-} // namespace gen
-// gen_amalgamated begin source: gen/protos/perfetto/ipc/relay_port.ipc.cc
-// gen_amalgamated begin header: gen/protos/perfetto/ipc/relay_port.ipc.h
-// DO NOT EDIT. Autogenerated by Perfetto IPC
-#ifndef PERFETTO_PROTOS_PROTOS_PERFETTO_IPC_RELAY_PORT_PROTO_H_
-#define PERFETTO_PROTOS_PROTOS_PERFETTO_IPC_RELAY_PORT_PROTO_H_
-
-// gen_amalgamated expanded: #include "perfetto/ext/ipc/deferred.h"
-// gen_amalgamated expanded: #include "perfetto/ext/ipc/service.h"
-// gen_amalgamated expanded: #include "perfetto/ext/ipc/service_descriptor.h"
-// gen_amalgamated expanded: #include "perfetto/ext/ipc/service_proxy.h"
-
-// gen_amalgamated expanded: #include "protos/perfetto/ipc/relay_port.gen.h"
-// gen_amalgamated expanded: #include "protos/perfetto/common/system_info.gen.h"
-
-namespace perfetto {
-namespace protos {
-namespace gen {
-
-class RelayPort : public ::perfetto::ipc::Service {
- private:
- static ::perfetto::ipc::ServiceDescriptor* NewDescriptor();
-
- public:
- ~RelayPort() override;
-
- static const ::perfetto::ipc::ServiceDescriptor& GetDescriptorStatic();
-
- // Service implementation.
- const ::perfetto::ipc::ServiceDescriptor& GetDescriptor() override;
-
- // Methods from the .proto file
- using DeferredInitRelayResponse = ::perfetto::ipc::Deferred<InitRelayResponse>;
- virtual void InitRelay(const InitRelayRequest&, DeferredInitRelayResponse) = 0;
-
- using DeferredSyncClockResponse = ::perfetto::ipc::Deferred<SyncClockResponse>;
- virtual void SyncClock(const SyncClockRequest&, DeferredSyncClockResponse) = 0;
-
-};
-
-
-class RelayPortProxy : public ::perfetto::ipc::ServiceProxy {
- public:
- explicit RelayPortProxy(::perfetto::ipc::ServiceProxy::EventListener*);
- ~RelayPortProxy() override;
-
- // ServiceProxy implementation.
- const ::perfetto::ipc::ServiceDescriptor& GetDescriptor() override;
-
- // Methods from the .proto file
- using DeferredInitRelayResponse = ::perfetto::ipc::Deferred<InitRelayResponse>;
- void InitRelay(const InitRelayRequest&, DeferredInitRelayResponse, int fd = -1);
-
- using DeferredSyncClockResponse = ::perfetto::ipc::Deferred<SyncClockResponse>;
- void SyncClock(const SyncClockRequest&, DeferredSyncClockResponse, int fd = -1);
-
-};
-
-} // namespace perfetto
-} // namespace protos
-} // namespace gen
-
-#endif // PERFETTO_PROTOS_PROTOS_PERFETTO_IPC_RELAY_PORT_PROTO_H_
-// DO NOT EDIT. Autogenerated by Perfetto IPC
-// gen_amalgamated expanded: #include "protos/perfetto/ipc/relay_port.ipc.h"
-// gen_amalgamated expanded: #include "perfetto/ext/ipc/codegen_helpers.h"
-
-#include <memory>
-
-namespace perfetto {
-namespace protos {
-namespace gen {
-::perfetto::ipc::ServiceDescriptor* RelayPort::NewDescriptor() {
- auto* desc = new ::perfetto::ipc::ServiceDescriptor();
- desc->service_name = "RelayPort";
-
- desc->methods.emplace_back(::perfetto::ipc::ServiceDescriptor::Method{
- "InitRelay",
- &_IPC_Decoder<InitRelayRequest>,
- &_IPC_Decoder<InitRelayResponse>,
- &_IPC_Invoker<RelayPort, InitRelayRequest, InitRelayResponse, &RelayPort::InitRelay>});
-
- desc->methods.emplace_back(::perfetto::ipc::ServiceDescriptor::Method{
- "SyncClock",
- &_IPC_Decoder<SyncClockRequest>,
- &_IPC_Decoder<SyncClockResponse>,
- &_IPC_Invoker<RelayPort, SyncClockRequest, SyncClockResponse, &RelayPort::SyncClock>});
- desc->methods.shrink_to_fit();
- return desc;
-}
-
-
-const ::perfetto::ipc::ServiceDescriptor& RelayPort::GetDescriptorStatic() {
- static auto* instance = NewDescriptor();
- return *instance;
-}
-
-// Host-side definitions.
-RelayPort::~RelayPort() = default;
-
-const ::perfetto::ipc::ServiceDescriptor& RelayPort::GetDescriptor() {
- return GetDescriptorStatic();
+void ConsumerPortProxy::GetTraceStats(const GetTraceStatsRequest& request, DeferredGetTraceStatsResponse reply, int fd) {
+ BeginInvoke("GetTraceStats", request, ::perfetto::ipc::DeferredBase(std::move(reply)),
+ fd);
}
-// Client-side definitions.
-RelayPortProxy::RelayPortProxy(::perfetto::ipc::ServiceProxy::EventListener* event_listener)
- : ::perfetto::ipc::ServiceProxy(event_listener) {}
+void ConsumerPortProxy::ObserveEvents(const ObserveEventsRequest& request, DeferredObserveEventsResponse reply, int fd) {
+ BeginInvoke("ObserveEvents", request, ::perfetto::ipc::DeferredBase(std::move(reply)),
+ fd);
+}
-RelayPortProxy::~RelayPortProxy() = default;
+void ConsumerPortProxy::QueryServiceState(const QueryServiceStateRequest& request, DeferredQueryServiceStateResponse reply, int fd) {
+ BeginInvoke("QueryServiceState", request, ::perfetto::ipc::DeferredBase(std::move(reply)),
+ fd);
+}
-const ::perfetto::ipc::ServiceDescriptor& RelayPortProxy::GetDescriptor() {
- return RelayPort::GetDescriptorStatic();
+void ConsumerPortProxy::QueryCapabilities(const QueryCapabilitiesRequest& request, DeferredQueryCapabilitiesResponse reply, int fd) {
+ BeginInvoke("QueryCapabilities", request, ::perfetto::ipc::DeferredBase(std::move(reply)),
+ fd);
}
-void RelayPortProxy::InitRelay(const InitRelayRequest& request, DeferredInitRelayResponse reply, int fd) {
- BeginInvoke("InitRelay", request, ::perfetto::ipc::DeferredBase(std::move(reply)),
+void ConsumerPortProxy::SaveTraceForBugreport(const SaveTraceForBugreportRequest& request, DeferredSaveTraceForBugreportResponse reply, int fd) {
+ BeginInvoke("SaveTraceForBugreport", request, ::perfetto::ipc::DeferredBase(std::move(reply)),
fd);
}
-void RelayPortProxy::SyncClock(const SyncClockRequest& request, DeferredSyncClockResponse reply, int fd) {
- BeginInvoke("SyncClock", request, ::perfetto::ipc::DeferredBase(std::move(reply)),
+void ConsumerPortProxy::CloneSession(const CloneSessionRequest& request, DeferredCloneSessionResponse reply, int fd) {
+ BeginInvoke("CloneSession", request, ::perfetto::ipc::DeferredBase(std::move(reply)),
fd);
}
} // namespace perfetto
} // namespace protos
} // namespace gen
-// gen_amalgamated begin source: src/tracing/ipc/default_socket.cc
-/*
- * 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.
- */
-
-// gen_amalgamated expanded: #include "perfetto/tracing/default_socket.h"
-
-// gen_amalgamated expanded: #include "perfetto/base/build_config.h"
-// gen_amalgamated expanded: #include "perfetto/base/logging.h"
-// gen_amalgamated expanded: #include "perfetto/ext/base/android_utils.h"
-// gen_amalgamated expanded: #include "perfetto/ext/base/string_utils.h"
-// gen_amalgamated expanded: #include "perfetto/ext/base/utils.h"
-// gen_amalgamated expanded: #include "perfetto/ext/ipc/basic_types.h"
-// gen_amalgamated expanded: #include "perfetto/ext/tracing/core/basic_types.h"
+// gen_amalgamated begin source: gen/protos/perfetto/ipc/producer_port.ipc.cc
+// gen_amalgamated begin header: gen/protos/perfetto/ipc/producer_port.ipc.h
+// DO NOT EDIT. Autogenerated by Perfetto IPC
+#ifndef PERFETTO_PROTOS_PROTOS_PERFETTO_IPC_PRODUCER_PORT_PROTO_H_
+#define PERFETTO_PROTOS_PROTOS_PERFETTO_IPC_PRODUCER_PORT_PROTO_H_
-#include <stdlib.h>
+// gen_amalgamated expanded: #include "perfetto/ext/ipc/deferred.h"
+// gen_amalgamated expanded: #include "perfetto/ext/ipc/service.h"
+// gen_amalgamated expanded: #include "perfetto/ext/ipc/service_descriptor.h"
+// gen_amalgamated expanded: #include "perfetto/ext/ipc/service_proxy.h"
-#if PERFETTO_BUILDFLAG(PERFETTO_OS_LINUX) || \
- PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID) || \
- PERFETTO_BUILDFLAG(PERFETTO_OS_FREEBSD) || \
- PERFETTO_BUILDFLAG(PERFETTO_OS_APPLE)
-#include <unistd.h>
-#endif
+// gen_amalgamated expanded: #include "protos/perfetto/ipc/producer_port.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/common/commit_data_request.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/config/data_source_config.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/common/data_source_descriptor.gen.h"
namespace perfetto {
-namespace {
+namespace protos {
+namespace gen {
-const char* kRunPerfettoBaseDir = "/run/perfetto/";
+class ProducerPort : public ::perfetto::ipc::Service {
+ private:
+ static ::perfetto::ipc::ServiceDescriptor* NewDescriptor();
-// On Linux and CrOS, check /run/perfetto/ before using /tmp/ as the socket
-// base directory.
-bool UseRunPerfettoBaseDir() {
-#if PERFETTO_BUILDFLAG(PERFETTO_OS_LINUX)
- // Note that the trailing / in |kRunPerfettoBaseDir| ensures we are checking
- // against a directory, not a file.
- int res = PERFETTO_EINTR(access(kRunPerfettoBaseDir, X_OK));
- if (!res)
- return true;
+ public:
+ ~ProducerPort() override;
- // If the path doesn't exist (ENOENT), fail silently to the caller. Otherwise,
- // fail with an explicit error message.
- if (errno != ENOENT
-#if PERFETTO_BUILDFLAG(PERFETTO_CHROMIUM_BUILD)
- // access(2) won't return EPERM, but Chromium sandbox returns EPERM if the
- // sandbox doesn't allow the call (e.g. in the child processes).
- && errno != EPERM
-#endif
- ) {
- PERFETTO_PLOG("%s exists but cannot be accessed. Falling back on /tmp/ ",
- kRunPerfettoBaseDir);
- }
- return false;
-#else
- base::ignore_result(kRunPerfettoBaseDir);
- return false;
-#endif
-}
+ static const ::perfetto::ipc::ServiceDescriptor& GetDescriptorStatic();
-} // anonymous namespace
+ // Service implementation.
+ const ::perfetto::ipc::ServiceDescriptor& GetDescriptor() override;
-const char* GetProducerSocket() {
- const char* name = getenv("PERFETTO_PRODUCER_SOCK_NAME");
- if (name == nullptr) {
-#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
- name = "127.0.0.1:32278";
-#elif PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID)
- name = "/dev/socket/traced_producer";
-#else
- // Use /run/perfetto if it exists. Then fallback to /tmp.
- static const char* producer_socket =
- UseRunPerfettoBaseDir() ? "/run/perfetto/traced-producer.sock"
- : "/tmp/perfetto-producer";
- name = producer_socket;
-#endif
- }
- base::ignore_result(UseRunPerfettoBaseDir); // Silence unused func warnings.
- return name;
-}
+ // Methods from the .proto file
+ using DeferredInitializeConnectionResponse = ::perfetto::ipc::Deferred<InitializeConnectionResponse>;
+ virtual void InitializeConnection(const InitializeConnectionRequest&, DeferredInitializeConnectionResponse) = 0;
-std::string GetRelaySocket() {
- // The relay socket is optional and is connected only when the env var is set.
- // In Android, if the env var isn't set then we check the
- // |traced_relay.relay_port| system property.
- const char* name = getenv("PERFETTO_RELAY_SOCK_NAME");
- if (name != nullptr)
- return std::string(name);
-#if PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID)
- return base::GetAndroidProp("traced_relay.relay_port");
-#else
- return std::string();
-#endif
-}
+ using DeferredRegisterDataSourceResponse = ::perfetto::ipc::Deferred<RegisterDataSourceResponse>;
+ virtual void RegisterDataSource(const RegisterDataSourceRequest&, DeferredRegisterDataSourceResponse) = 0;
-std::vector<std::string> TokenizeProducerSockets(
- const char* producer_socket_names) {
- return base::SplitString(producer_socket_names, ",");
-}
+ using DeferredUnregisterDataSourceResponse = ::perfetto::ipc::Deferred<UnregisterDataSourceResponse>;
+ virtual void UnregisterDataSource(const UnregisterDataSourceRequest&, DeferredUnregisterDataSourceResponse) = 0;
-const char* GetConsumerSocket() {
- const char* name = getenv("PERFETTO_CONSUMER_SOCK_NAME");
- if (name == nullptr) {
-#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
- name = "127.0.0.1:32279";
-#elif PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID)
- name = "/dev/socket/traced_consumer";
-#else
- // Use /run/perfetto if it exists. Then fallback to /tmp.
- static const char* consumer_socket =
- UseRunPerfettoBaseDir() ? "/run/perfetto/traced-consumer.sock"
- : "/tmp/perfetto-consumer";
- name = consumer_socket;
-#endif
- }
- return name;
-}
+ using DeferredCommitDataResponse = ::perfetto::ipc::Deferred<CommitDataResponse>;
+ virtual void CommitData(const CommitDataRequest&, DeferredCommitDataResponse) = 0;
-} // namespace perfetto
-// gen_amalgamated begin source: src/tracing/ipc/memfd.cc
-// gen_amalgamated begin header: src/tracing/ipc/memfd.h
-/*
- * 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.
- */
+ using DeferredGetAsyncCommandResponse = ::perfetto::ipc::Deferred<GetAsyncCommandResponse>;
+ virtual void GetAsyncCommand(const GetAsyncCommandRequest&, DeferredGetAsyncCommandResponse) = 0;
-#ifndef SRC_TRACING_IPC_MEMFD_H_
-#define SRC_TRACING_IPC_MEMFD_H_
+ using DeferredRegisterTraceWriterResponse = ::perfetto::ipc::Deferred<RegisterTraceWriterResponse>;
+ virtual void RegisterTraceWriter(const RegisterTraceWriterRequest&, DeferredRegisterTraceWriterResponse) = 0;
-// gen_amalgamated expanded: #include "perfetto/base/build_config.h"
+ using DeferredUnregisterTraceWriterResponse = ::perfetto::ipc::Deferred<UnregisterTraceWriterResponse>;
+ virtual void UnregisterTraceWriter(const UnregisterTraceWriterRequest&, DeferredUnregisterTraceWriterResponse) = 0;
-// gen_amalgamated expanded: #include "perfetto/ext/base/scoped_file.h"
+ using DeferredNotifyDataSourceStartedResponse = ::perfetto::ipc::Deferred<NotifyDataSourceStartedResponse>;
+ virtual void NotifyDataSourceStarted(const NotifyDataSourceStartedRequest&, DeferredNotifyDataSourceStartedResponse) = 0;
-// Some android build bots use a sysroot that doesn't support memfd when
-// compiling for the host, so we define the flags we need ourselves.
+ using DeferredNotifyDataSourceStoppedResponse = ::perfetto::ipc::Deferred<NotifyDataSourceStoppedResponse>;
+ virtual void NotifyDataSourceStopped(const NotifyDataSourceStoppedRequest&, DeferredNotifyDataSourceStoppedResponse) = 0;
-// from memfd.h
-#ifndef MFD_CLOEXEC
-#define MFD_CLOEXEC 0x0001U
-#define MFD_ALLOW_SEALING 0x0002U
-#endif
+ using DeferredActivateTriggersResponse = ::perfetto::ipc::Deferred<ActivateTriggersResponse>;
+ virtual void ActivateTriggers(const ActivateTriggersRequest&, DeferredActivateTriggersResponse) = 0;
-// from fcntl.h
-#ifndef F_ADD_SEALS
-#define F_ADD_SEALS 1033
-#define F_GET_SEALS 1034
-#define F_SEAL_SEAL 0x0001
-#define F_SEAL_SHRINK 0x0002
-#define F_SEAL_GROW 0x0004
-#define F_SEAL_WRITE 0x0008
-#endif
+ using DeferredSyncResponse = ::perfetto::ipc::Deferred<SyncResponse>;
+ virtual void Sync(const SyncRequest&, DeferredSyncResponse) = 0;
-namespace perfetto {
+ using DeferredUpdateDataSourceResponse = ::perfetto::ipc::Deferred<UpdateDataSourceResponse>;
+ virtual void UpdateDataSource(const UpdateDataSourceRequest&, DeferredUpdateDataSourceResponse) = 0;
-// Whether the operating system supports memfd.
-bool HasMemfdSupport();
+ using DeferredAttachV2RingBufferResponse = ::perfetto::ipc::Deferred<AttachV2RingBufferResponse>;
+ virtual void AttachV2RingBuffer(const AttachV2RingBufferRequest&, DeferredAttachV2RingBufferResponse) = 0;
-// Call memfd(2) if available on platform and return the fd as result. This call
-// also makes a kernel version check for safety on older kernels (b/116769556).
-// Returns an invalid ScopedFile on failure.
-base::ScopedFile CreateMemfd(const char* name, unsigned int flags);
+ using DeferredDrainV2RingBufferResponse = ::perfetto::ipc::Deferred<DrainV2RingBufferResponse>;
+ virtual void DrainV2RingBuffer(const DrainV2RingBufferRequest&, DeferredDrainV2RingBufferResponse) = 0;
-} // namespace perfetto
+};
-#endif // SRC_TRACING_IPC_MEMFD_H_
-/*
- * 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.
- */
-// gen_amalgamated expanded: #include "src/tracing/ipc/memfd.h"
+class ProducerPortProxy : public ::perfetto::ipc::ServiceProxy {
+ public:
+ explicit ProducerPortProxy(::perfetto::ipc::ServiceProxy::EventListener*);
+ ~ProducerPortProxy() override;
-#include <errno.h>
+ // ServiceProxy implementation.
+ const ::perfetto::ipc::ServiceDescriptor& GetDescriptor() override;
-#define PERFETTO_MEMFD_ENABLED() \
- PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID) || \
- PERFETTO_BUILDFLAG(PERFETTO_OS_LINUX_BUT_NOT_QNX)
+ // Methods from the .proto file
+ using DeferredInitializeConnectionResponse = ::perfetto::ipc::Deferred<InitializeConnectionResponse>;
+ void InitializeConnection(const InitializeConnectionRequest&, DeferredInitializeConnectionResponse, int fd = -1);
-#if PERFETTO_MEMFD_ENABLED()
+ using DeferredRegisterDataSourceResponse = ::perfetto::ipc::Deferred<RegisterDataSourceResponse>;
+ void RegisterDataSource(const RegisterDataSourceRequest&, DeferredRegisterDataSourceResponse, int fd = -1);
-#include <stdio.h>
-#include <string.h>
-#include <sys/syscall.h>
-#include <sys/utsname.h>
-#include <unistd.h>
+ using DeferredUnregisterDataSourceResponse = ::perfetto::ipc::Deferred<UnregisterDataSourceResponse>;
+ void UnregisterDataSource(const UnregisterDataSourceRequest&, DeferredUnregisterDataSourceResponse, int fd = -1);
-// Some android build bots use a sysroot that doesn't support memfd when
-// compiling for the host, so we redefine it if necessary.
-#if !defined(__NR_memfd_create)
-#if defined(__x86_64__)
-#define __NR_memfd_create 319
-#elif defined(__i386__)
-#define __NR_memfd_create 356
-#elif defined(__aarch64__)
-#define __NR_memfd_create 279
-#elif defined(__arm__)
-#define __NR_memfd_create 385
-#else
-#error "unsupported sysroot without memfd support"
-#endif
-#endif // !defined(__NR_memfd_create)
+ using DeferredCommitDataResponse = ::perfetto::ipc::Deferred<CommitDataResponse>;
+ void CommitData(const CommitDataRequest&, DeferredCommitDataResponse, int fd = -1);
-namespace perfetto {
-bool HasMemfdSupport() {
- static bool kSupportsMemfd = [] {
- // Check kernel version supports memfd_create(). Some older kernels segfault
- // executing memfd_create() rather than returning ENOSYS (b/116769556).
- static constexpr int kRequiredMajor = 3;
- static constexpr int kRequiredMinor = 17;
- struct utsname uts;
- int major, minor;
- if (uname(&uts) == 0 && strcmp(uts.sysname, "Linux") == 0 &&
- sscanf(uts.release, "%d.%d", &major, &minor) == 2 &&
- ((major < kRequiredMajor ||
- (major == kRequiredMajor && minor < kRequiredMinor)))) {
- return false;
- }
+ using DeferredGetAsyncCommandResponse = ::perfetto::ipc::Deferred<GetAsyncCommandResponse>;
+ void GetAsyncCommand(const GetAsyncCommandRequest&, DeferredGetAsyncCommandResponse, int fd = -1);
- base::ScopedFile fd;
- fd.reset(static_cast<int>(syscall(__NR_memfd_create, "perfetto_shmem",
- MFD_CLOEXEC | MFD_ALLOW_SEALING)));
- return !!fd;
- }();
- return kSupportsMemfd;
-}
+ using DeferredRegisterTraceWriterResponse = ::perfetto::ipc::Deferred<RegisterTraceWriterResponse>;
+ void RegisterTraceWriter(const RegisterTraceWriterRequest&, DeferredRegisterTraceWriterResponse, int fd = -1);
-base::ScopedFile CreateMemfd(const char* name, unsigned int flags) {
- if (!HasMemfdSupport()) {
- errno = ENOSYS;
- return base::ScopedFile();
- }
- return base::ScopedFile(
- static_cast<int>(syscall(__NR_memfd_create, name, flags)));
-}
-} // namespace perfetto
+ using DeferredUnregisterTraceWriterResponse = ::perfetto::ipc::Deferred<UnregisterTraceWriterResponse>;
+ void UnregisterTraceWriter(const UnregisterTraceWriterRequest&, DeferredUnregisterTraceWriterResponse, int fd = -1);
-#else // PERFETTO_MEMFD_ENABLED()
+ using DeferredNotifyDataSourceStartedResponse = ::perfetto::ipc::Deferred<NotifyDataSourceStartedResponse>;
+ void NotifyDataSourceStarted(const NotifyDataSourceStartedRequest&, DeferredNotifyDataSourceStartedResponse, int fd = -1);
-namespace perfetto {
-bool HasMemfdSupport() {
- return false;
-}
-base::ScopedFile CreateMemfd(const char*, unsigned int) {
- errno = ENOSYS;
- return base::ScopedFile();
-}
-} // namespace perfetto
+ using DeferredNotifyDataSourceStoppedResponse = ::perfetto::ipc::Deferred<NotifyDataSourceStoppedResponse>;
+ void NotifyDataSourceStopped(const NotifyDataSourceStoppedRequest&, DeferredNotifyDataSourceStoppedResponse, int fd = -1);
-#endif // PERFETTO_MEMFD_ENABLED()
-// gen_amalgamated begin source: src/tracing/ipc/posix_shared_memory.cc
-// gen_amalgamated begin header: src/tracing/ipc/posix_shared_memory.h
-/*
- * 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.
- */
+ using DeferredActivateTriggersResponse = ::perfetto::ipc::Deferred<ActivateTriggersResponse>;
+ void ActivateTriggers(const ActivateTriggersRequest&, DeferredActivateTriggersResponse, int fd = -1);
-#ifndef SRC_TRACING_IPC_POSIX_SHARED_MEMORY_H_
-#define SRC_TRACING_IPC_POSIX_SHARED_MEMORY_H_
+ using DeferredSyncResponse = ::perfetto::ipc::Deferred<SyncResponse>;
+ void Sync(const SyncRequest&, DeferredSyncResponse, int fd = -1);
-// gen_amalgamated expanded: #include "perfetto/base/build_config.h"
+ using DeferredUpdateDataSourceResponse = ::perfetto::ipc::Deferred<UpdateDataSourceResponse>;
+ void UpdateDataSource(const UpdateDataSourceRequest&, DeferredUpdateDataSourceResponse, int fd = -1);
-#if PERFETTO_BUILDFLAG(PERFETTO_OS_LINUX) || \
- PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID) || \
- PERFETTO_BUILDFLAG(PERFETTO_OS_APPLE) || \
- PERFETTO_BUILDFLAG(PERFETTO_OS_FUCHSIA) || \
- PERFETTO_BUILDFLAG(PERFETTO_OS_FREEBSD) || \
- PERFETTO_BUILDFLAG(PERFETTO_OS_WASM)
+ using DeferredAttachV2RingBufferResponse = ::perfetto::ipc::Deferred<AttachV2RingBufferResponse>;
+ void AttachV2RingBuffer(const AttachV2RingBufferRequest&, DeferredAttachV2RingBufferResponse, int fd = -1);
-#include <stddef.h>
+ using DeferredDrainV2RingBufferResponse = ::perfetto::ipc::Deferred<DrainV2RingBufferResponse>;
+ void DrainV2RingBuffer(const DrainV2RingBufferRequest&, DeferredDrainV2RingBufferResponse, int fd = -1);
-#include <memory>
+};
-// gen_amalgamated expanded: #include "perfetto/base/build_config.h"
-// gen_amalgamated expanded: #include "perfetto/ext/base/scoped_file.h"
-// gen_amalgamated expanded: #include "perfetto/ext/tracing/core/shared_memory.h"
+} // namespace perfetto
+} // namespace protos
+} // namespace gen
-namespace perfetto {
+#endif // PERFETTO_PROTOS_PROTOS_PERFETTO_IPC_PRODUCER_PORT_PROTO_H_
+// DO NOT EDIT. Autogenerated by Perfetto IPC
+// gen_amalgamated expanded: #include "protos/perfetto/ipc/producer_port.ipc.h"
+// gen_amalgamated expanded: #include "perfetto/ext/ipc/codegen_helpers.h"
-// Implements the SharedMemory and its factory for the posix-based transport.
-class PosixSharedMemory : public SharedMemory {
- public:
- class Factory : public SharedMemory::Factory {
- public:
- ~Factory() override;
- std::unique_ptr<SharedMemory> CreateSharedMemory(size_t) override;
- };
+#include <memory>
- // Create a brand new SHM region.
- static std::unique_ptr<PosixSharedMemory> Create(size_t size);
+namespace perfetto {
+namespace protos {
+namespace gen {
+::perfetto::ipc::ServiceDescriptor* ProducerPort::NewDescriptor() {
+ auto* desc = new ::perfetto::ipc::ServiceDescriptor();
+ desc->service_name = "ProducerPort";
- // Mmaps a file descriptor to an existing SHM region. If
- // |require_seals_if_supported| is true and the system supports
- // memfd_create(), the FD is required to be a sealed memfd with F_SEAL_SEAL,
- // F_SEAL_GROW, and F_SEAL_SHRINK seals set (otherwise, nullptr is returned).
- // May also return nullptr if mapping fails for another reason (e.g. OOM).
- static std::unique_ptr<PosixSharedMemory> AttachToFd(
- base::ScopedFile,
- bool require_seals_if_supported = true);
+ desc->methods.emplace_back(::perfetto::ipc::ServiceDescriptor::Method{
+ "InitializeConnection",
+ &_IPC_Decoder<InitializeConnectionRequest>,
+ &_IPC_Decoder<InitializeConnectionResponse>,
+ &_IPC_Invoker<ProducerPort, InitializeConnectionRequest, InitializeConnectionResponse, &ProducerPort::InitializeConnection>});
- ~PosixSharedMemory() override;
+ desc->methods.emplace_back(::perfetto::ipc::ServiceDescriptor::Method{
+ "RegisterDataSource",
+ &_IPC_Decoder<RegisterDataSourceRequest>,
+ &_IPC_Decoder<RegisterDataSourceResponse>,
+ &_IPC_Invoker<ProducerPort, RegisterDataSourceRequest, RegisterDataSourceResponse, &ProducerPort::RegisterDataSource>});
- int fd() const { return fd_.get(); }
+ desc->methods.emplace_back(::perfetto::ipc::ServiceDescriptor::Method{
+ "UnregisterDataSource",
+ &_IPC_Decoder<UnregisterDataSourceRequest>,
+ &_IPC_Decoder<UnregisterDataSourceResponse>,
+ &_IPC_Invoker<ProducerPort, UnregisterDataSourceRequest, UnregisterDataSourceResponse, &ProducerPort::UnregisterDataSource>});
- // SharedMemory implementation.
- using SharedMemory::start; // Equal priority to const and non-const versions
- const void* start() const override { return start_; }
- size_t size() const override { return size_; }
+ desc->methods.emplace_back(::perfetto::ipc::ServiceDescriptor::Method{
+ "CommitData",
+ &_IPC_Decoder<CommitDataRequest>,
+ &_IPC_Decoder<CommitDataResponse>,
+ &_IPC_Invoker<ProducerPort, CommitDataRequest, CommitDataResponse, &ProducerPort::CommitData>});
- private:
- static std::unique_ptr<PosixSharedMemory> MapFD(base::ScopedFile, size_t);
+ desc->methods.emplace_back(::perfetto::ipc::ServiceDescriptor::Method{
+ "GetAsyncCommand",
+ &_IPC_Decoder<GetAsyncCommandRequest>,
+ &_IPC_Decoder<GetAsyncCommandResponse>,
+ &_IPC_Invoker<ProducerPort, GetAsyncCommandRequest, GetAsyncCommandResponse, &ProducerPort::GetAsyncCommand>});
- PosixSharedMemory(void* start, size_t size, base::ScopedFile);
- PosixSharedMemory(const PosixSharedMemory&) = delete;
- PosixSharedMemory& operator=(const PosixSharedMemory&) = delete;
+ desc->methods.emplace_back(::perfetto::ipc::ServiceDescriptor::Method{
+ "RegisterTraceWriter",
+ &_IPC_Decoder<RegisterTraceWriterRequest>,
+ &_IPC_Decoder<RegisterTraceWriterResponse>,
+ &_IPC_Invoker<ProducerPort, RegisterTraceWriterRequest, RegisterTraceWriterResponse, &ProducerPort::RegisterTraceWriter>});
- void* const start_;
- const size_t size_;
- base::ScopedFile fd_;
-};
+ desc->methods.emplace_back(::perfetto::ipc::ServiceDescriptor::Method{
+ "UnregisterTraceWriter",
+ &_IPC_Decoder<UnregisterTraceWriterRequest>,
+ &_IPC_Decoder<UnregisterTraceWriterResponse>,
+ &_IPC_Invoker<ProducerPort, UnregisterTraceWriterRequest, UnregisterTraceWriterResponse, &ProducerPort::UnregisterTraceWriter>});
-} // namespace perfetto
+ desc->methods.emplace_back(::perfetto::ipc::ServiceDescriptor::Method{
+ "NotifyDataSourceStarted",
+ &_IPC_Decoder<NotifyDataSourceStartedRequest>,
+ &_IPC_Decoder<NotifyDataSourceStartedResponse>,
+ &_IPC_Invoker<ProducerPort, NotifyDataSourceStartedRequest, NotifyDataSourceStartedResponse, &ProducerPort::NotifyDataSourceStarted>});
-#endif // OS_LINUX || OS_ANDROID || OS_APPLE
-#endif // SRC_TRACING_IPC_POSIX_SHARED_MEMORY_H_
-/*
- * 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.
- */
+ desc->methods.emplace_back(::perfetto::ipc::ServiceDescriptor::Method{
+ "NotifyDataSourceStopped",
+ &_IPC_Decoder<NotifyDataSourceStoppedRequest>,
+ &_IPC_Decoder<NotifyDataSourceStoppedResponse>,
+ &_IPC_Invoker<ProducerPort, NotifyDataSourceStoppedRequest, NotifyDataSourceStoppedResponse, &ProducerPort::NotifyDataSourceStopped>});
-// gen_amalgamated expanded: #include "src/tracing/ipc/posix_shared_memory.h"
+ desc->methods.emplace_back(::perfetto::ipc::ServiceDescriptor::Method{
+ "ActivateTriggers",
+ &_IPC_Decoder<ActivateTriggersRequest>,
+ &_IPC_Decoder<ActivateTriggersResponse>,
+ &_IPC_Invoker<ProducerPort, ActivateTriggersRequest, ActivateTriggersResponse, &ProducerPort::ActivateTriggers>});
-#if PERFETTO_BUILDFLAG(PERFETTO_OS_LINUX) || \
- PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID) || \
- PERFETTO_BUILDFLAG(PERFETTO_OS_APPLE) || \
- PERFETTO_BUILDFLAG(PERFETTO_OS_FUCHSIA) || \
- PERFETTO_BUILDFLAG(PERFETTO_OS_FREEBSD) || \
- PERFETTO_BUILDFLAG(PERFETTO_OS_WASM)
+ desc->methods.emplace_back(::perfetto::ipc::ServiceDescriptor::Method{
+ "Sync",
+ &_IPC_Decoder<SyncRequest>,
+ &_IPC_Decoder<SyncResponse>,
+ &_IPC_Invoker<ProducerPort, SyncRequest, SyncResponse, &ProducerPort::Sync>});
-#include <fcntl.h>
-#include <stdint.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <sys/mman.h>
-#include <sys/stat.h>
-#include <unistd.h>
+ desc->methods.emplace_back(::perfetto::ipc::ServiceDescriptor::Method{
+ "UpdateDataSource",
+ &_IPC_Decoder<UpdateDataSourceRequest>,
+ &_IPC_Decoder<UpdateDataSourceResponse>,
+ &_IPC_Invoker<ProducerPort, UpdateDataSourceRequest, UpdateDataSourceResponse, &ProducerPort::UpdateDataSource>});
-#include <memory>
-#include <utility>
+ desc->methods.emplace_back(::perfetto::ipc::ServiceDescriptor::Method{
+ "AttachV2RingBuffer",
+ &_IPC_Decoder<AttachV2RingBufferRequest>,
+ &_IPC_Decoder<AttachV2RingBufferResponse>,
+ &_IPC_Invoker<ProducerPort, AttachV2RingBufferRequest, AttachV2RingBufferResponse, &ProducerPort::AttachV2RingBuffer>});
-// gen_amalgamated expanded: #include "perfetto/base/compiler.h"
-// gen_amalgamated expanded: #include "perfetto/base/logging.h"
-// gen_amalgamated expanded: #include "perfetto/ext/base/temp_file.h"
-// gen_amalgamated expanded: #include "src/tracing/ipc/memfd.h"
+ desc->methods.emplace_back(::perfetto::ipc::ServiceDescriptor::Method{
+ "DrainV2RingBuffer",
+ &_IPC_Decoder<DrainV2RingBufferRequest>,
+ &_IPC_Decoder<DrainV2RingBufferResponse>,
+ &_IPC_Invoker<ProducerPort, DrainV2RingBufferRequest, DrainV2RingBufferResponse, &ProducerPort::DrainV2RingBuffer>});
+ desc->methods.shrink_to_fit();
+ return desc;
+}
-namespace perfetto {
-namespace {
-int kFileSeals = F_SEAL_SHRINK | F_SEAL_GROW | F_SEAL_SEAL;
-} // namespace
+const ::perfetto::ipc::ServiceDescriptor& ProducerPort::GetDescriptorStatic() {
+ static auto* instance = NewDescriptor();
+ return *instance;
+}
-// static
-std::unique_ptr<PosixSharedMemory> PosixSharedMemory::Create(size_t size) {
- base::ScopedFile fd =
- CreateMemfd("perfetto_shmem", MFD_CLOEXEC | MFD_ALLOW_SEALING);
- bool is_memfd = !!fd;
+// Host-side definitions.
+ProducerPort::~ProducerPort() = default;
- // In-tree builds only allow mem_fd, so we can inspect the seals to verify the
- // fd is appropriately sealed. We'll crash in the PERFETTO_CHECK(fd) below if
- // memfd_create failed.
-#if !PERFETTO_BUILDFLAG(PERFETTO_ANDROID_BUILD)
- if (!fd) {
- // TODO: if this fails on Android we should fall back on ashmem.
- PERFETTO_DPLOG("memfd_create() failed");
- fd = base::TempFile::CreateUnlinked().ReleaseFD();
- }
-#endif
+const ::perfetto::ipc::ServiceDescriptor& ProducerPort::GetDescriptor() {
+ return GetDescriptorStatic();
+}
- PERFETTO_CHECK(fd);
- int res = ftruncate(fd.get(), static_cast<off_t>(size));
- PERFETTO_CHECK(res == 0);
+// Client-side definitions.
+ProducerPortProxy::ProducerPortProxy(::perfetto::ipc::ServiceProxy::EventListener* event_listener)
+ : ::perfetto::ipc::ServiceProxy(event_listener) {}
- if (is_memfd) {
- // When memfd is supported, file seals should be, too.
- res = fcntl(*fd, F_ADD_SEALS, kFileSeals);
- PERFETTO_DCHECK(res == 0);
- }
+ProducerPortProxy::~ProducerPortProxy() = default;
- return MapFD(std::move(fd), size);
+const ::perfetto::ipc::ServiceDescriptor& ProducerPortProxy::GetDescriptor() {
+ return ProducerPort::GetDescriptorStatic();
}
-// static
-std::unique_ptr<PosixSharedMemory> PosixSharedMemory::AttachToFd(
- base::ScopedFile fd,
- bool require_seals_if_supported) {
- bool requires_seals = require_seals_if_supported;
+void ProducerPortProxy::InitializeConnection(const InitializeConnectionRequest& request, DeferredInitializeConnectionResponse reply, int fd) {
+ BeginInvoke("InitializeConnection", request, ::perfetto::ipc::DeferredBase(std::move(reply)),
+ fd);
+}
-#if PERFETTO_BUILDFLAG(PERFETTO_ANDROID_BUILD)
- // In-tree kernels all support memfd.
- PERFETTO_CHECK(HasMemfdSupport());
-#else
- // In out-of-tree builds, we only require seals if the kernel supports memfd.
- if (requires_seals)
- requires_seals = HasMemfdSupport();
-#endif
+void ProducerPortProxy::RegisterDataSource(const RegisterDataSourceRequest& request, DeferredRegisterDataSourceResponse reply, int fd) {
+ BeginInvoke("RegisterDataSource", request, ::perfetto::ipc::DeferredBase(std::move(reply)),
+ fd);
+}
- if (requires_seals) {
- // If the system supports memfd, we require a sealed memfd.
- int res = fcntl(*fd, F_GET_SEALS);
- if (res == -1 || (res & kFileSeals) != kFileSeals) {
- PERFETTO_PLOG("Couldn't verify file seals on shmem FD");
- return nullptr;
- }
- }
+void ProducerPortProxy::UnregisterDataSource(const UnregisterDataSourceRequest& request, DeferredUnregisterDataSourceResponse reply, int fd) {
+ BeginInvoke("UnregisterDataSource", request, ::perfetto::ipc::DeferredBase(std::move(reply)),
+ fd);
+}
- struct stat stat_buf = {};
- int res = fstat(fd.get(), &stat_buf);
- PERFETTO_CHECK(res == 0 && stat_buf.st_size > 0);
- return MapFD(std::move(fd), static_cast<size_t>(stat_buf.st_size));
+void ProducerPortProxy::CommitData(const CommitDataRequest& request, DeferredCommitDataResponse reply, int fd) {
+ BeginInvoke("CommitData", request, ::perfetto::ipc::DeferredBase(std::move(reply)),
+ fd);
}
-// static
-std::unique_ptr<PosixSharedMemory> PosixSharedMemory::MapFD(base::ScopedFile fd,
- size_t size) {
- PERFETTO_DCHECK(fd);
- PERFETTO_DCHECK(size > 0);
- void* start =
- mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd.get(), 0);
- PERFETTO_CHECK(start != MAP_FAILED);
- return std::unique_ptr<PosixSharedMemory>(
- new PosixSharedMemory(start, size, std::move(fd)));
+void ProducerPortProxy::GetAsyncCommand(const GetAsyncCommandRequest& request, DeferredGetAsyncCommandResponse reply, int fd) {
+ BeginInvoke("GetAsyncCommand", request, ::perfetto::ipc::DeferredBase(std::move(reply)),
+ fd);
}
-PosixSharedMemory::PosixSharedMemory(void* start,
- size_t size,
- base::ScopedFile fd)
- : start_(start), size_(size), fd_(std::move(fd)) {}
+void ProducerPortProxy::RegisterTraceWriter(const RegisterTraceWriterRequest& request, DeferredRegisterTraceWriterResponse reply, int fd) {
+ BeginInvoke("RegisterTraceWriter", request, ::perfetto::ipc::DeferredBase(std::move(reply)),
+ fd);
+}
-PosixSharedMemory::~PosixSharedMemory() {
- munmap(start(), size());
+void ProducerPortProxy::UnregisterTraceWriter(const UnregisterTraceWriterRequest& request, DeferredUnregisterTraceWriterResponse reply, int fd) {
+ BeginInvoke("UnregisterTraceWriter", request, ::perfetto::ipc::DeferredBase(std::move(reply)),
+ fd);
}
-PosixSharedMemory::Factory::~Factory() {}
+void ProducerPortProxy::NotifyDataSourceStarted(const NotifyDataSourceStartedRequest& request, DeferredNotifyDataSourceStartedResponse reply, int fd) {
+ BeginInvoke("NotifyDataSourceStarted", request, ::perfetto::ipc::DeferredBase(std::move(reply)),
+ fd);
+}
-std::unique_ptr<SharedMemory> PosixSharedMemory::Factory::CreateSharedMemory(
- size_t size) {
- return PosixSharedMemory::Create(size);
+void ProducerPortProxy::NotifyDataSourceStopped(const NotifyDataSourceStoppedRequest& request, DeferredNotifyDataSourceStoppedResponse reply, int fd) {
+ BeginInvoke("NotifyDataSourceStopped", request, ::perfetto::ipc::DeferredBase(std::move(reply)),
+ fd);
}
-} // namespace perfetto
+void ProducerPortProxy::ActivateTriggers(const ActivateTriggersRequest& request, DeferredActivateTriggersResponse reply, int fd) {
+ BeginInvoke("ActivateTriggers", request, ::perfetto::ipc::DeferredBase(std::move(reply)),
+ fd);
+}
-#endif // OS_LINUX || OS_ANDROID || OS_APPLE
-// gen_amalgamated begin source: src/tracing/ipc/shared_memory_windows.cc
-// gen_amalgamated begin header: src/tracing/ipc/shared_memory_windows.h
-/*
- * Copyright (C) 2021 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.
- */
+void ProducerPortProxy::Sync(const SyncRequest& request, DeferredSyncResponse reply, int fd) {
+ BeginInvoke("Sync", request, ::perfetto::ipc::DeferredBase(std::move(reply)),
+ fd);
+}
-#ifndef SRC_TRACING_IPC_SHARED_MEMORY_WINDOWS_H_
-#define SRC_TRACING_IPC_SHARED_MEMORY_WINDOWS_H_
+void ProducerPortProxy::UpdateDataSource(const UpdateDataSourceRequest& request, DeferredUpdateDataSourceResponse reply, int fd) {
+ BeginInvoke("UpdateDataSource", request, ::perfetto::ipc::DeferredBase(std::move(reply)),
+ fd);
+}
-// gen_amalgamated expanded: #include "perfetto/base/build_config.h"
+void ProducerPortProxy::AttachV2RingBuffer(const AttachV2RingBufferRequest& request, DeferredAttachV2RingBufferResponse reply, int fd) {
+ BeginInvoke("AttachV2RingBuffer", request, ::perfetto::ipc::DeferredBase(std::move(reply)),
+ fd);
+}
-#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
+void ProducerPortProxy::DrainV2RingBuffer(const DrainV2RingBufferRequest& request, DeferredDrainV2RingBufferResponse reply, int fd) {
+ BeginInvoke("DrainV2RingBuffer", request, ::perfetto::ipc::DeferredBase(std::move(reply)),
+ fd);
+}
+} // namespace perfetto
+} // namespace protos
+} // namespace gen
+// gen_amalgamated begin source: gen/protos/perfetto/ipc/relay_port.ipc.cc
+// gen_amalgamated begin header: gen/protos/perfetto/ipc/relay_port.ipc.h
+// DO NOT EDIT. Autogenerated by Perfetto IPC
+#ifndef PERFETTO_PROTOS_PROTOS_PERFETTO_IPC_RELAY_PORT_PROTO_H_
+#define PERFETTO_PROTOS_PROTOS_PERFETTO_IPC_RELAY_PORT_PROTO_H_
-#include <string>
+// gen_amalgamated expanded: #include "perfetto/ext/ipc/deferred.h"
+// gen_amalgamated expanded: #include "perfetto/ext/ipc/service.h"
+// gen_amalgamated expanded: #include "perfetto/ext/ipc/service_descriptor.h"
+// gen_amalgamated expanded: #include "perfetto/ext/ipc/service_proxy.h"
-// gen_amalgamated expanded: #include "perfetto/base/build_config.h"
-// gen_amalgamated expanded: #include "perfetto/ext/base/scoped_file.h"
-// gen_amalgamated expanded: #include "perfetto/ext/tracing/core/shared_memory.h"
+// gen_amalgamated expanded: #include "protos/perfetto/ipc/relay_port.gen.h"
+// gen_amalgamated expanded: #include "protos/perfetto/common/system_info.gen.h"
namespace perfetto {
+namespace protos {
+namespace gen {
+
+class RelayPort : public ::perfetto::ipc::Service {
+ private:
+ static ::perfetto::ipc::ServiceDescriptor* NewDescriptor();
-// Implements the SharedMemory and its factory for the Windows IPC transport.
-// This used only for standalone builds and NOT in chromium, which instead uses
-// a custom Mojo wrapper (MojoSharedMemory in chromium's //services/tracing/).
-class SharedMemoryWindows : public SharedMemory {
public:
- class Factory : public SharedMemory::Factory {
- public:
- ~Factory() override;
- std::unique_ptr<SharedMemory> CreateSharedMemory(size_t) override;
- };
+ ~RelayPort() override;
- // Create a brand new SHM region.
- enum Flags { kNone = 0, kInheritableHandles };
- static std::unique_ptr<SharedMemoryWindows> Create(
- size_t size,
- Flags flags = Flags::kNone);
- static std::unique_ptr<SharedMemoryWindows> Attach(const std::string& key);
- static std::unique_ptr<SharedMemoryWindows> AttachToHandleWithKey(
- base::ScopedPlatformHandle fd,
- const std::string& key);
- ~SharedMemoryWindows() override;
- const std::string& key() const { return key_; }
- const base::ScopedPlatformHandle& handle() const { return handle_; }
+ static const ::perfetto::ipc::ServiceDescriptor& GetDescriptorStatic();
- // SharedMemory implementation.
- using SharedMemory::start; // Equal priority to const and non-const versions
- const void* start() const override { return start_; }
- size_t size() const override { return size_; }
+ // Service implementation.
+ const ::perfetto::ipc::ServiceDescriptor& GetDescriptor() override;
- private:
- SharedMemoryWindows(void* start,
- size_t size,
- std::string,
- base::ScopedPlatformHandle);
- SharedMemoryWindows(const SharedMemoryWindows&) = delete;
- SharedMemoryWindows& operator=(const SharedMemoryWindows&) = delete;
+ // Methods from the .proto file
+ using DeferredInitRelayResponse = ::perfetto::ipc::Deferred<InitRelayResponse>;
+ virtual void InitRelay(const InitRelayRequest&, DeferredInitRelayResponse) = 0;
+
+ using DeferredSyncClockResponse = ::perfetto::ipc::Deferred<SyncClockResponse>;
+ virtual void SyncClock(const SyncClockRequest&, DeferredSyncClockResponse) = 0;
- void* const start_;
- const size_t size_;
- std::string key_;
- base::ScopedPlatformHandle handle_;
};
-} // namespace perfetto
-#endif // OS_WIN
+class RelayPortProxy : public ::perfetto::ipc::ServiceProxy {
+ public:
+ explicit RelayPortProxy(::perfetto::ipc::ServiceProxy::EventListener*);
+ ~RelayPortProxy() override;
-#endif // SRC_TRACING_IPC_SHARED_MEMORY_WINDOWS_H_
-/*
- * Copyright (C) 2021 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.
- */
+ // ServiceProxy implementation.
+ const ::perfetto::ipc::ServiceDescriptor& GetDescriptor() override;
-// gen_amalgamated expanded: #include "src/tracing/ipc/shared_memory_windows.h"
+ // Methods from the .proto file
+ using DeferredInitRelayResponse = ::perfetto::ipc::Deferred<InitRelayResponse>;
+ void InitRelay(const InitRelayRequest&, DeferredInitRelayResponse, int fd = -1);
-#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
+ using DeferredSyncClockResponse = ::perfetto::ipc::Deferred<SyncClockResponse>;
+ void SyncClock(const SyncClockRequest&, DeferredSyncClockResponse, int fd = -1);
-#include <memory>
-#include <random>
+};
-#include <windows.h>
+} // namespace perfetto
+} // namespace protos
+} // namespace gen
-// gen_amalgamated expanded: #include "perfetto/base/logging.h"
-// gen_amalgamated expanded: #include "perfetto/ext/base/string_utils.h"
+#endif // PERFETTO_PROTOS_PROTOS_PERFETTO_IPC_RELAY_PORT_PROTO_H_
+// DO NOT EDIT. Autogenerated by Perfetto IPC
+// gen_amalgamated expanded: #include "protos/perfetto/ipc/relay_port.ipc.h"
+// gen_amalgamated expanded: #include "perfetto/ext/ipc/codegen_helpers.h"
-namespace perfetto {
+#include <memory>
-// static
-std::unique_ptr<SharedMemoryWindows> SharedMemoryWindows::Create(size_t size,
- Flags flags) {
- base::ScopedPlatformHandle shmem_handle;
- std::random_device rnd_dev;
- uint64_t rnd_key = (static_cast<uint64_t>(rnd_dev()) << 32) | rnd_dev();
- std::string key = "perfetto_shm_" + base::Uint64ToHexStringNoPrefix(rnd_key);
+namespace perfetto {
+namespace protos {
+namespace gen {
+::perfetto::ipc::ServiceDescriptor* RelayPort::NewDescriptor() {
+ auto* desc = new ::perfetto::ipc::ServiceDescriptor();
+ desc->service_name = "RelayPort";
- SECURITY_ATTRIBUTES security_attributes = {};
- security_attributes.nLength = sizeof(SECURITY_ATTRIBUTES);
- if (flags & Flags::kInheritableHandles)
- security_attributes.bInheritHandle = TRUE;
+ desc->methods.emplace_back(::perfetto::ipc::ServiceDescriptor::Method{
+ "InitRelay",
+ &_IPC_Decoder<InitRelayRequest>,
+ &_IPC_Decoder<InitRelayResponse>,
+ &_IPC_Invoker<RelayPort, InitRelayRequest, InitRelayResponse, &RelayPort::InitRelay>});
- shmem_handle.reset(CreateFileMappingA(
- INVALID_HANDLE_VALUE, // Use paging file.
- &security_attributes, PAGE_READWRITE,
- static_cast<DWORD>(size >> 32), // maximum object size (high-order DWORD)
- static_cast<DWORD>(size), // maximum object size (low-order DWORD)
- key.c_str()));
+ desc->methods.emplace_back(::perfetto::ipc::ServiceDescriptor::Method{
+ "SyncClock",
+ &_IPC_Decoder<SyncClockRequest>,
+ &_IPC_Decoder<SyncClockResponse>,
+ &_IPC_Invoker<RelayPort, SyncClockRequest, SyncClockResponse, &RelayPort::SyncClock>});
+ desc->methods.shrink_to_fit();
+ return desc;
+}
- if (!shmem_handle) {
- PERFETTO_PLOG("CreateFileMapping() call failed");
- return nullptr;
- }
- void* start =
- MapViewOfFile(*shmem_handle, FILE_MAP_ALL_ACCESS, /*offsetHigh=*/0,
- /*offsetLow=*/0, size);
- if (!start) {
- PERFETTO_PLOG("MapViewOfFile() failed");
- return nullptr;
- }
- return std::unique_ptr<SharedMemoryWindows>(new SharedMemoryWindows(
- start, size, std::move(key), std::move(shmem_handle)));
+const ::perfetto::ipc::ServiceDescriptor& RelayPort::GetDescriptorStatic() {
+ static auto* instance = NewDescriptor();
+ return *instance;
}
-// static
-std::unique_ptr<SharedMemoryWindows> SharedMemoryWindows::Attach(
- const std::string& key) {
- base::ScopedPlatformHandle shmem_handle;
- shmem_handle.reset(
- OpenFileMappingA(FILE_MAP_ALL_ACCESS, /*inherit=*/false, key.c_str()));
- if (!shmem_handle) {
- PERFETTO_PLOG("Failed to OpenFileMapping()");
- return nullptr;
- }
-
- void* start =
- MapViewOfFile(*shmem_handle, FILE_MAP_ALL_ACCESS, /*offsetHigh=*/0,
- /*offsetLow=*/0, /*dwNumberOfBytesToMap=*/0);
- if (!start) {
- PERFETTO_PLOG("MapViewOfFile() failed");
- return nullptr;
- }
+// Host-side definitions.
+RelayPort::~RelayPort() = default;
- MEMORY_BASIC_INFORMATION info{};
- if (!VirtualQuery(start, &info, sizeof(info))) {
- PERFETTO_PLOG("VirtualQuery() failed");
- return nullptr;
- }
- size_t size = info.RegionSize;
- return std::unique_ptr<SharedMemoryWindows>(
- new SharedMemoryWindows(start, size, key, std::move(shmem_handle)));
+const ::perfetto::ipc::ServiceDescriptor& RelayPort::GetDescriptor() {
+ return GetDescriptorStatic();
}
-// static
-std::unique_ptr<SharedMemoryWindows> SharedMemoryWindows::AttachToHandleWithKey(
- base::ScopedPlatformHandle shmem_handle,
- const std::string& key) {
- void* start =
- MapViewOfFile(*shmem_handle, FILE_MAP_ALL_ACCESS, /*offsetHigh=*/0,
- /*offsetLow=*/0, /*dwNumberOfBytesToMap=*/0);
- if (!start) {
- PERFETTO_PLOG("MapViewOfFile() failed");
- return nullptr;
- }
+// Client-side definitions.
+RelayPortProxy::RelayPortProxy(::perfetto::ipc::ServiceProxy::EventListener* event_listener)
+ : ::perfetto::ipc::ServiceProxy(event_listener) {}
- MEMORY_BASIC_INFORMATION info{};
- if (!VirtualQuery(start, &info, sizeof(info))) {
- PERFETTO_PLOG("VirtualQuery() failed");
- return nullptr;
- }
- size_t size = info.RegionSize;
+RelayPortProxy::~RelayPortProxy() = default;
- return std::unique_ptr<SharedMemoryWindows>(
- new SharedMemoryWindows(start, size, key, std::move(shmem_handle)));
+const ::perfetto::ipc::ServiceDescriptor& RelayPortProxy::GetDescriptor() {
+ return RelayPort::GetDescriptorStatic();
}
-SharedMemoryWindows::SharedMemoryWindows(void* start,
- size_t size,
- std::string key,
- base::ScopedPlatformHandle handle)
- : start_(start),
- size_(size),
- key_(std::move(key)),
- handle_(std::move(handle)) {}
-
-SharedMemoryWindows::~SharedMemoryWindows() {
- if (start_)
- UnmapViewOfFile(start_);
+void RelayPortProxy::InitRelay(const InitRelayRequest& request, DeferredInitRelayResponse reply, int fd) {
+ BeginInvoke("InitRelay", request, ::perfetto::ipc::DeferredBase(std::move(reply)),
+ fd);
}
-SharedMemoryWindows::Factory::~Factory() = default;
-
-std::unique_ptr<SharedMemory> SharedMemoryWindows::Factory::CreateSharedMemory(
- size_t size) {
- return SharedMemoryWindows::Create(size);
+void RelayPortProxy::SyncClock(const SyncClockRequest& request, DeferredSyncClockResponse reply, int fd) {
+ BeginInvoke("SyncClock", request, ::perfetto::ipc::DeferredBase(std::move(reply)),
+ fd);
}
-
} // namespace perfetto
-
-#endif // !OS_WIN
+} // namespace protos
+} // namespace gen
// gen_amalgamated begin source: src/tracing/ipc/consumer/consumer_ipc_client_impl.cc
// gen_amalgamated begin header: src/tracing/ipc/consumer/consumer_ipc_client_impl.h
// gen_amalgamated begin header: include/perfetto/ext/tracing/ipc/consumer_ipc_client.h
@@ -83711,6 +92304,8 @@ class PERFETTO_EXPORT_COMPONENT ProducerIPCClient {
#include <stdint.h>
+#include <memory>
+#include <optional>
#include <set>
#include <vector>
@@ -83722,6 +92317,7 @@ class PERFETTO_EXPORT_COMPONENT ProducerIPCClient {
// gen_amalgamated expanded: #include "perfetto/ext/tracing/core/shared_memory.h"
// gen_amalgamated expanded: #include "perfetto/ext/tracing/core/tracing_service.h"
// gen_amalgamated expanded: #include "perfetto/ext/tracing/ipc/producer_ipc_client.h"
+// gen_amalgamated expanded: #include "src/tracing/v2/producer_ring_buffer_arbiter.h"
// gen_amalgamated expanded: #include "protos/perfetto/ipc/producer_port.ipc.h"
@@ -83731,6 +92327,10 @@ namespace base {
class TaskRunner;
} // namespace base
+namespace test {
+class ProducerIPCClientTestPeer;
+} // namespace test
+
class Producer;
class SharedMemoryArbiter;
@@ -83740,6 +92340,10 @@ class SharedMemoryArbiter;
// actual IPC transport.
// If create_socket_async is set, it will be called to create and connect to a
// socket to the service. If unset, the producer will create and connect itself.
+//
+// TODO(sashwinbalaji): Check all paths through Disconnect(), OnDisconnect(),
+// and ScheduleDisconnect() again. Check for unnecessary steps, incorrect
+// cleanup or callback order, and object lifetime errors.
class ProducerIPCClientImpl : public TracingService::ProducerEndpoint,
public ipc::ServiceProxy::EventListener {
public:
@@ -83769,10 +92373,18 @@ class ProducerIPCClientImpl : public TracingService::ProducerEndpoint,
void NotifyDataSourceStopped(DataSourceInstanceID) override;
void ActivateTriggers(const std::vector<std::string>&) override;
void Sync(std::function<void()> callback) override;
+ void InitializeV2RingBuffer(const DataSourceConfig&) override;
+ void AttachV2RingBuffer(const std::shared_ptr<SharedMemory>&,
+ uint32_t chunk_size_bytes,
+ std::function<void(bool)> callback) override;
+ void DrainV2RingBuffer() override;
std::unique_ptr<TraceWriter> CreateTraceWriter(
BufferID target_buffer,
BufferExhaustedPolicy) override;
+ std::unique_ptr<TraceWriter> CreateTraceWriterV2(
+ BufferID,
+ BufferExhaustedPolicy) override;
SharedMemoryArbiter* MaybeSharedMemoryArbiter() override;
bool IsShmemProvidedByProducer() const override;
void NotifyFlushComplete(FlushRequestID) override;
@@ -83788,15 +92400,22 @@ class ProducerIPCClientImpl : public TracingService::ProducerEndpoint,
ipc::Client* GetClientForTesting() { return ipc_channel_.get(); }
private:
+ // Defined in tracing_integration_test.cc.
+ friend class test::ProducerIPCClientTestPeer;
+
// Drops the provider connection if a protocol error was detected while
// processing an IPC command.
void ScheduleDisconnect();
// Invoked soon after having established the connection with the service.
- void OnConnectionInitialized(bool connection_succeeded,
- bool using_shmem_provided_by_producer,
- bool direct_smb_patching_supported,
- bool use_shmem_emulation);
+ // |offered_versions| is the bitmask sent in the request.
+ void OnConnectionInitialized(
+ uint32_t offered_versions,
+ ipc::AsyncResult<protos::gen::InitializeConnectionResponse> response);
+
+ bool HasNegotiatedV2Abi() const {
+ return !!(protocol_abi_versions_ & kProtocolAbiV2);
+ }
// Invoked when the remote Service sends an IPC to tell us to do something
// (e.g. start/stop a data source).
@@ -83824,6 +92443,8 @@ class ProducerIPCClientImpl : public TracingService::ProducerEndpoint,
std::map<WriterID, BufferID> writers_for_scraping_;
std::unique_ptr<SharedMemory> shared_memory_;
+ // Bitmask of the versions agreed in InitializeConnection, zero until then.
+ uint32_t protocol_abi_versions_ = 0;
std::unique_ptr<SharedMemoryArbiter> shared_memory_arbiter_;
size_t shared_buffer_page_size_kb_ = 0;
std::set<DataSourceInstanceID> data_sources_setup_;
@@ -83836,6 +92457,23 @@ class ProducerIPCClientImpl : public TracingService::ProducerEndpoint,
bool direct_smb_patching_supported_ = false;
bool use_shmem_emulation_ = false;
std::vector<std::function<void()>> pending_sync_reqs_;
+ // Owns the ring buffer and creates v2 writers.
+ //
+ // States:
+ // - nullopt: initialization has not been attempted.
+ // - nullptr: sizing or allocation failed.
+ // Later InitializeV2RingBuffer() calls on the same connection do not retry
+ // initialization, to avoid changing the pointer while v2 writer threads
+ // read it without a lock.
+ // - Non-null pointer: the arbiter exists and tracks service attachment.
+ //
+ // Set by InitializeV2RingBuffer() when an instance selects v2, before the
+ // first v2 writer.
+ // Writer threads then read it without a lock.
+ // OnDisconnect() does not reset this member because v2 writer threads can
+ // still read it or use the arbiter.
+ std::optional<std::unique_ptr<tracing_v2::ProducerRingBufferArbiter>>
+ v2_ring_buffer_arbiter_;
base::WeakPtrFactory<ProducerIPCClientImpl> weak_factory_{this};
PERFETTO_THREAD_CHECKER(thread_checker_)
};
@@ -83865,8 +92503,11 @@ class ProducerIPCClientImpl : public TracingService::ProducerEndpoint,
#include <string.h>
+// gen_amalgamated expanded: #include "perfetto/base/compiler.h"
// gen_amalgamated expanded: #include "perfetto/base/logging.h"
// gen_amalgamated expanded: #include "perfetto/base/task_runner.h"
+// gen_amalgamated expanded: #include "perfetto/ext/base/status_macros.h"
+// gen_amalgamated expanded: #include "perfetto/ext/base/status_or.h"
// gen_amalgamated expanded: #include "perfetto/ext/base/unix_socket.h"
// gen_amalgamated expanded: #include "perfetto/ext/base/version.h"
// gen_amalgamated expanded: #include "perfetto/ext/ipc/client.h"
@@ -83875,10 +92516,13 @@ class ProducerIPCClientImpl : public TracingService::ProducerEndpoint,
// gen_amalgamated expanded: #include "perfetto/ext/tracing/core/shared_memory_abi.h"
// gen_amalgamated expanded: #include "perfetto/ext/tracing/core/shared_memory_arbiter.h"
// gen_amalgamated expanded: #include "perfetto/ext/tracing/core/trace_writer.h"
+// gen_amalgamated expanded: #include "perfetto/ext/tracing/core/tracing_service.h"
// gen_amalgamated expanded: #include "perfetto/tracing/core/data_source_config.h"
// gen_amalgamated expanded: #include "perfetto/tracing/core/data_source_descriptor.h"
// gen_amalgamated expanded: #include "perfetto/tracing/core/trace_config.h"
// gen_amalgamated expanded: #include "src/tracing/core/in_process_shared_memory.h"
+// gen_amalgamated expanded: #include "src/tracing/core/null_trace_writer.h"
+// gen_amalgamated expanded: #include "src/tracing/v2/shared_ring_buffer_abi.h"
#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
// gen_amalgamated expanded: #include "src/tracing/ipc/shared_memory_windows.h"
@@ -84000,14 +92644,19 @@ ProducerIPCClientImpl::~ProducerIPCClientImpl() {
void ProducerIPCClientImpl::Disconnect() {
PERFETTO_DCHECK_THREAD(thread_checker_);
- if (!producer_port_)
+ // Disconnect() is complete when both the port and channel are gone.
+ // ScheduleDisconnect() drops only the port and leaves the channel open.
+ if (!producer_port_ && !ipc_channel_)
return;
- // Reset the producer port so that no further IPCs are received and IPC
- // callbacks are no longer executed. Also reset the IPC channel so that the
- // service is notified of the disconnection.
+
+ // Clear |connected_| so callbacks invoked during port destruction see a
+ // disconnected endpoint.
+ connected_ = false;
+ // Reset |producer_port_| to stop further IPC replies, then close
+ // |ipc_channel_| so the service sees the disconnection.
producer_port_.reset();
ipc_channel_.reset();
- // Perform disconnect synchronously.
+ // Perform disconnect synchronously. This may delete |this|.
OnDisconnect();
}
@@ -84016,19 +92665,22 @@ void ProducerIPCClientImpl::OnConnect() {
PERFETTO_DCHECK_THREAD(thread_checker_);
connected_ = true;
- // The IPC layer guarantees that any outstanding callback will be dropped on
- // the floor if producer_port_ is destroyed between the request and the reply.
- // Binding |this| is hence safe.
+ uint32_t offered_versions = kProtocolAbiV1;
+ offered_versions |= tracing_v2::IpcSupportsTracingV2() ? kProtocolAbiV2 : 0u;
+ protos::gen::InitializeConnectionRequest req;
+ req.set_supported_protocol_abi_versions(offered_versions);
+
+ // When this client is destroyed, the port calls pending callbacks with a
+ // failure result. By then, members used by OnConnectionInitialized() have
+ // already been destroyed. Use a weak pointer to skip the handler in that
+ // case.
ipc::Deferred<protos::gen::InitializeConnectionResponse> on_init;
on_init.Bind(
- [this](ipc::AsyncResult<protos::gen::InitializeConnectionResponse> resp) {
- OnConnectionInitialized(
- resp.success(),
- resp.success() ? resp->using_shmem_provided_by_producer() : false,
- resp.success() ? resp->direct_smb_patching_supported() : false,
- resp.success() ? resp->use_shmem_emulation() : false);
+ [weak_this = weak_factory_.GetWeakPtr(), offered_versions](
+ ipc::AsyncResult<protos::gen::InitializeConnectionResponse> resp) {
+ if (weak_this)
+ weak_this->OnConnectionInitialized(offered_versions, std::move(resp));
});
- protos::gen::InitializeConnectionRequest req;
req.set_producer_name(name_);
req.set_shared_memory_size_hint_bytes(
static_cast<uint32_t>(shared_memory_size_hint_bytes_));
@@ -84085,6 +92737,11 @@ void ProducerIPCClientImpl::OnDisconnect() {
PERFETTO_DLOG("Tracing service connection failure");
connected_ = false;
data_sources_setup_.clear();
+ auto* arbiter = v2_ring_buffer_arbiter_.has_value()
+ ? v2_ring_buffer_arbiter_->get()
+ : nullptr;
+ if (arbiter)
+ arbiter->Disconnect();
producer_->OnDisconnect(); // Note: may delete |this|.
}
@@ -84092,8 +92749,10 @@ void ProducerIPCClientImpl::ScheduleDisconnect() {
// |ipc_channel| doesn't allow disconnection in the middle of handling
// an IPC call, so the connection drop must take place over two phases.
- // First, synchronously drop the |producer_port_| so that no more IPC
- // messages are handled.
+ // First, clear |connected_| so pending Sync() callbacks see a disconnected
+ // endpoint when the port is destroyed. Then synchronously drop
+ // |producer_port_| so that no more IPC messages are handled.
+ connected_ = false;
producer_port_.reset();
// Then schedule an async task for performing the remainder of the
@@ -84107,22 +92766,44 @@ void ProducerIPCClientImpl::ScheduleDisconnect() {
}
void ProducerIPCClientImpl::OnConnectionInitialized(
- bool connection_succeeded,
- bool using_shmem_provided_by_producer,
- bool direct_smb_patching_supported,
- bool use_shmem_emulation) {
+ uint32_t offered_versions,
+ ipc::AsyncResult<protos::gen::InitializeConnectionResponse> response) {
PERFETTO_DCHECK_THREAD(thread_checker_);
- // If connection_succeeded == false, the OnDisconnect() call will follow next
- // and there we'll notify the |producer_|. TODO: add a test for this.
- if (!connection_succeeded)
+ // The IPC proxy accesses this callback after it returns, so keep the port
+ // alive until the next task.
+ auto reject_connection = [this] {
+ task_runner_->PostTask([weak_this = weak_factory_.GetWeakPtr()] {
+ if (weak_this && weak_this->connected_)
+ weak_this->Disconnect();
+ });
+ };
+
+ if (!response.success()) {
+ reject_connection();
+ return;
+ }
+
+ // An old service sends no versions. This means v1 only.
+ uint32_t versions = response->protocol_abi_versions();
+ if (!versions)
+ versions = kProtocolAbiV1;
+
+ // The service returns only versions that the producer offered. Log both
+ // masks if it does not.
+ if (versions & ~offered_versions) {
+ PERFETTO_ELOG("Unexpected protocol versions (advertised: %x, service: %x)",
+ offered_versions, versions);
+ reject_connection();
return;
- is_shmem_provided_by_producer_ = using_shmem_provided_by_producer;
- direct_smb_patching_supported_ = direct_smb_patching_supported;
+ }
+ protocol_abi_versions_ = versions;
+ is_shmem_provided_by_producer_ = response->using_shmem_provided_by_producer();
+ direct_smb_patching_supported_ = response->direct_smb_patching_supported();
// The tracing service may reject using shared memory and tell the client to
// commit data over the socket. This can happen when the client connects to
// the service via a relay service:
// client <-Unix socket-> relay service <- vsock -> tracing service.
- use_shmem_emulation_ = use_shmem_emulation;
+ use_shmem_emulation_ = response->use_shmem_emulation();
producer_->OnConnect();
// Bail out if the service failed to adopt our producer-allocated SMB.
@@ -84179,27 +92860,17 @@ void ProducerIPCClientImpl::OnServiceRequest(
// FD, which is provided to this code via a blocking callback.
PERFETTO_CHECK(receive_shmem_fd_cb_fuchsia_);
- base::ScopedFile shmem_fd(receive_shmem_fd_cb_fuchsia_());
- if (!shmem_fd) {
- // Failure to get a shared memory buffer is a protocol violation and
- // therefore we should drop the Protocol connection.
- PERFETTO_ELOG("Could not get shared memory FD from embedder.");
- ScheduleDisconnect();
- return;
- }
-
- ipc_shared_memory =
- PosixSharedMemory::AttachToFd(std::move(shmem_fd),
- /*require_seals_if_supported=*/false);
+ ipc_shared_memory = PosixSharedMemory::AttachToFd(
+ base::ScopedFile(receive_shmem_fd_cb_fuchsia_()),
+ /*require_seals_if_supported=*/false, TracingService::kMaxShmSize);
#else
- base::ScopedFile shmem_fd = ipc_channel_->TakeReceivedFD();
- if (shmem_fd) {
- // TODO(primiano): handle mmap failure in case of OOM.
- ipc_shared_memory =
- PosixSharedMemory::AttachToFd(std::move(shmem_fd),
- /*require_seals_if_supported=*/false);
- }
+ // The FD can be invalid, for example with a producer-provided SMB.
+ // |ipc_shared_memory| is then null. The checks below handle it.
+ ipc_shared_memory = PosixSharedMemory::AttachToFd(
+ ipc_channel_->TakeReceivedFD(),
+ /*require_seals_if_supported=*/false, TracingService::kMaxShmSize);
#endif
+
if (use_shmem_emulation_) {
PERFETTO_CHECK(!ipc_shared_memory);
// Need to create an emulated shmem buffer when the transport doesn't
@@ -84207,6 +92878,16 @@ void ProducerIPCClientImpl::OnServiceRequest(
ipc_shared_memory = InProcessSharedMemory::Create(
/*size=*/InProcessSharedMemory::kShmemEmulationSize);
}
+
+ // No SMB from the service (none sent, or it failed to map), and none
+ // provided by the producer. The producer cannot trace without one.
+ // Drop the connection: the producer gets OnDisconnect() and can reconnect.
+ if (!ipc_shared_memory && !is_shmem_provided_by_producer_) {
+ PERFETTO_ELOG("No usable shared memory from the service, disconnecting.");
+ ScheduleDisconnect();
+ return;
+ }
+
if (ipc_shared_memory) {
auto shmem_mode = use_shmem_emulation_
? SharedMemoryABI::ShmemMode::kShmemEmulation
@@ -84268,6 +92949,7 @@ void ProducerIPCClientImpl::RegisterDataSource(
if (!connected_) {
PERFETTO_DLOG(
"Cannot RegisterDataSource(), not connected to tracing service");
+ return;
}
protos::gen::RegisterDataSourceRequest req;
*req.mutable_data_source_descriptor() = descriptor;
@@ -84286,6 +92968,7 @@ void ProducerIPCClientImpl::UpdateDataSource(
if (!connected_) {
PERFETTO_DLOG(
"Cannot UpdateDataSource(), not connected to tracing service");
+ return;
}
protos::gen::UpdateDataSourceRequest req;
*req.mutable_data_source_descriptor() = descriptor;
@@ -84371,6 +93054,87 @@ void ProducerIPCClientImpl::CommitData(const CommitDataRequest& req,
producer_port_->CommitData(req, std::move(async_response));
}
+void ProducerIPCClientImpl::InitializeV2RingBuffer(
+ const DataSourceConfig& config) {
+ PERFETTO_DCHECK_THREAD(thread_checker_);
+ // V2 IPC requires a sealed memfd.
+ // TODO(sashwinbalaji): Decide how tracing v2 shares the ring buffer over IPC
+ // on Windows and macOS, which have no memfd.
+#if PERFETTO_MEMFD_ENABLED()
+ if (v2_ring_buffer_arbiter_.has_value() || !connected_ ||
+ !HasNegotiatedV2Abi()) {
+ return;
+ }
+
+ auto arbiter_or = tracing_v2::ProducerRingBufferArbiter::Create(
+ task_runner_, this, config, shared_memory_size_hint_bytes_,
+ [](size_t size) -> base::StatusOr<std::shared_ptr<SharedMemory>> {
+ ASSIGN_OR_RETURN(auto memory, PosixSharedMemory::Create(size));
+ return std::shared_ptr<SharedMemory>(std::move(memory));
+ });
+ if (!arbiter_or.ok()) {
+ PERFETTO_ELOG("tracing v2: cannot create ring buffer: %s",
+ arbiter_or.status().c_message());
+ v2_ring_buffer_arbiter_ = nullptr;
+ return;
+ }
+ v2_ring_buffer_arbiter_ = std::move(*arbiter_or);
+
+ auto* arbiter = v2_ring_buffer_arbiter_->get();
+ AttachV2RingBuffer(
+ arbiter->memory(), arbiter->ring_buffer()->chunk_size(),
+ [weak_arbiter = arbiter->GetWeakPtr()](bool reader_attached) {
+ if (weak_arbiter)
+ weak_arbiter->OnReaderAttachReply(reader_attached);
+ });
+#else
+ base::ignore_result(config);
+#endif // PERFETTO_MEMFD_ENABLED()
+}
+
+void ProducerIPCClientImpl::AttachV2RingBuffer(
+ const std::shared_ptr<SharedMemory>& memory,
+ uint32_t chunk_size_bytes,
+ std::function<void(bool)> callback) {
+ PERFETTO_DCHECK_THREAD(thread_checker_);
+
+ // OnConnect() offers v2 only if tracing_v2::IpcSupportsTracingV2().
+ if (!connected_ || !HasNegotiatedV2Abi() || !memory) {
+ callback(false);
+ return;
+ }
+
+#if PERFETTO_TRACING_V2_IPC()
+ protos::gen::AttachV2RingBufferRequest req;
+ req.set_chunk_size_bytes(chunk_size_bytes);
+ ipc::Deferred<protos::gen::AttachV2RingBufferResponse> reply;
+ reply.Bind(
+ [callback = std::move(callback)](
+ ipc::AsyncResult<protos::gen::AttachV2RingBufferResponse> result) {
+ callback(result.success());
+ });
+ // The IPC layer sends the descriptor before this call returns. The service
+ // maps it on its side.
+ //
+ // The producer that called this method owns |memory| and keeps it mapped for
+ // its writers.
+ const int fd = static_cast<PosixSharedMemory*>(memory.get())->fd();
+ producer_port_->AttachV2RingBuffer(req, std::move(reply), fd);
+#else
+ base::ignore_result(chunk_size_bytes);
+ callback(false);
+#endif
+}
+
+void ProducerIPCClientImpl::DrainV2RingBuffer() {
+ PERFETTO_DCHECK_THREAD(thread_checker_);
+ if (!connected_ || !HasNegotiatedV2Abi())
+ return;
+ producer_port_->DrainV2RingBuffer(
+ protos::gen::DrainV2RingBufferRequest(),
+ ipc::Deferred<protos::gen::DrainV2RingBufferResponse>());
+}
+
void ProducerIPCClientImpl::NotifyDataSourceStarted(DataSourceInstanceID id) {
PERFETTO_DCHECK_THREAD(thread_checker_);
if (!connected_) {
@@ -84435,10 +93199,29 @@ std::unique_ptr<TraceWriter> ProducerIPCClientImpl::CreateTraceWriter(
BufferExhaustedPolicy buffer_exhausted_policy) {
// This method can be called by different threads. |shared_memory_arbiter_| is
// thread-safe but be aware of accessing any other state in this function.
+ // |protocol_abi_versions_| does not change after setup.
+ if (!(protocol_abi_versions_ & kProtocolAbiV1)) {
+ PERFETTO_ELOG(
+ "Cannot create a v1 trace writer: v1 is not in the common protocol "
+ "mask (%x)",
+ protocol_abi_versions_);
+ return std::make_unique<NullTraceWriter>();
+ }
return shared_memory_arbiter_->CreateTraceWriter(target_buffer,
buffer_exhausted_policy);
}
+std::unique_ptr<TraceWriter> ProducerIPCClientImpl::CreateTraceWriterV2(
+ BufferID target_buffer,
+ BufferExhaustedPolicy policy) {
+ auto* arbiter = v2_ring_buffer_arbiter_.has_value()
+ ? v2_ring_buffer_arbiter_->get()
+ : nullptr;
+ if (!arbiter)
+ return std::make_unique<NullTraceWriter>();
+ return arbiter->CreateTraceWriter(target_buffer, policy);
+}
+
SharedMemoryArbiter* ProducerIPCClientImpl::MaybeSharedMemoryArbiter() {
return shared_memory_arbiter_.get();
}
@@ -85253,6 +94036,10 @@ class ProducerIPCService : public protos::gen::ProducerPort {
void GetAsyncCommand(const protos::gen::GetAsyncCommandRequest&,
DeferredGetAsyncCommandResponse) override;
void Sync(const protos::gen::SyncRequest&, DeferredSyncResponse) override;
+ void AttachV2RingBuffer(const protos::gen::AttachV2RingBufferRequest&,
+ DeferredAttachV2RingBufferResponse) override;
+ void DrainV2RingBuffer(const protos::gen::DrainV2RingBufferRequest&,
+ DeferredDrainV2RingBufferResponse) override;
void OnClientDisconnected() override;
private:
@@ -85351,6 +94138,7 @@ class ProducerIPCService : public protos::gen::ProducerPort {
// gen_amalgamated expanded: #include "perfetto/ext/tracing/core/tracing_service.h"
// gen_amalgamated expanded: #include "perfetto/tracing/core/data_source_config.h"
// gen_amalgamated expanded: #include "perfetto/tracing/core/data_source_descriptor.h"
+// gen_amalgamated expanded: #include "src/tracing/v2/shared_ring_buffer_abi.h"
#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
// gen_amalgamated expanded: #include "src/tracing/ipc/shared_memory_windows.h"
@@ -85364,6 +94152,32 @@ class ProducerIPCService : public protos::gen::ProducerPort {
namespace perfetto {
+namespace {
+
+// The proto and C++ enums use the same bits.
+static_assert(static_cast<uint32_t>(protos::gen::PROTOCOL_ABI_VERSION_V1) ==
+ kProtocolAbiV1);
+static_assert(static_cast<uint32_t>(protos::gen::PROTOCOL_ABI_VERSION_V2) ==
+ kProtocolAbiV2);
+
+// Returns the bitmask of common protocol versions, or 0 if none match.
+uint32_t GetCommonProtocolAbiVersions(uint32_t producer_versions,
+ bool use_shmem_emulation) {
+ // Old producers send no versions and support only v1.
+ if (!producer_versions)
+ return kProtocolAbiV1;
+
+ // v2 needs memfd support and cannot use shared memory emulation.
+ uint32_t supported = kProtocolAbiV1;
+ if (tracing_v2::IpcSupportsTracingV2() && !use_shmem_emulation)
+ supported |= kProtocolAbiV2;
+
+ // Unknown bits from a newer producer drop out here.
+ return producer_versions & supported;
+}
+
+} // namespace
+
ProducerIPCService::ProducerIPCService(TracingService* core_service)
: core_service_(core_service), weak_ptr_factory_(this) {}
@@ -85425,8 +94239,9 @@ void ProducerIPCService::InitializeConnection(
base::ScopedFile shmem_fd = ipc::Service::TakeReceivedFD();
if (shmem_fd) {
- shmem = PosixSharedMemory::AttachToFd(
- std::move(shmem_fd), /*require_seals_if_supported=*/true);
+ shmem = PosixSharedMemory::AttachToFd(std::move(shmem_fd),
+ /*require_seals_if_supported=*/true,
+ TracingService::kMaxShmSize);
if (!shmem) {
PERFETTO_ELOG(
"Couldn't map producer-provided SMB, falling back to "
@@ -85443,13 +94258,23 @@ void ProducerIPCService::InitializeConnection(
// Copy the data fields to be emitted to trace packets into ClientIdentity.
ClientIdentity client_identity(client_info.uid(), client_info.pid(),
client_info.machine_id());
+ const uint32_t protocol_abi_versions =
+ GetCommonProtocolAbiVersions(req.supported_protocol_abi_versions(),
+ ipc::Service::use_shmem_emulation());
+ if (!protocol_abi_versions) {
+ PERFETTO_ELOG(
+ "Producer \"%s\" supports no protocol version of this service",
+ req.producer_name().c_str());
+ return response.Reject();
+ }
+
// ConnectProducer will call OnConnect() on the next task.
producer->service_endpoint = core_service_->ConnectProducer(
producer.get(), client_identity, req.producer_name(),
req.shared_memory_size_hint_bytes(),
/*in_process=*/false, smb_scraping_mode,
req.shared_memory_page_size_hint_bytes(), std::move(shmem),
- req.sdk_version(), client_info.machine_name());
+ req.sdk_version(), client_info.machine_name(), protocol_abi_versions);
// Could happen if the service has too many producers connected.
if (!producer->service_endpoint) {
@@ -85470,6 +94295,7 @@ void ProducerIPCService::InitializeConnection(
async_res->set_using_shmem_provided_by_producer(using_producer_shmem);
async_res->set_direct_smb_patching_supported(true);
async_res->set_use_shmem_emulation(use_shmem_emulation);
+ async_res->set_protocol_abi_versions(protocol_abi_versions);
response.Resolve(std::move(async_res));
}
@@ -85712,6 +94538,52 @@ void ProducerIPCService::GetAsyncCommand(
producer->SendSetupTracing();
}
+void ProducerIPCService::AttachV2RingBuffer(
+ const protos::gen::AttachV2RingBufferRequest& req,
+ DeferredAttachV2RingBufferResponse resp) {
+ // Take the descriptor first. It is closed on every rejection path.
+ auto fd = ipc::Service::TakeReceivedFD();
+ auto* producer = GetProducerForCurrentRequest();
+ if (!producer) {
+ resp.Reject();
+ return;
+ }
+
+ std::shared_ptr<SharedMemory> memory;
+#if PERFETTO_TRACING_V2_IPC()
+ memory = PosixSharedMemory::AttachToFd(std::move(fd),
+ /*require_seals_if_supported=*/true,
+ TracingService::kMaxShmSize);
+#endif
+ if (!memory) {
+ PERFETTO_DLOG("AttachV2RingBuffer() rejected: could not map the memfd");
+ resp.Reject();
+ return;
+ }
+
+ // |resp| cannot be copied, but std::function requires a copyable callback.
+ // Capture a shared_ptr so callback copies refer to the same response.
+ auto pending =
+ std::make_shared<DeferredAttachV2RingBufferResponse>(std::move(resp));
+ producer->service_endpoint->AttachV2RingBuffer(
+ memory, req.chunk_size_bytes(), [pending](bool accepted) {
+ if (!accepted) {
+ pending->Reject();
+ return;
+ }
+ pending->Resolve(ipc::AsyncResult<
+ protos::gen::AttachV2RingBufferResponse>::Create());
+ });
+}
+
+void ProducerIPCService::DrainV2RingBuffer(
+ const protos::gen::DrainV2RingBufferRequest&,
+ DeferredDrainV2RingBufferResponse) {
+ auto* producer = GetProducerForCurrentRequest();
+ if (producer)
+ producer->service_endpoint->DrainV2RingBuffer();
+}
+
void ProducerIPCService::Sync(const protos::gen::SyncRequest&,
DeferredSyncResponse resp) {
RemoteProducer* producer = GetProducerForCurrentRequest();
@@ -86499,7 +95371,7 @@ std::unique_ptr<ProducerEndpoint> SystemProducerTracingBackend::ConnectProducer(
#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
shm = SharedMemoryWindows::Create(shmem_size_hint);
#else
- shm = PosixSharedMemory::Create(shmem_size_hint);
+ shm = PosixSharedMemory::Create(shmem_size_hint).ValueOrDie();
#endif
arbiter = SharedMemoryArbiter::CreateUnboundInstance(
shm.get(), shmem_page_size_hint, SharedMemoryABI::ShmemMode::kDefault);
diff --git a/deps/perfetto/sdk/perfetto.h b/deps/perfetto/sdk/perfetto.h
index 5bf6732f9b7..29ce162dd55 100644
--- a/deps/perfetto/sdk/perfetto.h
+++ b/deps/perfetto/sdk/perfetto.h
@@ -543,6 +543,17 @@ static const int kPerfettoBuildFlagsCount = sizeof(kPerfettoBuildFlags) / sizeof
#define PERFETTO_NORETURN __declspec(noreturn)
#endif
+// Promises that what a pointer reaches is reached through nothing else in its
+// scope, so writes through it cannot change what other pointers read. Not
+// `__restrict`: the macOS SDK defines that away to nothing in C++.
+#if defined(__GNUC__) || defined(__clang__)
+#define PERFETTO_RESTRICT __restrict__
+#elif defined(_MSC_VER)
+#define PERFETTO_RESTRICT __restrict
+#else
+#define PERFETTO_RESTRICT
+#endif
+
#if defined(__GNUC__) || defined(__clang__)
#define PERFETTO_DEBUG_FUNCTION_IDENTIFIER() __PRETTY_FUNCTION__
#elif defined(_MSC_VER)
@@ -595,7 +606,7 @@ extern "C" void __msan_unpoison(void const volatile*, size_t);
#endif // __clang__
#if defined(__GNUC__) || defined(__clang__)
-#define PERFETTO_IS_LITTLE_ENDIAN() __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
+#define PERFETTO_IS_LITTLE_ENDIAN() (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)
#else
// Assume all MSVC targets are little endian.
#define PERFETTO_IS_LITTLE_ENDIAN() 1
@@ -1036,6 +1047,7 @@ inline void MaybeSerializeLastLogsForCrashReporting() {}
#include <mach/mach_init.h>
#include <mach/mach_port.h>
#include <mach/mach_time.h>
+#include <mach/task.h>
#include <mach/thread_act.h>
#endif
@@ -1534,6 +1546,38 @@ static inline uint32_t PerfettoPbMakeTag(int32_t field_id,
PERFETTO_STATIC_CAST(uint32_t, wire_type);
}
+// Constants for tracing v2's append-only proto group format:
+//
+// open nested field f: varint((f << 3) | 3)
+// close current nested: 0x04
+// root: no wrapper and no close byte
+//
+// Unlike standard protobuf groups, the closing byte does not repeat the field
+// number. It encodes field zero (invalid in standard protobuf) with wire
+// type 4. At a field boundary, it closes the innermost message. The packet
+// boundary ends the root.
+//
+// The parent writes both the start tag and the closing byte of a nested
+// message. A root has no parent, so nothing writes a closing byte for it.
+//
+// The packet must be rewritten to length-delimited protobuf before standard
+// decoders can read it. See RFC 0014 for the design:
+// https://github.com/google/perfetto/discussions/4508.
+//
+// The wire types stay outside PerfettoPbWireType because the decoders do not
+// support groups. Keep in sync with kWireTypeStartGroup and kProtoGroupEndByte
+// in perfetto/protozero/proto_utils.h.
+enum {
+ PERFETTO_PB_WIRE_TYPE_START_GROUP = 3,
+ PERFETTO_PB_PROTO_GROUP_END_BYTE = 0x04,
+};
+
+// Creates the tag that opens a nested message in proto group mode.
+static inline uint32_t PerfettoPbMakeTagStartGroup(int32_t field_id) {
+ return ((PERFETTO_STATIC_CAST(uint32_t, field_id)) << 3) |
+ PERFETTO_STATIC_CAST(uint32_t, PERFETTO_PB_WIRE_TYPE_START_GROUP);
+}
+
enum {
// Maximum bytes size of a 64-bit integer encoded as a VarInt.
PERFETTO_PB_VARINT_MAX_SIZE_64 = 10,
@@ -1695,6 +1739,7 @@ static inline uint32_t PerfettoPbFloatToFixed32(float value) {
#include <cinttypes>
#include <type_traits>
+// gen_amalgamated expanded: #include "perfetto/base/compiler.h"
// gen_amalgamated expanded: #include "perfetto/base/logging.h"
// gen_amalgamated expanded: #include "perfetto/public/compiler.h"
// gen_amalgamated expanded: #include "perfetto/public/pb_utils.h"
@@ -1721,6 +1766,41 @@ enum class ProtoWireType : uint32_t {
kFixed32 = 5,
};
+// Wire types for proto group boundaries. These stay outside ProtoWireType
+// because protozero decoders do not support groups. See kProtoGroupEndByte.
+// Keep in sync with PERFETTO_PB_WIRE_TYPE_START_GROUP in public/pb_utils.h.
+constexpr uint32_t kWireTypeStartGroup = 3;
+constexpr uint32_t kWireTypeEndGroup = 4;
+
+// Closing byte for tracing v2's append-only proto group format:
+//
+// open nested field f: varint((f << 3) | 3)
+// close current nested: 0x04
+// root: no wrapper and no close byte
+//
+// Unlike standard protobuf groups, the closing byte does not repeat the field
+// number. It encodes field zero (invalid in standard protobuf) with wire
+// type 4. At a field boundary, it closes the innermost message. The packet
+// boundary ends the root.
+//
+// The parent writes both the start tag and the closing byte of a nested
+// message, as it writes the tag and the length field of a length-delimited
+// one. A root has no parent, so nothing writes a closing byte for it.
+//
+// The packet must be rewritten to length-delimited protobuf before standard
+// decoders can read it. See RFC 0014 for the design:
+// https://github.com/google/perfetto/discussions/4508.
+// Keep in sync with PERFETTO_PB_PROTO_GROUP_END_BYTE in pb_utils.h.
+constexpr uint8_t kProtoGroupEndByte = static_cast<uint8_t>(kWireTypeEndGroup);
+
+// Enforces the "Keep in sync" rules above.
+static_assert(kWireTypeStartGroup ==
+ static_cast<uint32_t>(PERFETTO_PB_WIRE_TYPE_START_GROUP),
+ "C and C++ start group wire types differ");
+static_assert(kProtoGroupEndByte ==
+ static_cast<uint8_t>(PERFETTO_PB_PROTO_GROUP_END_BYTE),
+ "C and C++ proto group closing bytes differ");
+
// This is the type defined in the proto for each field. This information
// is used to decide the translation strategy when writing the trace.
enum class ProtoSchemaType {
@@ -1873,6 +1953,11 @@ constexpr uint32_t MakeTagLengthDelimited(uint32_t field_id) {
static_cast<uint32_t>(ProtoWireType::kLengthDelimited);
}
+// Opens a nested message in the proto group encoding described above.
+constexpr uint32_t MakeTagStartGroup(uint32_t field_id) {
+ return (field_id << kFieldTypeNumBits) | kWireTypeStartGroup;
+}
+
// Proto types: sint64, sint32.
template <typename T>
inline typename std::make_unsigned<T>::type ZigZagEncode(T value) {
@@ -2587,6 +2672,8 @@ class InterceptorConfig;
class ConsoleConfig;
class ChromeConfig;
class SystemInfoConfig;
+class DataSourceConfig_ExperimentalTracingV2Config;
+class DataSourceConfig_ExperimentalTracingV2Config_ChunkSizeOption;
class ProtoVmConfig;
class PriorityBoostConfig;
enum DataSourceConfig_SessionInitiator : int;
@@ -2618,6 +2705,7 @@ enum DataSourceConfig_BufferExhaustedPolicy : int {
class PERFETTO_EXPORT_COMPONENT DataSourceConfig : public ::protozero::CppMessageObj {
public:
+ using ExperimentalTracingV2Config = DataSourceConfig_ExperimentalTracingV2Config;
using SessionInitiator = DataSourceConfig_SessionInitiator;
static constexpr auto SESSION_INITIATOR_UNSPECIFIED = DataSourceConfig_SessionInitiator_SESSION_INITIATOR_UNSPECIFIED;
static constexpr auto SESSION_INITIATOR_TRUSTED_SYSTEM = DataSourceConfig_SessionInitiator_SESSION_INITIATOR_TRUSTED_SYSTEM;
@@ -2643,6 +2731,8 @@ class PERFETTO_EXPORT_COMPONENT DataSourceConfig : public ::protozero::CppMessag
kBufferExhaustedPolicyFieldNumber = 9,
kPriorityBoostFieldNumber = 10,
kProtovmConfigFieldNumber = 12,
+ kSupportsTracingV2FieldNumber = 147,
+ kExperimentalTracingV2FieldNumber = 148,
kFtraceConfigFieldNumber = 100,
kInodeFileConfigFieldNumber = 102,
kProcessStatsConfigFieldNumber = 103,
@@ -2685,6 +2775,10 @@ class PERFETTO_EXPORT_COMPONENT DataSourceConfig : public ::protozero::CppMessag
kAndroidAflagsConfigFieldNumber = 140,
kJournaldConfigFieldNumber = 141,
kDisplayVideoConfigFieldNumber = 142,
+ kChromiumStackSamplingProfilerFieldNumber = 143,
+ kChromiumSamplingHeapProfilerFieldNumber = 144,
+ kAndroidProcessStateConfigFieldNumber = 145,
+ kProcessSmapsConfigFieldNumber = 146,
kQnxConfigFieldNumber = 150,
kLegacyConfigFieldNumber = 1000,
kForTestingFieldNumber = 1001,
@@ -2752,6 +2846,14 @@ class PERFETTO_EXPORT_COMPONENT DataSourceConfig : public ::protozero::CppMessag
const ProtoVmConfig& protovm_config() const { return *protovm_config_; }
ProtoVmConfig* mutable_protovm_config() { _has_field_.set(12); return protovm_config_.get(); }
+ bool has_supports_tracing_v2() const { return _has_field_[147]; }
+ bool supports_tracing_v2() const { return supports_tracing_v2_; }
+ void set_supports_tracing_v2(bool value) { supports_tracing_v2_ = value; _has_field_.set(147); }
+
+ bool has_experimental_tracing_v2() const { return _has_field_[148]; }
+ const DataSourceConfig_ExperimentalTracingV2Config& experimental_tracing_v2() const { return *experimental_tracing_v2_; }
+ DataSourceConfig_ExperimentalTracingV2Config* mutable_experimental_tracing_v2() { _has_field_.set(148); return experimental_tracing_v2_.get(); }
+
const std::string& ftrace_config_raw() const { return ftrace_config_; }
void set_ftrace_config_raw(const std::string& raw) { ftrace_config_ = raw; _has_field_.set(100); }
@@ -2881,6 +2983,18 @@ class PERFETTO_EXPORT_COMPONENT DataSourceConfig : public ::protozero::CppMessag
const std::string& display_video_config_raw() const { return display_video_config_; }
void set_display_video_config_raw(const std::string& raw) { display_video_config_ = raw; _has_field_.set(142); }
+ const std::string& chromium_stack_sampling_profiler_raw() const { return chromium_stack_sampling_profiler_; }
+ void set_chromium_stack_sampling_profiler_raw(const std::string& raw) { chromium_stack_sampling_profiler_ = raw; _has_field_.set(143); }
+
+ const std::string& chromium_sampling_heap_profiler_raw() const { return chromium_sampling_heap_profiler_; }
+ void set_chromium_sampling_heap_profiler_raw(const std::string& raw) { chromium_sampling_heap_profiler_ = raw; _has_field_.set(144); }
+
+ const std::string& android_process_state_config_raw() const { return android_process_state_config_; }
+ void set_android_process_state_config_raw(const std::string& raw) { android_process_state_config_ = raw; _has_field_.set(145); }
+
+ const std::string& process_smaps_config_raw() const { return process_smaps_config_; }
+ void set_process_smaps_config_raw(const std::string& raw) { process_smaps_config_ = raw; _has_field_.set(146); }
+
const std::string& qnx_config_raw() const { return qnx_config_; }
void set_qnx_config_raw(const std::string& raw) { qnx_config_ = raw; _has_field_.set(150); }
@@ -2905,6 +3019,8 @@ class PERFETTO_EXPORT_COMPONENT DataSourceConfig : public ::protozero::CppMessag
DataSourceConfig_BufferExhaustedPolicy buffer_exhausted_policy_{};
::protozero::CopyablePtr<PriorityBoostConfig> priority_boost_;
::protozero::CopyablePtr<ProtoVmConfig> protovm_config_;
+ bool supports_tracing_v2_{};
+ ::protozero::CopyablePtr<DataSourceConfig_ExperimentalTracingV2Config> experimental_tracing_v2_;
std::string ftrace_config_; // [lazy=true]
std::string inode_file_config_; // [lazy=true]
std::string process_stats_config_; // [lazy=true]
@@ -2947,6 +3063,10 @@ class PERFETTO_EXPORT_COMPONENT DataSourceConfig : public ::protozero::CppMessag
std::string android_aflags_config_; // [lazy=true]
std::string journald_config_; // [lazy=true]
std::string display_video_config_; // [lazy=true]
+ std::string chromium_stack_sampling_profiler_; // [lazy=true]
+ std::string chromium_sampling_heap_profiler_; // [lazy=true]
+ std::string android_process_state_config_; // [lazy=true]
+ std::string process_smaps_config_; // [lazy=true]
std::string qnx_config_; // [lazy=true]
std::string legacy_config_{};
::protozero::CopyablePtr<TestConfig> for_testing_;
@@ -2958,6 +3078,97 @@ class PERFETTO_EXPORT_COMPONENT DataSourceConfig : public ::protozero::CppMessag
std::bitset<1002> _has_field_{};
};
+
+class PERFETTO_EXPORT_COMPONENT DataSourceConfig_ExperimentalTracingV2Config : public ::protozero::CppMessageObj {
+ public:
+ using ChunkSizeOption = DataSourceConfig_ExperimentalTracingV2Config_ChunkSizeOption;
+ enum FieldNumbers {
+ kUseV2ProbabilityPercentFieldNumber = 1,
+ kChunkSizeOptionsFieldNumber = 2,
+ kDrainOccupancyPercentFieldNumber = 3,
+ };
+
+ DataSourceConfig_ExperimentalTracingV2Config();
+ ~DataSourceConfig_ExperimentalTracingV2Config() override;
+ DataSourceConfig_ExperimentalTracingV2Config(DataSourceConfig_ExperimentalTracingV2Config&&) noexcept;
+ DataSourceConfig_ExperimentalTracingV2Config& operator=(DataSourceConfig_ExperimentalTracingV2Config&&);
+ DataSourceConfig_ExperimentalTracingV2Config(const DataSourceConfig_ExperimentalTracingV2Config&);
+ DataSourceConfig_ExperimentalTracingV2Config& operator=(const DataSourceConfig_ExperimentalTracingV2Config&);
+ bool operator==(const DataSourceConfig_ExperimentalTracingV2Config&) const;
+ bool operator!=(const DataSourceConfig_ExperimentalTracingV2Config& other) const { return !(*this == other); }
+
+ bool ParseFromArray(const void*, size_t) override;
+ std::string SerializeAsString() const override;
+ std::vector<uint8_t> SerializeAsArray() const override;
+ void Serialize(::protozero::Message*) const;
+
+ bool has_use_v2_probability_percent() const { return _has_field_[1]; }
+ uint32_t use_v2_probability_percent() const { return use_v2_probability_percent_; }
+ void set_use_v2_probability_percent(uint32_t value) { use_v2_probability_percent_ = value; _has_field_.set(1); }
+
+ const std::vector<DataSourceConfig_ExperimentalTracingV2Config_ChunkSizeOption>& chunk_size_options() const { return chunk_size_options_; }
+ std::vector<DataSourceConfig_ExperimentalTracingV2Config_ChunkSizeOption>* mutable_chunk_size_options() { return &chunk_size_options_; }
+ int chunk_size_options_size() const;
+ void clear_chunk_size_options();
+ DataSourceConfig_ExperimentalTracingV2Config_ChunkSizeOption* add_chunk_size_options();
+
+ bool has_drain_occupancy_percent() const { return _has_field_[3]; }
+ int32_t drain_occupancy_percent() const { return drain_occupancy_percent_; }
+ void set_drain_occupancy_percent(int32_t value) { drain_occupancy_percent_ = value; _has_field_.set(3); }
+
+ private:
+ uint32_t use_v2_probability_percent_{};
+ std::vector<DataSourceConfig_ExperimentalTracingV2Config_ChunkSizeOption> chunk_size_options_;
+ int32_t drain_occupancy_percent_{};
+
+ // Allows to preserve unknown protobuf fields for compatibility
+ // with future versions of .proto files.
+ std::string unknown_fields_;
+
+ std::bitset<4> _has_field_{};
+};
+
+
+class PERFETTO_EXPORT_COMPONENT DataSourceConfig_ExperimentalTracingV2Config_ChunkSizeOption : public ::protozero::CppMessageObj {
+ public:
+ enum FieldNumbers {
+ kSizeBytesFieldNumber = 1,
+ kWeightFieldNumber = 2,
+ };
+
+ DataSourceConfig_ExperimentalTracingV2Config_ChunkSizeOption();
+ ~DataSourceConfig_ExperimentalTracingV2Config_ChunkSizeOption() override;
+ DataSourceConfig_ExperimentalTracingV2Config_ChunkSizeOption(DataSourceConfig_ExperimentalTracingV2Config_ChunkSizeOption&&) noexcept;
+ DataSourceConfig_ExperimentalTracingV2Config_ChunkSizeOption& operator=(DataSourceConfig_ExperimentalTracingV2Config_ChunkSizeOption&&);
+ DataSourceConfig_ExperimentalTracingV2Config_ChunkSizeOption(const DataSourceConfig_ExperimentalTracingV2Config_ChunkSizeOption&);
+ DataSourceConfig_ExperimentalTracingV2Config_ChunkSizeOption& operator=(const DataSourceConfig_ExperimentalTracingV2Config_ChunkSizeOption&);
+ bool operator==(const DataSourceConfig_ExperimentalTracingV2Config_ChunkSizeOption&) const;
+ bool operator!=(const DataSourceConfig_ExperimentalTracingV2Config_ChunkSizeOption& other) const { return !(*this == other); }
+
+ bool ParseFromArray(const void*, size_t) override;
+ std::string SerializeAsString() const override;
+ std::vector<uint8_t> SerializeAsArray() const override;
+ void Serialize(::protozero::Message*) const;
+
+ bool has_size_bytes() const { return _has_field_[1]; }
+ uint32_t size_bytes() const { return size_bytes_; }
+ void set_size_bytes(uint32_t value) { size_bytes_ = value; _has_field_.set(1); }
+
+ bool has_weight() const { return _has_field_[2]; }
+ uint32_t weight() const { return weight_; }
+ void set_weight(uint32_t value) { weight_ = value; _has_field_.set(2); }
+
+ private:
+ uint32_t size_bytes_{};
+ uint32_t weight_{};
+
+ // Allows to preserve unknown protobuf fields for compatibility
+ // with future versions of .proto files.
+ std::string unknown_fields_;
+
+ std::bitset<3> _has_field_{};
+};
+
} // namespace perfetto
} // namespace protos
} // namespace gen
@@ -2994,6 +3205,256 @@ class PERFETTO_EXPORT_COMPONENT DataSourceConfig : public ::protozero::CppMessag
// gen_amalgamated begin header: include/perfetto/tracing/trace_writer_base.h
// gen_amalgamated begin header: include/perfetto/protozero/message_handle.h
// gen_amalgamated begin header: include/perfetto/protozero/message.h
+// gen_amalgamated begin header: include/perfetto/base/endian.h
+/*
+ * 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.
+ */
+
+#ifndef INCLUDE_PERFETTO_BASE_ENDIAN_H_
+#define INCLUDE_PERFETTO_BASE_ENDIAN_H_
+
+#include <stdint.h>
+#include <stdlib.h> // For MSVC
+#include <string.h>
+
+// gen_amalgamated expanded: #include "perfetto/base/build_config.h"
+// gen_amalgamated expanded: #include "perfetto/base/compiler.h"
+
+namespace perfetto {
+namespace base {
+
+#if PERFETTO_BUILDFLAG(PERFETTO_COMPILER_MSVC)
+inline uint16_t ByteSwap16(uint16_t x) {
+ return _byteswap_ushort(x);
+}
+inline uint32_t ByteSwap32(uint32_t x) {
+ return _byteswap_ulong(x);
+}
+inline uint64_t ByteSwap64(uint64_t x) {
+ return _byteswap_uint64(x);
+}
+#else
+inline uint16_t ByteSwap16(uint16_t x) {
+ return __builtin_bswap16(x);
+}
+inline uint32_t ByteSwap32(uint32_t x) {
+ return __builtin_bswap32(x);
+}
+inline uint64_t ByteSwap64(uint64_t x) {
+ return __builtin_bswap64(x);
+}
+#endif
+
+#if PERFETTO_IS_LITTLE_ENDIAN()
+inline uint16_t HostToLE16(uint16_t x) {
+ return x;
+}
+inline uint32_t HostToLE32(uint32_t x) {
+ return x;
+}
+inline uint64_t HostToLE64(uint64_t x) {
+ return x;
+}
+inline uint16_t LE16ToHost(uint16_t x) {
+ return x;
+}
+inline uint32_t LE32ToHost(uint32_t x) {
+ return x;
+}
+inline uint64_t LE64ToHost(uint64_t x) {
+ return x;
+}
+inline uint16_t HostToBE16(uint16_t x) {
+ return ByteSwap16(x);
+}
+inline uint32_t HostToBE32(uint32_t x) {
+ return ByteSwap32(x);
+}
+inline uint64_t HostToBE64(uint64_t x) {
+ return ByteSwap64(x);
+}
+inline uint16_t BE16ToHost(uint16_t x) {
+ return ByteSwap16(x);
+}
+inline uint32_t BE32ToHost(uint32_t x) {
+ return ByteSwap32(x);
+}
+inline uint64_t BE64ToHost(uint64_t x) {
+ return ByteSwap64(x);
+}
+inline float HostToLEFloat(float x) {
+ return x;
+}
+inline double HostToLEDouble(double x) {
+ return x;
+}
+inline float LEFloatToHost(float x) {
+ return x;
+}
+inline double LEDoubleToHost(double x) {
+ return x;
+}
+inline float HostToBEFloat(float x) {
+ uint32_t u;
+ memcpy(&u, &x, sizeof(u));
+ u = ByteSwap32(u);
+ memcpy(&x, &u, sizeof(u));
+ return x;
+}
+inline double HostToBEDouble(double x) {
+ uint64_t u;
+ memcpy(&u, &x, sizeof(u));
+ u = ByteSwap64(u);
+ memcpy(&x, &u, sizeof(u));
+ return x;
+}
+inline float BEFloatToHost(float x) {
+ uint32_t u;
+ memcpy(&u, &x, sizeof(u));
+ u = ByteSwap32(u);
+ memcpy(&x, &u, sizeof(u));
+ return x;
+}
+inline double BEDoubleToHost(double x) {
+ uint64_t u;
+ memcpy(&u, &x, sizeof(u));
+ u = ByteSwap64(u);
+ memcpy(&x, &u, sizeof(u));
+ return x;
+}
+#else
+inline uint16_t HostToLE16(uint16_t x) {
+ return ByteSwap16(x);
+}
+inline uint32_t HostToLE32(uint32_t x) {
+ return ByteSwap32(x);
+}
+inline uint64_t HostToLE64(uint64_t x) {
+ return ByteSwap64(x);
+}
+inline uint16_t LE16ToHost(uint16_t x) {
+ return ByteSwap16(x);
+}
+inline uint32_t LE32ToHost(uint32_t x) {
+ return ByteSwap32(x);
+}
+inline uint64_t LE64ToHost(uint64_t x) {
+ return ByteSwap64(x);
+}
+inline uint16_t HostToBE16(uint16_t x) {
+ return x;
+}
+inline uint32_t HostToBE32(uint32_t x) {
+ return x;
+}
+inline uint64_t HostToBE64(uint64_t x) {
+ return x;
+}
+inline uint16_t BE16ToHost(uint16_t x) {
+ return x;
+}
+inline uint32_t BE32ToHost(uint32_t x) {
+ return x;
+}
+inline uint64_t BE64ToHost(uint64_t x) {
+ return x;
+}
+inline float HostToLEFloat(float x) {
+ uint32_t u;
+ memcpy(&u, &x, sizeof(u));
+ u = ByteSwap32(u);
+ memcpy(&x, &u, sizeof(u));
+ return x;
+}
+inline double HostToLEDouble(double x) {
+ uint64_t u;
+ memcpy(&u, &x, sizeof(u));
+ u = ByteSwap64(u);
+ memcpy(&x, &u, sizeof(u));
+ return x;
+}
+inline float LEFloatToHost(float x) {
+ uint32_t u;
+ memcpy(&u, &x, sizeof(u));
+ u = ByteSwap32(u);
+ memcpy(&x, &u, sizeof(u));
+ return x;
+}
+inline double LEDoubleToHost(double x) {
+ uint64_t u;
+ memcpy(&u, &x, sizeof(u));
+ u = ByteSwap64(u);
+ memcpy(&x, &u, sizeof(u));
+ return x;
+}
+inline float HostToBEFloat(float x) {
+ return x;
+}
+inline double HostToBEDouble(double x) {
+ return x;
+}
+inline float BEFloatToHost(float x) {
+ return x;
+}
+inline double BEDoubleToHost(double x) {
+ return x;
+}
+#endif
+
+inline uint32_t HostToLE(uint32_t x) {
+ return HostToLE32(x);
+}
+inline int32_t HostToLE(int32_t x) {
+ return static_cast<int32_t>(HostToLE32(static_cast<uint32_t>(x)));
+}
+inline uint64_t HostToLE(uint64_t x) {
+ return HostToLE64(x);
+}
+inline int64_t HostToLE(int64_t x) {
+ return static_cast<int64_t>(HostToLE64(static_cast<uint64_t>(x)));
+}
+inline float HostToLE(float x) {
+ return HostToLEFloat(x);
+}
+inline double HostToLE(double x) {
+ return HostToLEDouble(x);
+}
+
+inline uint32_t LEToHost(uint32_t x) {
+ return LE32ToHost(x);
+}
+inline int32_t LEToHost(int32_t x) {
+ return static_cast<int32_t>(LE32ToHost(static_cast<uint32_t>(x)));
+}
+inline uint64_t LEToHost(uint64_t x) {
+ return LE64ToHost(x);
+}
+inline int64_t LEToHost(int64_t x) {
+ return static_cast<int64_t>(LE64ToHost(static_cast<uint64_t>(x)));
+}
+inline float LEToHost(float x) {
+ return LEFloatToHost(x);
+}
+inline double LEToHost(double x) {
+ return LEDoubleToHost(x);
+}
+
+} // namespace base
+} // namespace perfetto
+
+#endif // INCLUDE_PERFETTO_BASE_ENDIAN_H_
// gen_amalgamated begin header: include/perfetto/protozero/scattered_stream_writer.h
/*
* Copyright (C) 2017 The Android Open Source Project
@@ -3200,6 +3661,7 @@ class PERFETTO_EXPORT_COMPONENT ScatteredStreamWriter {
#include <string>
#include <type_traits>
+// gen_amalgamated expanded: #include "perfetto/base/endian.h"
// gen_amalgamated expanded: #include "perfetto/base/export.h"
// gen_amalgamated expanded: #include "perfetto/base/logging.h"
// gen_amalgamated expanded: #include "perfetto/protozero/contiguous_memory_range.h"
@@ -3234,16 +3696,46 @@ class PERFETTO_EXPORT_COMPONENT Message {
// static_assert()s in the Reset() method.
Message() = default;
- // Clears up the state, allowing the message to be reused as a fresh one.
- void Reset(ScatteredStreamWriter*, MessageArena*);
-
- // Commits all the changes to the buffer (backfills the size field of this and
- // all nested messages) and seals the message. Returns the size of the message
- // (and all nested sub-messages), without taking into account any chunking.
+ // Encoding for nested messages. The root selects it in Reset(). Each child
+ // inherits its parent's encoding.
+ // Keep in sync with PerfettoPbMsgEncoding in perfetto/public/pb_msg.h.
+ enum class Encoding : uint8_t {
+ // Standard protobuf. Finalize() writes each child's length into a reserved
+ // field before the child's contents.
+ kLengthDelimited = 0,
+
+ // Append-only format for tracing v2. It needs no patches:
+ // - A nested message starts with a group start tag and ends with a
+ // closing byte, instead of a fixed-size length field.
+ // - Use it only inside the SMB, for the tracing v2 protocol. The final
+ // trace output stays canonical protobuf.
+ // See proto_utils::kProtoGroupEndByte for the wire format.
+ kProtoGroup = 1,
+ };
+
+ // Returns the encoding each new child inherits.
+ Encoding encoding() const { return encoding_; }
+
+ // Clears up the state, allowing the message to be reused as a fresh one
+ // with the specified encoding.
+ void Reset(ScatteredStreamWriter*, MessageArena*, Encoding);
+
+ // Convenience wrapper for the default length-delimited encoding.
+ // See the TODO on RootMessage::Reset().
+ void Reset(ScatteredStreamWriter* stream_writer, MessageArena* arena) {
+ Reset(stream_writer, arena, Encoding::kLengthDelimited);
+ }
+
+ // Finalizes all open children, then seals this message:
+ // - Length-delimited: writes the encoded size into the reserved length field,
+ // if present. For short messages within the current chunk, compaction can
+ // reduce the field from proto_utils::kMessageLengthFieldSize bytes to one.
+ // - kProtoGroup: writes nothing. The parent writes the closing byte.
+ //
+ // Returns the encoded size of this message's fields, including nested
+ // messages. It excludes this message's own tag, length field and closing
+ // byte.
// Finalize is idempotent and can be called several times w/o side effects.
- // Short messages may be compacted in memory into the size field, since their
- // size can be represented with fewer than
- // proto_utils::kMessageLengthFieldSize bytes.
uint32_t Finalize();
// Optional. If is_valid() == true, the corresponding memory region (its
@@ -3252,6 +3744,8 @@ class PERFETTO_EXPORT_COMPONENT Message {
// corresponding size field in the parent message. In most cases this is only
// used for nested messages and the ScatteredStreamWriter::Delegate (e.g.
// TraceWriterImpl), takes case of the outer message.
+ //
+ // In kProtoGroup mode, this pointer must always be null.
uint8_t* size_field() const { return size_field_; }
void set_size_field(uint8_t* size_field) { size_field_ = size_field; }
@@ -3311,7 +3805,8 @@ class PERFETTO_EXPORT_COMPONENT Message {
uint8_t* pos = buffer;
pos = proto_utils::WriteVarInt(proto_utils::MakeTagFixed<T>(field_id), pos);
- memcpy(pos, &value, sizeof(T));
+ T le_value = perfetto::base::HostToLE(value);
+ memcpy(pos, &le_value, sizeof(T));
pos += sizeof(T);
// TODO: Optimize memcpy performance, see http://crbug.com/624311 .
WriteToStream(buffer, pos);
@@ -3357,6 +3852,12 @@ class PERFETTO_EXPORT_COMPONENT Message {
// generated by the cppgen_plugin.cc.
// The caller needs to guarantee that the appended data is properly
// proto-encoded and each field has a proto preamble.
+ //
+ // In kProtoGroup mode:
+ // - |data| must not contain protobuf group fields. This mode reserves wire
+ // types 3 and 4 for nested message boundaries.
+ // - A nested message must contain only proto fields. For a raw string or
+ // bytes payload, use AppendBytes() on the parent.
void AppendRawProtoBytes(const void* data, size_t size) {
if (nested_message_)
EndNestedMessage();
@@ -3371,6 +3872,8 @@ class PERFETTO_EXPORT_COMPONENT Message {
Message* BeginNestedMessageInternal(uint32_t field_id);
// Called by Finalize and Append* methods.
+ // Ends the open child: finalizes it, adds its encoded size to this message
+ // and, in kProtoGroup mode, appends its closing byte.
void EndNestedMessage();
void WriteToStream(const uint8_t* src_begin, const uint8_t* src_end) {
@@ -3403,6 +3906,8 @@ class PERFETTO_EXPORT_COMPONENT Message {
// [optional] Pointer to a non-aligned pre-reserved var-int slot of
// kMessageLengthFieldSize bytes. When set, the Finalize() method will write
// the size of proto-encoded message in the pointed memory region.
+ //
+ // In kProtoGroup mode, this pointer is unused and always null.
uint8_t* size_field_;
// Keeps track of the size of the current message.
@@ -3422,6 +3927,9 @@ class PERFETTO_EXPORT_COMPONENT Message {
MessageState message_state_;
+ // Selected by the root and inherited by every nested message.
+ Encoding encoding_;
+
#if PERFETTO_DCHECK_IS_ON()
// Current generation of message. Incremented on Reset.
// Used to detect stale handles.
@@ -3838,6 +4346,14 @@ struct DataSourceState {
// this data source.
std::atomic<uint32_t> incremental_state_generation{0};
+ // True if the writers of this instance use tracing v2.
+ // The muxer sets it once during setup, before writer threads see the
+ // instance.
+ // It stays true if v2 initialization fails, so the writers discard their
+ // data and do not fall back to v1.
+ // A startup instance keeps v1, also after adoption.
+ bool use_tracing_v2 = false;
+
// This lock is not held to implement Trace() and it's used only if the trace
// code wants to access its own data source state.
// This is to prevent that accessing the data source on an arbitrary embedder
@@ -4563,6 +5079,7 @@ struct FieldWriter<proto_utils::ProtoSchemaType::kBytes> {
#include <memory>
#include <type_traits>
+// gen_amalgamated expanded: #include "perfetto/base/endian.h"
// gen_amalgamated expanded: #include "perfetto/base/logging.h"
// gen_amalgamated expanded: #include "perfetto/protozero/proto_utils.h"
@@ -4645,7 +5162,8 @@ class PackedFixedSizeInt : public PackedBufferBase {
"kMaxElementSize needs to be updated");
GrowIfNeeded();
PERFETTO_DCHECK(reinterpret_cast<size_t>(write_ptr_) % alignof(T) == 0);
- memcpy(reinterpret_cast<T*>(write_ptr_), &value, sizeof(T));
+ T le_value = perfetto::base::HostToLE(value);
+ memcpy(reinterpret_cast<T*>(write_ptr_), &le_value, sizeof(T));
write_ptr_ += sizeof(T);
}
};
@@ -4683,6 +5201,7 @@ class PackedFixedSizeInt : public PackedBufferBase {
#include <type_traits>
#include <variant>
+// gen_amalgamated expanded: #include "perfetto/base/endian.h"
// gen_amalgamated expanded: #include "perfetto/base/export.h"
// gen_amalgamated expanded: #include "perfetto/base/logging.h"
// gen_amalgamated expanded: #include "perfetto/protozero/field.h"
@@ -4880,7 +5399,7 @@ class PackedRepeatedFieldIterator {
return *this;
}
- if (wire_type == ProtoWireType::kVarInt) {
+ if constexpr (wire_type == ProtoWireType::kVarInt) {
uint64_t new_value = 0;
const uint8_t* new_pos =
proto_utils::ParseVarInt(read_ptr_, data_end_, &new_value);
@@ -4899,6 +5418,7 @@ class PackedRepeatedFieldIterator {
// NB: the raw buffer is not guaranteed to be aligned, so neither are
// these copies.
memcpy(&curr_value_, read_ptr_, sizeof(CppType));
+ curr_value_ = perfetto::base::LEToHost(curr_value_);
read_ptr_ += kStep;
}
@@ -4983,7 +5503,8 @@ class UnifiedRepeatedFieldIterator {
// static constexpr SelectiveDecodeMask<TracePacket::kTimestampFieldNumber,
// TracePacket::kInternedDataFieldNumber>
// kMask{};
-// SelectiveTypedProtoDecoder<MAX_FIELD_ID> decoder(data, size, kMask);
+// SelectiveTypedProtoDecoder<TypedProtoDecoder<MAX_FIELD_ID>> decoder(
+// data, size, kMask);
// for (const Field& f : decoder.unknown_fields()) { ... }
template <uint32_t... kFieldIds>
class SelectiveDecodeMask {
@@ -5042,6 +5563,24 @@ class PERFETTO_EXPORT_COMPONENT TypedProtoDecoderBase : public ProtoDecoder {
return kInvalidField;
}
+ // True if the message contained at least one field with an id beyond the
+ // highest id known in-tree (typically an out-of-tree extension). Such
+ // fields are not stored here; this lets callers skip a selective re-decode
+ // via unknown_fields() when there is nothing to find.
+ bool has_out_of_range_fields() const { return has_out_of_range_fields_; }
+
+ // True if any field whose bit is set in |mask| is present. |mask| is laid
+ // out like the presence bitmap (bit i of word i / 64 for field id i) and
+ // holds |words| words; bits beyond the known field range are ignored.
+ bool HasAnyField(const uint64_t* mask, size_t words) const {
+ size_t presence_words = (num_fields_ + 63) / 64;
+ for (size_t i = 0; i < words && i < presence_words; ++i) {
+ if (presence_[i] & mask[i])
+ return true;
+ }
+ return false;
+ }
+
// True if the field with the given id was seen while decoding: tests bit
// |id| of the presence bitmap. The caller must check that |id| is within
// the bitmap, i.e. <= the decoder's MAX_FIELD_ID. Note that |id| may
@@ -5221,6 +5760,9 @@ class PERFETTO_EXPORT_COMPONENT TypedProtoDecoderBase : public ProtoDecoder {
// |size_| is always <= |capacity_|. But |num_fields_| can be > |size_|.
uint32_t size_;
+ // See has_out_of_range_fields().
+ bool has_out_of_range_fields_ = false;
+
// Initially equal to kFieldsCapacity of the TypedProtoDecoder
// specialization. Can grow when falling back on heap-based storage, in which
// case it represents the size (#fields with each entry of a repeated field
@@ -5254,11 +5796,16 @@ class PERFETTO_EXPORT_COMPONENT TypedProtoDecoderBase : public ProtoDecoder {
template <int MAX_FIELD_ID, bool = false>
class TypedProtoDecoder : public TypedProtoDecoderBase {
public:
+ // The highest field id known to this decoder; see has_out_of_range_fields().
+ static constexpr uint32_t kMaxFieldId = static_cast<uint32_t>(MAX_FIELD_ID);
+
TypedProtoDecoder(const uint8_t* buffer, size_t length)
- : TypedProtoDecoder(SkipParseTag{},
- buffer,
- length,
- /*num_fields=*/MAX_FIELD_ID + 1) {
+ : TypedProtoDecoderBase(on_stack_storage_,
+ presence_storage_,
+ /*num_fields=*/MAX_FIELD_ID + 1,
+ PROTOZERO_DECODER_INITIAL_STACK_CAPACITY,
+ buffer,
+ length) {
TypedProtoDecoderBase::ParseAllFields();
}
@@ -5290,21 +5837,6 @@ class TypedProtoDecoder : public TypedProtoDecoderBase {
return *this;
}
- protected:
- // Sets up the storage but does not parse: for subclasses that drive
- // ParseAllFields() themselves (see SelectiveTypedProtoDecoder).
- struct SkipParseTag {};
- TypedProtoDecoder(SkipParseTag,
- const uint8_t* buffer,
- size_t length,
- uint32_t num_fields)
- : TypedProtoDecoderBase(on_stack_storage_,
- presence_storage_,
- num_fields,
- PROTOZERO_DECODER_INITIAL_STACK_CAPACITY,
- buffer,
- length) {}
-
private:
void MaybeCopyOnStackStorage(const TypedProtoDecoder& other) {
// If the moved-from decoder was using on-stack storage, we need to update
@@ -5344,37 +5876,34 @@ class TypedProtoDecoder : public TypedProtoDecoderBase {
// static constexpr SelectiveDecodeMask<TracePacket::kTimestampFieldNumber,
// TracePacket::kInternedDataFieldNumber>
// kMask{};
-// SelectiveTypedProtoDecoder<MAX_FIELD_ID> decoder(data, size, kMask);
+// SelectiveTypedProtoDecoder<TypedProtoDecoder<MAX_FIELD_ID>> decoder(
+// data, size, kMask);
// for (const Field& f : decoder.unknown_fields()) { ... }
-template <int MAX_FIELD_ID>
-class SelectiveTypedProtoDecoder : public TypedProtoDecoder<MAX_FIELD_ID> {
- using Base = TypedProtoDecoder<MAX_FIELD_ID>;
-
- public:
- // The dense window is capped at the mask's extent: |num_fields_| is the
- // only id bound the decode loop checks, so capping it both bounds the mask
- // read and makes every id above the mask spill, letting the mask be sized
- // to the allowlisted ids only rather than to MAX_FIELD_ID.
- // |mask| is only read during this call.
+template <typename Decoder>
+class SelectiveTypedProtoDecoder : public Decoder {
+ public:
+ // |Decoder| is a TypedProtoDecoder or a generated message decoder, whose
+ // typed accessors this class inherits. The dense window is capped at the
+ // mask's extent: |num_fields_| is the only id bound the decode loop checks,
+ // so capping it both bounds the mask read and makes every id above the
+ // mask spill, letting the mask be sized to the allowlisted ids only rather
+ // than to the decoder's max field id. |mask| is only read during this call.
template <uint32_t... kFieldIds>
SelectiveTypedProtoDecoder(const uint8_t* buffer,
size_t length,
const SelectiveDecodeMask<kFieldIds...>& mask)
- : Base(typename Base::SkipParseTag{},
- buffer,
- length,
- /*num_fields=*/
- std::min(static_cast<uint32_t>(MAX_FIELD_ID),
- SelectiveDecodeMask<kFieldIds...>::kMaxFieldId) +
- 1) {
- // The base constructor cleared the presence bitmap only up to the capped
- // |num_fields_|. at<>() skips the range check for ids below the on-stack
- // capacity and tests the presence bit directly, so the rest of the bitmap
- // must be cleared too.
- constexpr uint32_t kPresenceWords = (MAX_FIELD_ID + 1 + 63) / 64;
- const uint32_t cleared_words = (this->num_fields_ + 63) / 64;
- memset(this->presence_ + cleared_words, 0,
- (kPresenceWords - cleared_words) * sizeof(uint64_t));
+ : Decoder(nullptr, 0) {
+ // The empty decode above set up the storage and cleared the whole
+ // presence bitmap without parsing anything; point it at the real buffer
+ // and parse selectively.
+ this->begin_ = buffer;
+ this->end_ = buffer + length;
+ this->read_ptr_ = buffer;
+ this->num_fields_ =
+ std::min(Decoder::kMaxFieldId,
+ SelectiveDecodeMask<kFieldIds...>::kMaxFieldId) +
+ 1;
+ this->size_ = std::min(this->num_fields_, this->capacity_ - 1);
spill_ = spill_storage_;
uint32_t spill_capacity = kSpillStackCapacity;
this->ParseAllFieldsSelective(mask.data(), &spill_, &spill_capacity,
@@ -5388,7 +5917,7 @@ class SelectiveTypedProtoDecoder : public TypedProtoDecoder<MAX_FIELD_ID> {
}
SelectiveTypedProtoDecoder(SelectiveTypedProtoDecoder&& other) noexcept
- : Base(std::move(other)),
+ : Decoder(std::move(other)),
spill_(other.spill_),
spill_size_(other.spill_size_),
heap_spill_(std::move(other.heap_spill_)) {
@@ -7599,16 +8128,6 @@ namespace perfetto {
namespace protos {
namespace gen {
class DataSourceDescriptor;
-class VmProgram;
-class VmInstruction;
-class VmOpDel;
-class VmOpSet;
-class VmOpMerge;
-class VmOpRegLoad;
-class VmOpSelect;
-class VmOpSelect_PathComponent;
-enum VmInstruction_AbortLevel : int;
-enum VmCursorEnum : int;
} // namespace perfetto
} // namespace protos
} // namespace gen
@@ -7674,9 +8193,8 @@ class PERFETTO_EXPORT_COMPONENT DataSourceDescriptor : public ::protozero::CppMe
bool no_flush() const { return no_flush_; }
void set_no_flush(bool value) { no_flush_ = value; _has_field_.set(9); }
- bool has_protovm_program() const { return _has_field_[10]; }
- const VmProgram& protovm_program() const { return *protovm_program_; }
- VmProgram* mutable_protovm_program() { _has_field_.set(10); return protovm_program_.get(); }
+ const std::string& protovm_program_raw() const { return protovm_program_; }
+ void set_protovm_program_raw(const std::string& raw) { protovm_program_ = raw; _has_field_.set(10); }
const std::string& gpu_counter_descriptor_raw() const { return gpu_counter_descriptor_; }
void set_gpu_counter_descriptor_raw(const std::string& raw) { gpu_counter_descriptor_ = raw; _has_field_.set(5); }
@@ -7694,7 +8212,7 @@ class PERFETTO_EXPORT_COMPONENT DataSourceDescriptor : public ::protozero::CppMe
bool will_notify_on_start_{};
bool handles_incremental_state_clear_{};
bool no_flush_{};
- ::protozero::CopyablePtr<VmProgram> protovm_program_;
+ std::string protovm_program_; // [lazy=true]
std::string gpu_counter_descriptor_; // [lazy=true]
std::string track_event_descriptor_; // [lazy=true]
std::string ftrace_descriptor_; // [lazy=true]
@@ -7787,6 +8305,8 @@ class InterceptorConfig;
class ConsoleConfig;
class ChromeConfig;
class SystemInfoConfig;
+class DataSourceConfig_ExperimentalTracingV2Config;
+class DataSourceConfig_ExperimentalTracingV2Config_ChunkSizeOption;
class ProtoVmConfig;
class TraceConfig_BufferConfig;
enum TraceConfig_LockdownModeOperation : int;
@@ -7913,6 +8433,7 @@ class PERFETTO_EXPORT_COMPONENT TraceConfig : public ::protozero::CppMessageObj
static constexpr auto FFlushMode_MAX = TraceConfig_FFlushMode_FFLUSH_ENABLED;
enum FieldNumbers {
kBuffersFieldNumber = 1,
+ kExperimentalTraceBufferV2CompactionFieldNumber = 50,
kDataSourcesFieldNumber = 2,
kBuiltinDataSourcesFieldNumber = 20,
kDurationMsFieldNumber = 3,
@@ -7954,6 +8475,7 @@ class PERFETTO_EXPORT_COMPONENT TraceConfig : public ::protozero::CppMessageObj
kFflushPostWriteFieldNumber = 45,
kTraceAllMachinesFieldNumber = 43,
kTraceAttributesFieldNumber = 48,
+ kPersistTraceAcrossRebootsFieldNumber = 49,
};
TraceConfig();
@@ -7976,6 +8498,10 @@ class PERFETTO_EXPORT_COMPONENT TraceConfig : public ::protozero::CppMessageObj
void clear_buffers();
TraceConfig_BufferConfig* add_buffers();
+ bool has_experimental_trace_buffer_v2_compaction() const { return _has_field_[50]; }
+ bool experimental_trace_buffer_v2_compaction() const { return experimental_trace_buffer_v2_compaction_; }
+ void set_experimental_trace_buffer_v2_compaction(bool value) { experimental_trace_buffer_v2_compaction_ = value; _has_field_.set(50); }
+
const std::vector<TraceConfig_DataSource>& data_sources() const { return data_sources_; }
std::vector<TraceConfig_DataSource>* mutable_data_sources() { return &data_sources_; }
int data_sources_size() const;
@@ -8149,8 +8675,13 @@ class PERFETTO_EXPORT_COMPONENT TraceConfig : public ::protozero::CppMessageObj
const TraceAttributes& trace_attributes() const { return *trace_attributes_; }
TraceAttributes* mutable_trace_attributes() { _has_field_.set(48); return trace_attributes_.get(); }
+ bool has_persist_trace_across_reboots() const { return _has_field_[49]; }
+ bool persist_trace_across_reboots() const { return persist_trace_across_reboots_; }
+ void set_persist_trace_across_reboots(bool value) { persist_trace_across_reboots_ = value; _has_field_.set(49); }
+
private:
std::vector<TraceConfig_BufferConfig> buffers_;
+ bool experimental_trace_buffer_v2_compaction_{};
std::vector<TraceConfig_DataSource> data_sources_;
::protozero::CopyablePtr<TraceConfig_BuiltinDataSource> builtin_data_sources_;
uint32_t duration_ms_{};
@@ -8192,12 +8723,13 @@ class PERFETTO_EXPORT_COMPONENT TraceConfig : public ::protozero::CppMessageObj
TraceConfig_FFlushMode fflush_post_write_{};
bool trace_all_machines_{};
::protozero::CopyablePtr<TraceAttributes> trace_attributes_;
+ bool persist_trace_across_reboots_{};
// Allows to preserve unknown protobuf fields for compatibility
// with future versions of .proto files.
std::string unknown_fields_;
- std::bitset<49> _has_field_{};
+ std::bitset<51> _has_field_{};
};
@@ -10851,6 +11383,11 @@ struct DataSourceParams {
bool buffer_exhausted_policy_configurable = false;
bool supports_multiple_instances = true;
bool requires_callbacks_under_lock = true;
+ // Advertises that the data source supports tracing v2.
+ // This does NOT mean v2 will be used which is decided after the negotiation
+ // with the service, which might not support v2 or might decide not to use it.
+ // See DataSourceState.use_tracing_v2 for the active state.
+ bool supports_tracing_v2 = false;
};
struct DataSourceStaticState;
@@ -11334,6 +11871,7 @@ class ProcessDescriptor;
class ProcessStats;
class ProcessTree;
class ProfilePacket;
+class RecoveredTraceInfo;
class RemoteClockSync;
class SmapsPacket;
class StackSample;
@@ -11641,6 +12179,8 @@ class TracePacket_Decoder : public ::protozero::TypedProtoDecoder</*MAX_FIELD_ID
::protozero::ConstBytes user_list() const { return at<123>().as_bytes(); }
bool has_journald_event() const { return at<132>().valid(); }
::protozero::ConstBytes journald_event() const { return at<132>().as_bytes(); }
+ bool has_recovered_trace_info() const { return at<138>().valid(); }
+ ::protozero::ConstBytes recovered_trace_info() const { return at<138>().as_bytes(); }
bool has_for_testing() const { return at<900>().valid(); }
::protozero::ConstBytes for_testing() const { return at<900>().as_bytes(); }
bool has_trusted_uid() const { return at<3>().valid(); }
@@ -11755,6 +12295,7 @@ class TracePacket : public ::protozero::Message {
kCpuPerUidDataFieldNumber = 119,
kUserListFieldNumber = 123,
kJournaldEventFieldNumber = 132,
+ kRecoveredTraceInfoFieldNumber = 138,
kForTestingFieldNumber = 900,
kTrustedUidFieldNumber = 3,
kTrustedPacketSequenceIdFieldNumber = 10,
@@ -13036,6 +13577,20 @@ class TracePacket : public ::protozero::Message {
}
+ using FieldMetadata_RecoveredTraceInfo =
+ ::protozero::proto_utils::FieldMetadata<
+ 138,
+ ::protozero::proto_utils::RepetitionType::kNotRepeated,
+ ::protozero::proto_utils::ProtoSchemaType::kMessage,
+ RecoveredTraceInfo,
+ TracePacket>;
+
+ static constexpr FieldMetadata_RecoveredTraceInfo kRecoveredTraceInfo{};
+ template <typename T = RecoveredTraceInfo> T* set_recovered_trace_info() {
+ return BeginNestedMessage<T>(138);
+ }
+
+
using FieldMetadata_ForTesting =
::protozero::proto_utils::FieldMetadata<
900,
@@ -13714,6 +14269,15 @@ class DataSource : public DataSourceBase {
// This can be useful for splitting protos that might grow very large.
uint64_t written() { return tls_inst_->trace_writer->written(); }
+ // Returns the number of times the trace writer for the current thread and
+ // data source instance entered a mode in which it started dropping data
+ // (e.g. because the shared memory buffer was exhausted and the buffer
+ // exhausted policy is kDrop). Note that this does *not* necessarily
+ // correspond to the number of dropped packets, as multiple packets can be
+ // dropped on each entry into the drop mode. A non-zero (or increased)
+ // value indicates that some data written on this thread was lost.
+ uint64_t drop_count() { return tls_inst_->trace_writer->drop_count(); }
+
// Returns a RAII handle to access the data source instance, guaranteeing
// that it won't be deleted on another thread (because of trace stopping)
// while accessing it from within the Trace() lambda.
@@ -13870,6 +14434,7 @@ class DataSource : public DataSourceBase {
DerivedDataSource::GetDefaultBufferExhaustedPolicy();
params.buffer_exhausted_policy_configurable =
DerivedDataSource::kBufferExhaustedPolicyConfigurable;
+ params.supports_tracing_v2 = true;
return Helper::type().Register(
descriptor, factory, params, no_flush,
GetCreateTlsFn(
@@ -14675,9 +15240,20 @@ class RootMessage : public T {
RootMessage(RootMessage&&) = delete;
RootMessage& operator=(RootMessage&&) = delete;
- void Reset(ScatteredStreamWriter* writer) {
+ // Resets the root and its arena for output to |writer| with |encoding|.
+ // See Message::Encoding.
+ void Reset(ScatteredStreamWriter* writer, Message::Encoding encoding) {
root_arena_.Reset();
- Message::Reset(writer, &root_arena_);
+ Message::Reset(writer, &root_arena_, encoding);
+ }
+
+ // Convenience wrapper for the default length-delimited encoding.
+ //
+ // TODO(sashwinbalaji): Remove this overload once Chromium calls the one
+ // above, for example in:
+ // https://crsrc.org/c/services/tracing/public/cpp/perfetto/traced_value_proto_writer.cc
+ void Reset(ScatteredStreamWriter* writer) {
+ Reset(writer, Message::Encoding::kLengthDelimited);
}
private:
@@ -14765,6 +15341,10 @@ class PERFETTO_EXPORT_COMPONENT ScatteredHeapBuffer
// writer has written.
const std::vector<Slice>& GetSlices();
+ // Like GetSlices() but hands them over, leaving this empty. The writer is
+ // reset so it no longer points into the handed-over memory.
+ std::vector<Slice> TakeSlices();
+
// Stitch all the slices into a single contiguous buffer.
std::vector<uint8_t> StitchSlices();
@@ -14864,6 +15444,16 @@ class HeapBuffered {
return shb_.GetSlices();
}
+ // Finalizes the message and hands over its slices, leaving this empty and
+ // reusable.
+ std::vector<ScatteredHeapBuffer::Slice> TakeSlices() {
+ msg_.Finalize();
+ std::vector<ScatteredHeapBuffer::Slice> slices = shb_.TakeSlices();
+ msg_.Reset(&writer_);
+ PERFETTO_DCHECK(empty());
+ return slices;
+ }
+
void Reset() {
shb_.Reset();
writer_.Reset(protozero::ContiguousMemoryRange{});
@@ -21791,7 +22381,7 @@ class FlowImpl {
static PERFETTO_ALWAYS_INLINE inline FlowImpl ProcessScoped(
uint64_t flow_id,
const char* named_scope) {
- return Global(flow_id, named_scope);
+ return Global(flow_id ^ Track::process_uuid, named_scope);
}
// Same as above, but construct an id from a pointer.
@@ -29094,6 +29684,7 @@ class PERFETTO_EXPORT_COMPONENT SystemInfo : public ::protozero::CppMessageObj {
kAndroidBuildFingerprintFieldNumber = 2,
kAndroidDeviceManufacturerFieldNumber = 14,
kAndroidSocModelFieldNumber = 9,
+ kDeviceTreeCompatiblesFieldNumber = 18,
kAndroidGuestSocModelFieldNumber = 13,
kAndroidHardwareRevisionFieldNumber = 10,
kAndroidStorageModelFieldNumber = 11,
@@ -29139,6 +29730,13 @@ class PERFETTO_EXPORT_COMPONENT SystemInfo : public ::protozero::CppMessageObj {
const std::string& android_soc_model() const { return android_soc_model_; }
void set_android_soc_model(const std::string& value) { android_soc_model_ = value; _has_field_.set(9); }
+ const std::vector<std::string>& device_tree_compatibles() const { return device_tree_compatibles_; }
+ std::vector<std::string>* mutable_device_tree_compatibles() { return &device_tree_compatibles_; }
+ int device_tree_compatibles_size() const { return static_cast<int>(device_tree_compatibles_.size()); }
+ void clear_device_tree_compatibles() { device_tree_compatibles_.clear(); }
+ void add_device_tree_compatibles(std::string value) { device_tree_compatibles_.emplace_back(value); }
+ std::string* add_device_tree_compatibles() { device_tree_compatibles_.emplace_back(); return &device_tree_compatibles_.back(); }
+
bool has_android_guest_soc_model() const { return _has_field_[13]; }
const std::string& android_guest_soc_model() const { return android_guest_soc_model_; }
void set_android_guest_soc_model(const std::string& value) { android_guest_soc_model_ = value; _has_field_.set(13); }
@@ -29196,6 +29794,7 @@ class PERFETTO_EXPORT_COMPONENT SystemInfo : public ::protozero::CppMessageObj {
std::string android_build_fingerprint_{};
std::string android_device_manufacturer_{};
std::string android_soc_model_{};
+ std::vector<std::string> device_tree_compatibles_;
std::string android_guest_soc_model_{};
std::string android_hardware_revision_{};
std::string android_storage_model_{};
@@ -29214,7 +29813,7 @@ class PERFETTO_EXPORT_COMPONENT SystemInfo : public ::protozero::CppMessageObj {
// with future versions of .proto files.
std::string unknown_fields_;
- std::bitset<18> _has_field_{};
+ std::bitset<19> _has_field_{};
};
@@ -29727,12 +30326,15 @@ class PERFETTO_EXPORT_COMPONENT TraceStats_BufferStats : public ::protozero::Cpp
kChunksReadFieldNumber = 17,
kChunksCommittedOutOfOrderFieldNumber = 11,
kWriteWrapCountFieldNumber = 4,
+ kCompactionsFieldNumber = 23,
+ kCompactionsSkippedFieldNumber = 24,
kPatchesSucceededFieldNumber = 5,
kPatchesFailedFieldNumber = 6,
kReadaheadsSucceededFieldNumber = 7,
kReadaheadsFailedFieldNumber = 8,
kAbiViolationsFieldNumber = 9,
kTraceWriterPacketLossFieldNumber = 19,
+ kOversizedPacketsDroppedFieldNumber = 22,
};
TraceStats_BufferStats();
@@ -29805,6 +30407,14 @@ class PERFETTO_EXPORT_COMPONENT TraceStats_BufferStats : public ::protozero::Cpp
uint64_t write_wrap_count() const { return write_wrap_count_; }
void set_write_wrap_count(uint64_t value) { write_wrap_count_ = value; _has_field_.set(4); }
+ bool has_compactions() const { return _has_field_[23]; }
+ uint64_t compactions() const { return compactions_; }
+ void set_compactions(uint64_t value) { compactions_ = value; _has_field_.set(23); }
+
+ bool has_compactions_skipped() const { return _has_field_[24]; }
+ uint64_t compactions_skipped() const { return compactions_skipped_; }
+ void set_compactions_skipped(uint64_t value) { compactions_skipped_ = value; _has_field_.set(24); }
+
bool has_patches_succeeded() const { return _has_field_[5]; }
uint64_t patches_succeeded() const { return patches_succeeded_; }
void set_patches_succeeded(uint64_t value) { patches_succeeded_ = value; _has_field_.set(5); }
@@ -29829,6 +30439,10 @@ class PERFETTO_EXPORT_COMPONENT TraceStats_BufferStats : public ::protozero::Cpp
uint64_t trace_writer_packet_loss() const { return trace_writer_packet_loss_; }
void set_trace_writer_packet_loss(uint64_t value) { trace_writer_packet_loss_ = value; _has_field_.set(19); }
+ bool has_oversized_packets_dropped() const { return _has_field_[22]; }
+ uint64_t oversized_packets_dropped() const { return oversized_packets_dropped_; }
+ void set_oversized_packets_dropped(uint64_t value) { oversized_packets_dropped_ = value; _has_field_.set(22); }
+
private:
uint64_t buffer_size_{};
uint64_t bytes_written_{};
@@ -29844,18 +30458,21 @@ class PERFETTO_EXPORT_COMPONENT TraceStats_BufferStats : public ::protozero::Cpp
uint64_t chunks_read_{};
uint64_t chunks_committed_out_of_order_{};
uint64_t write_wrap_count_{};
+ uint64_t compactions_{};
+ uint64_t compactions_skipped_{};
uint64_t patches_succeeded_{};
uint64_t patches_failed_{};
uint64_t readaheads_succeeded_{};
uint64_t readaheads_failed_{};
uint64_t abi_violations_{};
uint64_t trace_writer_packet_loss_{};
+ uint64_t oversized_packets_dropped_{};
// Allows to preserve unknown protobuf fields for compatibility
// with future versions of .proto files.
std::string unknown_fields_;
- std::bitset<21> _has_field_{};
+ std::bitset<25> _has_field_{};
};
} // namespace perfetto
@@ -29977,17 +30594,7 @@ class TracingServiceState;
class TracingServiceState_TracingSession;
class TracingServiceState_DataSource;
class DataSourceDescriptor;
-class VmProgram;
-class VmInstruction;
-class VmOpDel;
-class VmOpSet;
-class VmOpMerge;
-class VmOpRegLoad;
-class VmOpSelect;
-class VmOpSelect_PathComponent;
class TracingServiceState_Producer;
-enum VmInstruction_AbortLevel : int;
-enum VmCursorEnum : int;
} // namespace perfetto
} // namespace protos
} // namespace gen
@@ -31993,6 +32600,10 @@ class DataSourceDescriptor : public ::protozero::Message {
return BeginNestedMessage<T>(10);
}
+ void set_protovm_program_raw(const std::string& raw) {
+ return AppendBytes(10, raw.data(), raw.size());
+ }
+
using FieldMetadata_GpuCounterDescriptor =
::protozero::proto_utils::FieldMetadata<
@@ -36896,7 +37507,7 @@ namespace perfetto {
namespace protos {
namespace pbzero {
-class SystemInfo_Decoder : public ::protozero::TypedProtoDecoder</*MAX_FIELD_ID=*/17> {
+class SystemInfo_Decoder : public ::protozero::TypedProtoDecoder</*MAX_FIELD_ID=*/18> {
public:
SystemInfo_Decoder(const uint8_t* data, size_t len) : TypedProtoDecoder(data, len) {}
explicit SystemInfo_Decoder(const std::string& raw) : TypedProtoDecoder(reinterpret_cast<const uint8_t*>(raw.data()), raw.size()) {}
@@ -36909,6 +37520,8 @@ class SystemInfo_Decoder : public ::protozero::TypedProtoDecoder</*MAX_FIELD_ID=
::protozero::ConstChars android_device_manufacturer() const { return at<14>().as_string(); }
bool has_android_soc_model() const { return at<9>().valid(); }
::protozero::ConstChars android_soc_model() const { return at<9>().as_string(); }
+ bool has_device_tree_compatibles() const { return at<18>().valid(); }
+ ::protozero::RepeatedFieldIterator<::protozero::ConstChars> device_tree_compatibles() const { return GetRepeated<::protozero::ConstChars>(18); }
bool has_android_guest_soc_model() const { return at<13>().valid(); }
::protozero::ConstChars android_guest_soc_model() const { return at<13>().as_string(); }
bool has_android_hardware_revision() const { return at<10>().valid(); }
@@ -36945,6 +37558,7 @@ class SystemInfo : public ::protozero::Message {
kAndroidBuildFingerprintFieldNumber = 2,
kAndroidDeviceManufacturerFieldNumber = 14,
kAndroidSocModelFieldNumber = 9,
+ kDeviceTreeCompatiblesFieldNumber = 18,
kAndroidGuestSocModelFieldNumber = 13,
kAndroidHardwareRevisionFieldNumber = 10,
kAndroidStorageModelFieldNumber = 11,
@@ -37048,6 +37662,30 @@ class SystemInfo : public ::protozero::Message {
::Append(*this, field_id, value);
}
+ using FieldMetadata_DeviceTreeCompatibles =
+ ::protozero::proto_utils::FieldMetadata<
+ 18,
+ ::protozero::proto_utils::RepetitionType::kRepeatedNotPacked,
+ ::protozero::proto_utils::ProtoSchemaType::kString,
+ std::string,
+ SystemInfo>;
+
+ static constexpr FieldMetadata_DeviceTreeCompatibles kDeviceTreeCompatibles{};
+ void add_device_tree_compatibles(const char* data, size_t size) {
+ AppendBytes(FieldMetadata_DeviceTreeCompatibles::kFieldId, data, size);
+ }
+ void add_device_tree_compatibles(::protozero::ConstChars chars) {
+ AppendBytes(FieldMetadata_DeviceTreeCompatibles::kFieldId, chars.data, chars.size);
+ }
+ void add_device_tree_compatibles(std::string value) {
+ static constexpr uint32_t field_id = FieldMetadata_DeviceTreeCompatibles::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_AndroidGuestSocModel =
::protozero::proto_utils::FieldMetadata<
13,
@@ -38277,7 +38915,7 @@ class TraceStats_WriterStats : public ::protozero::Message {
}
};
-class TraceStats_BufferStats_Decoder : public ::protozero::TypedProtoDecoder</*MAX_FIELD_ID=*/20> {
+class TraceStats_BufferStats_Decoder : public ::protozero::TypedProtoDecoder</*MAX_FIELD_ID=*/24> {
public:
TraceStats_BufferStats_Decoder(const uint8_t* data, size_t len) : TypedProtoDecoder(data, len) {}
explicit TraceStats_BufferStats_Decoder(const std::string& raw) : TypedProtoDecoder(reinterpret_cast<const uint8_t*>(raw.data()), raw.size()) {}
@@ -38310,6 +38948,10 @@ class TraceStats_BufferStats_Decoder : public ::protozero::TypedProtoDecoder</*M
uint64_t chunks_committed_out_of_order() const { return at<11>().as_uint64(); }
bool has_write_wrap_count() const { return at<4>().valid(); }
uint64_t write_wrap_count() const { return at<4>().as_uint64(); }
+ bool has_compactions() const { return at<23>().valid(); }
+ uint64_t compactions() const { return at<23>().as_uint64(); }
+ bool has_compactions_skipped() const { return at<24>().valid(); }
+ uint64_t compactions_skipped() const { return at<24>().as_uint64(); }
bool has_patches_succeeded() const { return at<5>().valid(); }
uint64_t patches_succeeded() const { return at<5>().as_uint64(); }
bool has_patches_failed() const { return at<6>().valid(); }
@@ -38322,6 +38964,8 @@ class TraceStats_BufferStats_Decoder : public ::protozero::TypedProtoDecoder</*M
uint64_t abi_violations() const { return at<9>().as_uint64(); }
bool has_trace_writer_packet_loss() const { return at<19>().valid(); }
uint64_t trace_writer_packet_loss() const { return at<19>().as_uint64(); }
+ bool has_oversized_packets_dropped() const { return at<22>().valid(); }
+ uint64_t oversized_packets_dropped() const { return at<22>().as_uint64(); }
};
class TraceStats_BufferStats : public ::protozero::Message {
@@ -38342,12 +38986,15 @@ class TraceStats_BufferStats : public ::protozero::Message {
kChunksReadFieldNumber = 17,
kChunksCommittedOutOfOrderFieldNumber = 11,
kWriteWrapCountFieldNumber = 4,
+ kCompactionsFieldNumber = 23,
+ kCompactionsSkippedFieldNumber = 24,
kPatchesSucceededFieldNumber = 5,
kPatchesFailedFieldNumber = 6,
kReadaheadsSucceededFieldNumber = 7,
kReadaheadsFailedFieldNumber = 8,
kAbiViolationsFieldNumber = 9,
kTraceWriterPacketLossFieldNumber = 19,
+ kOversizedPacketsDroppedFieldNumber = 22,
};
static constexpr const char* GetName() { return ".perfetto.protos.TraceStats.BufferStats"; }
@@ -38604,6 +39251,42 @@ class TraceStats_BufferStats : public ::protozero::Message {
::Append(*this, field_id, value);
}
+ using FieldMetadata_Compactions =
+ ::protozero::proto_utils::FieldMetadata<
+ 23,
+ ::protozero::proto_utils::RepetitionType::kNotRepeated,
+ ::protozero::proto_utils::ProtoSchemaType::kUint64,
+ uint64_t,
+ TraceStats_BufferStats>;
+
+ static constexpr FieldMetadata_Compactions kCompactions{};
+ void set_compactions(uint64_t value) {
+ static constexpr uint32_t field_id = FieldMetadata_Compactions::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_CompactionsSkipped =
+ ::protozero::proto_utils::FieldMetadata<
+ 24,
+ ::protozero::proto_utils::RepetitionType::kNotRepeated,
+ ::protozero::proto_utils::ProtoSchemaType::kUint64,
+ uint64_t,
+ TraceStats_BufferStats>;
+
+ static constexpr FieldMetadata_CompactionsSkipped kCompactionsSkipped{};
+ void set_compactions_skipped(uint64_t value) {
+ static constexpr uint32_t field_id = FieldMetadata_CompactionsSkipped::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_PatchesSucceeded =
::protozero::proto_utils::FieldMetadata<
5,
@@ -38711,6 +39394,24 @@ class TraceStats_BufferStats : public ::protozero::Message {
::protozero::proto_utils::ProtoSchemaType::kUint64>
::Append(*this, field_id, value);
}
+
+ using FieldMetadata_OversizedPacketsDropped =
+ ::protozero::proto_utils::FieldMetadata<
+ 22,
+ ::protozero::proto_utils::RepetitionType::kNotRepeated,
+ ::protozero::proto_utils::ProtoSchemaType::kUint64,
+ uint64_t,
+ TraceStats_BufferStats>;
+
+ static constexpr FieldMetadata_OversizedPacketsDropped kOversizedPacketsDropped{};
+ void set_oversized_packets_dropped(uint64_t value) {
+ static constexpr uint32_t field_id = FieldMetadata_OversizedPacketsDropped::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.
@@ -40262,6 +40963,76 @@ class PERFETTO_EXPORT_COMPONENT AndroidPolledStateConfig : public ::protozero::C
} // namespace gen
#endif // PERFETTO_PROTOS_PROTOS_PERFETTO_CONFIG_ANDROID_ANDROID_POLLED_STATE_CONFIG_PROTO_CPP_H_
+// gen_amalgamated begin header: gen/protos/perfetto/config/android/android_process_state_config.gen.h
+// DO NOT EDIT. Autogenerated by Perfetto cppgen_plugin
+#ifndef PERFETTO_PROTOS_PROTOS_PERFETTO_CONFIG_ANDROID_ANDROID_PROCESS_STATE_CONFIG_PROTO_CPP_H_
+#define PERFETTO_PROTOS_PROTOS_PERFETTO_CONFIG_ANDROID_ANDROID_PROCESS_STATE_CONFIG_PROTO_CPP_H_
+
+#include <stdint.h>
+#include <bitset>
+#include <vector>
+#include <string>
+#include <type_traits>
+
+// gen_amalgamated expanded: #include "perfetto/protozero/cpp_message_obj.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/copyable_ptr.h"
+// gen_amalgamated expanded: #include "perfetto/base/export.h"
+
+namespace perfetto {
+namespace protos {
+namespace gen {
+class AndroidProcessStateConfig;
+} // namespace perfetto
+} // namespace protos
+} // namespace gen
+
+namespace protozero {
+class Message;
+} // namespace protozero
+
+namespace perfetto {
+namespace protos {
+namespace gen {
+
+class PERFETTO_EXPORT_COMPONENT AndroidProcessStateConfig : public ::protozero::CppMessageObj {
+ public:
+ enum FieldNumbers {
+ kDumpProcessMetadataFieldNumber = 1,
+ };
+
+ AndroidProcessStateConfig();
+ ~AndroidProcessStateConfig() override;
+ AndroidProcessStateConfig(AndroidProcessStateConfig&&) noexcept;
+ AndroidProcessStateConfig& operator=(AndroidProcessStateConfig&&);
+ AndroidProcessStateConfig(const AndroidProcessStateConfig&);
+ AndroidProcessStateConfig& operator=(const AndroidProcessStateConfig&);
+ bool operator==(const AndroidProcessStateConfig&) const;
+ bool operator!=(const AndroidProcessStateConfig& other) const { return !(*this == other); }
+
+ bool ParseFromArray(const void*, size_t) override;
+ std::string SerializeAsString() const override;
+ std::vector<uint8_t> SerializeAsArray() const override;
+ void Serialize(::protozero::Message*) const;
+
+ bool has_dump_process_metadata() const { return _has_field_[1]; }
+ bool dump_process_metadata() const { return dump_process_metadata_; }
+ void set_dump_process_metadata(bool value) { dump_process_metadata_ = value; _has_field_.set(1); }
+
+ private:
+ bool dump_process_metadata_{};
+
+ // Allows to preserve unknown protobuf fields for compatibility
+ // with future versions of .proto files.
+ std::string unknown_fields_;
+
+ std::bitset<2> _has_field_{};
+};
+
+} // namespace perfetto
+} // namespace protos
+} // namespace gen
+
+#endif // PERFETTO_PROTOS_PROTOS_PERFETTO_CONFIG_ANDROID_ANDROID_PROCESS_STATE_CONFIG_PROTO_CPP_H_
// gen_amalgamated begin header: gen/protos/perfetto/config/android/android_sdk_sysprop_guard_config.gen.h
// DO NOT EDIT. Autogenerated by Perfetto cppgen_plugin
#ifndef PERFETTO_PROTOS_PROTOS_PERFETTO_CONFIG_ANDROID_ANDROID_SDK_SYSPROP_GUARD_CONFIG_PROTO_CPP_H_
@@ -42612,6 +43383,7 @@ class PERFETTO_EXPORT_COMPONENT GpuRenderStagesConfig : public ::protozero::CppM
kFullLoadstoreFieldNumber = 1,
kLowOverheadFieldNumber = 2,
kTraceMetricsFieldNumber = 3,
+ kDrawcallStagesFieldNumber = 4,
};
GpuRenderStagesConfig();
@@ -42643,16 +43415,21 @@ class PERFETTO_EXPORT_COMPONENT GpuRenderStagesConfig : public ::protozero::CppM
void add_trace_metrics(std::string value) { trace_metrics_.emplace_back(value); }
std::string* add_trace_metrics() { trace_metrics_.emplace_back(); return &trace_metrics_.back(); }
+ bool has_drawcall_stages() const { return _has_field_[4]; }
+ bool drawcall_stages() const { return drawcall_stages_; }
+ void set_drawcall_stages(bool value) { drawcall_stages_ = value; _has_field_.set(4); }
+
private:
bool full_loadstore_{};
bool low_overhead_{};
std::vector<std::string> trace_metrics_;
+ bool drawcall_stages_{};
// Allows to preserve unknown protobuf fields for compatibility
// with future versions of .proto files.
std::string unknown_fields_;
- std::bitset<4> _has_field_{};
+ std::bitset<5> _has_field_{};
};
} // namespace perfetto
@@ -44262,6 +45039,9 @@ namespace protos {
namespace gen {
class RedactionRule;
class SmapsConfig;
+class ProcessSmapsConfig;
+class ProcessSmapsConfig_Scope;
+class ProcessSmapsConfig_Scope_UidRange;
enum RedactionRule_MatchMode : int;
enum SmapsConfig_VmaField : int;
} // namespace perfetto
@@ -44436,6 +45216,154 @@ class PERFETTO_EXPORT_COMPONENT SmapsConfig : public ::protozero::CppMessageObj
std::bitset<4> _has_field_{};
};
+
+class PERFETTO_EXPORT_COMPONENT ProcessSmapsConfig : public ::protozero::CppMessageObj {
+ public:
+ using Scope = ProcessSmapsConfig_Scope;
+ enum FieldNumbers {
+ kSmapsConfigFieldNumber = 1,
+ kScopeFieldNumber = 2,
+ kReadPeriodMsFieldNumber = 3,
+ kMaxProcessesPerPeriodFieldNumber = 4,
+ };
+
+ ProcessSmapsConfig();
+ ~ProcessSmapsConfig() override;
+ ProcessSmapsConfig(ProcessSmapsConfig&&) noexcept;
+ ProcessSmapsConfig& operator=(ProcessSmapsConfig&&);
+ ProcessSmapsConfig(const ProcessSmapsConfig&);
+ ProcessSmapsConfig& operator=(const ProcessSmapsConfig&);
+ bool operator==(const ProcessSmapsConfig&) const;
+ bool operator!=(const ProcessSmapsConfig& other) const { return !(*this == other); }
+
+ bool ParseFromArray(const void*, size_t) override;
+ std::string SerializeAsString() const override;
+ std::vector<uint8_t> SerializeAsArray() const override;
+ void Serialize(::protozero::Message*) const;
+
+ bool has_smaps_config() const { return _has_field_[1]; }
+ const SmapsConfig& smaps_config() const { return *smaps_config_; }
+ SmapsConfig* mutable_smaps_config() { _has_field_.set(1); return smaps_config_.get(); }
+
+ bool has_scope() const { return _has_field_[2]; }
+ const ProcessSmapsConfig_Scope& scope() const { return *scope_; }
+ ProcessSmapsConfig_Scope* mutable_scope() { _has_field_.set(2); return scope_.get(); }
+
+ bool has_read_period_ms() const { return _has_field_[3]; }
+ uint32_t read_period_ms() const { return read_period_ms_; }
+ void set_read_period_ms(uint32_t value) { read_period_ms_ = value; _has_field_.set(3); }
+
+ bool has_max_processes_per_period() const { return _has_field_[4]; }
+ uint32_t max_processes_per_period() const { return max_processes_per_period_; }
+ void set_max_processes_per_period(uint32_t value) { max_processes_per_period_ = value; _has_field_.set(4); }
+
+ private:
+ ::protozero::CopyablePtr<SmapsConfig> smaps_config_;
+ ::protozero::CopyablePtr<ProcessSmapsConfig_Scope> scope_;
+ uint32_t read_period_ms_{};
+ uint32_t max_processes_per_period_{};
+
+ // Allows to preserve unknown protobuf fields for compatibility
+ // with future versions of .proto files.
+ std::string unknown_fields_;
+
+ std::bitset<5> _has_field_{};
+};
+
+
+class PERFETTO_EXPORT_COMPONENT ProcessSmapsConfig_Scope : public ::protozero::CppMessageObj {
+ public:
+ using UidRange = ProcessSmapsConfig_Scope_UidRange;
+ enum FieldNumbers {
+ kTargetCmdlineFieldNumber = 1,
+ kTargetUidFieldNumber = 2,
+ };
+
+ ProcessSmapsConfig_Scope();
+ ~ProcessSmapsConfig_Scope() override;
+ ProcessSmapsConfig_Scope(ProcessSmapsConfig_Scope&&) noexcept;
+ ProcessSmapsConfig_Scope& operator=(ProcessSmapsConfig_Scope&&);
+ ProcessSmapsConfig_Scope(const ProcessSmapsConfig_Scope&);
+ ProcessSmapsConfig_Scope& operator=(const ProcessSmapsConfig_Scope&);
+ bool operator==(const ProcessSmapsConfig_Scope&) const;
+ bool operator!=(const ProcessSmapsConfig_Scope& other) const { return !(*this == other); }
+
+ bool ParseFromArray(const void*, size_t) override;
+ std::string SerializeAsString() const override;
+ std::vector<uint8_t> SerializeAsArray() const override;
+ void Serialize(::protozero::Message*) const;
+
+ const std::vector<std::string>& target_cmdline() const { return target_cmdline_; }
+ std::vector<std::string>* mutable_target_cmdline() { return &target_cmdline_; }
+ int target_cmdline_size() const { return static_cast<int>(target_cmdline_.size()); }
+ void clear_target_cmdline() { target_cmdline_.clear(); }
+ void add_target_cmdline(std::string value) { target_cmdline_.emplace_back(value); }
+ std::string* add_target_cmdline() { target_cmdline_.emplace_back(); return &target_cmdline_.back(); }
+
+ const std::vector<ProcessSmapsConfig_Scope_UidRange>& target_uid() const { return target_uid_; }
+ std::vector<ProcessSmapsConfig_Scope_UidRange>* mutable_target_uid() { return &target_uid_; }
+ int target_uid_size() const;
+ void clear_target_uid();
+ ProcessSmapsConfig_Scope_UidRange* add_target_uid();
+
+ private:
+ std::vector<std::string> target_cmdline_;
+ std::vector<ProcessSmapsConfig_Scope_UidRange> target_uid_;
+
+ // Allows to preserve unknown protobuf fields for compatibility
+ // with future versions of .proto files.
+ std::string unknown_fields_;
+
+ std::bitset<3> _has_field_{};
+};
+
+
+class PERFETTO_EXPORT_COMPONENT ProcessSmapsConfig_Scope_UidRange : public ::protozero::CppMessageObj {
+ public:
+ enum FieldNumbers {
+ kMinUidFieldNumber = 1,
+ kMaxUidFieldNumber = 2,
+ kAndroidMatchAcrossProfilesFieldNumber = 3,
+ };
+
+ ProcessSmapsConfig_Scope_UidRange();
+ ~ProcessSmapsConfig_Scope_UidRange() override;
+ ProcessSmapsConfig_Scope_UidRange(ProcessSmapsConfig_Scope_UidRange&&) noexcept;
+ ProcessSmapsConfig_Scope_UidRange& operator=(ProcessSmapsConfig_Scope_UidRange&&);
+ ProcessSmapsConfig_Scope_UidRange(const ProcessSmapsConfig_Scope_UidRange&);
+ ProcessSmapsConfig_Scope_UidRange& operator=(const ProcessSmapsConfig_Scope_UidRange&);
+ bool operator==(const ProcessSmapsConfig_Scope_UidRange&) const;
+ bool operator!=(const ProcessSmapsConfig_Scope_UidRange& other) const { return !(*this == other); }
+
+ bool ParseFromArray(const void*, size_t) override;
+ std::string SerializeAsString() const override;
+ std::vector<uint8_t> SerializeAsArray() const override;
+ void Serialize(::protozero::Message*) const;
+
+ bool has_min_uid() const { return _has_field_[1]; }
+ uint32_t min_uid() const { return min_uid_; }
+ void set_min_uid(uint32_t value) { min_uid_ = value; _has_field_.set(1); }
+
+ bool has_max_uid() const { return _has_field_[2]; }
+ uint32_t max_uid() const { return max_uid_; }
+ void set_max_uid(uint32_t value) { max_uid_ = value; _has_field_.set(2); }
+
+ bool has_android_match_across_profiles() const { return _has_field_[3]; }
+ bool android_match_across_profiles() const { return android_match_across_profiles_; }
+ void set_android_match_across_profiles(bool value) { android_match_across_profiles_ = value; _has_field_.set(3); }
+
+ private:
+ uint32_t min_uid_{};
+ uint32_t max_uid_{};
+ bool android_match_across_profiles_{};
+
+ // Allows to preserve unknown protobuf fields for compatibility
+ // with future versions of .proto files.
+ std::string unknown_fields_;
+
+ std::bitset<4> _has_field_{};
+};
+
} // namespace perfetto
} // namespace protos
} // namespace gen
@@ -46499,6 +47427,82 @@ class PERFETTO_EXPORT_COMPONENT ChromiumHistogramSamplesConfig_HistogramSample :
} // namespace gen
#endif // PERFETTO_PROTOS_PROTOS_PERFETTO_CONFIG_CHROME_HISTOGRAM_SAMPLES_PROTO_CPP_H_
+// gen_amalgamated begin header: gen/protos/perfetto/config/chrome/sampling_heap_profiler.gen.h
+// DO NOT EDIT. Autogenerated by Perfetto cppgen_plugin
+#ifndef PERFETTO_PROTOS_PROTOS_PERFETTO_CONFIG_CHROME_SAMPLING_HEAP_PROFILER_PROTO_CPP_H_
+#define PERFETTO_PROTOS_PROTOS_PERFETTO_CONFIG_CHROME_SAMPLING_HEAP_PROFILER_PROTO_CPP_H_
+
+#include <stdint.h>
+#include <bitset>
+#include <vector>
+#include <string>
+#include <type_traits>
+
+// gen_amalgamated expanded: #include "perfetto/protozero/cpp_message_obj.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/copyable_ptr.h"
+// gen_amalgamated expanded: #include "perfetto/base/export.h"
+
+namespace perfetto {
+namespace protos {
+namespace gen {
+class ChromiumSamplingHeapProfilerConfig;
+} // namespace perfetto
+} // namespace protos
+} // namespace gen
+
+namespace protozero {
+class Message;
+} // namespace protozero
+
+namespace perfetto {
+namespace protos {
+namespace gen {
+
+class PERFETTO_EXPORT_COMPONENT ChromiumSamplingHeapProfilerConfig : public ::protozero::CppMessageObj {
+ public:
+ enum FieldNumbers {
+ kSamplingIntervalBytesFieldNumber = 1,
+ kSamplingIntervalMsFieldNumber = 2,
+ };
+
+ ChromiumSamplingHeapProfilerConfig();
+ ~ChromiumSamplingHeapProfilerConfig() override;
+ ChromiumSamplingHeapProfilerConfig(ChromiumSamplingHeapProfilerConfig&&) noexcept;
+ ChromiumSamplingHeapProfilerConfig& operator=(ChromiumSamplingHeapProfilerConfig&&);
+ ChromiumSamplingHeapProfilerConfig(const ChromiumSamplingHeapProfilerConfig&);
+ ChromiumSamplingHeapProfilerConfig& operator=(const ChromiumSamplingHeapProfilerConfig&);
+ bool operator==(const ChromiumSamplingHeapProfilerConfig&) const;
+ bool operator!=(const ChromiumSamplingHeapProfilerConfig& other) const { return !(*this == other); }
+
+ bool ParseFromArray(const void*, size_t) override;
+ std::string SerializeAsString() const override;
+ std::vector<uint8_t> SerializeAsArray() const override;
+ void Serialize(::protozero::Message*) const;
+
+ bool has_sampling_interval_bytes() const { return _has_field_[1]; }
+ uint64_t sampling_interval_bytes() const { return sampling_interval_bytes_; }
+ void set_sampling_interval_bytes(uint64_t value) { sampling_interval_bytes_ = value; _has_field_.set(1); }
+
+ bool has_sampling_interval_ms() const { return _has_field_[2]; }
+ uint32_t sampling_interval_ms() const { return sampling_interval_ms_; }
+ void set_sampling_interval_ms(uint32_t value) { sampling_interval_ms_ = value; _has_field_.set(2); }
+
+ private:
+ uint64_t sampling_interval_bytes_{};
+ uint32_t sampling_interval_ms_{};
+
+ // Allows to preserve unknown protobuf fields for compatibility
+ // with future versions of .proto files.
+ std::string unknown_fields_;
+
+ std::bitset<3> _has_field_{};
+};
+
+} // namespace perfetto
+} // namespace protos
+} // namespace gen
+
+#endif // PERFETTO_PROTOS_PROTOS_PERFETTO_CONFIG_CHROME_SAMPLING_HEAP_PROFILER_PROTO_CPP_H_
// gen_amalgamated begin header: gen/protos/perfetto/config/chrome/scenario_config.gen.h
// DO NOT EDIT. Autogenerated by Perfetto cppgen_plugin
#ifndef PERFETTO_PROTOS_PROTOS_PERFETTO_CONFIG_CHROME_SCENARIO_CONFIG_PROTO_CPP_H_
@@ -46553,6 +47557,8 @@ class InterceptorConfig;
class ConsoleConfig;
class ChromeConfig;
class SystemInfoConfig;
+class DataSourceConfig_ExperimentalTracingV2Config;
+class DataSourceConfig_ExperimentalTracingV2Config_ChunkSizeOption;
class ProtoVmConfig;
class TraceConfig_BufferConfig;
enum TraceConfig_LockdownModeOperation : int;
@@ -46974,6 +47980,76 @@ class PERFETTO_EXPORT_COMPONENT NestedScenarioConfig : public ::protozero::CppMe
} // namespace gen
#endif // PERFETTO_PROTOS_PROTOS_PERFETTO_CONFIG_CHROME_SCENARIO_CONFIG_PROTO_CPP_H_
+// gen_amalgamated begin header: gen/protos/perfetto/config/chrome/stack_sampling_profiler.gen.h
+// DO NOT EDIT. Autogenerated by Perfetto cppgen_plugin
+#ifndef PERFETTO_PROTOS_PROTOS_PERFETTO_CONFIG_CHROME_STACK_SAMPLING_PROFILER_PROTO_CPP_H_
+#define PERFETTO_PROTOS_PROTOS_PERFETTO_CONFIG_CHROME_STACK_SAMPLING_PROFILER_PROTO_CPP_H_
+
+#include <stdint.h>
+#include <bitset>
+#include <vector>
+#include <string>
+#include <type_traits>
+
+// gen_amalgamated expanded: #include "perfetto/protozero/cpp_message_obj.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/copyable_ptr.h"
+// gen_amalgamated expanded: #include "perfetto/base/export.h"
+
+namespace perfetto {
+namespace protos {
+namespace gen {
+class ChromiumStackSamplingProfilerConfig;
+} // namespace perfetto
+} // namespace protos
+} // namespace gen
+
+namespace protozero {
+class Message;
+} // namespace protozero
+
+namespace perfetto {
+namespace protos {
+namespace gen {
+
+class PERFETTO_EXPORT_COMPONENT ChromiumStackSamplingProfilerConfig : public ::protozero::CppMessageObj {
+ public:
+ enum FieldNumbers {
+ kSamplingIntervalMsFieldNumber = 1,
+ };
+
+ ChromiumStackSamplingProfilerConfig();
+ ~ChromiumStackSamplingProfilerConfig() override;
+ ChromiumStackSamplingProfilerConfig(ChromiumStackSamplingProfilerConfig&&) noexcept;
+ ChromiumStackSamplingProfilerConfig& operator=(ChromiumStackSamplingProfilerConfig&&);
+ ChromiumStackSamplingProfilerConfig(const ChromiumStackSamplingProfilerConfig&);
+ ChromiumStackSamplingProfilerConfig& operator=(const ChromiumStackSamplingProfilerConfig&);
+ bool operator==(const ChromiumStackSamplingProfilerConfig&) const;
+ bool operator!=(const ChromiumStackSamplingProfilerConfig& other) const { return !(*this == other); }
+
+ bool ParseFromArray(const void*, size_t) override;
+ std::string SerializeAsString() const override;
+ std::vector<uint8_t> SerializeAsArray() const override;
+ void Serialize(::protozero::Message*) const;
+
+ bool has_sampling_interval_ms() const { return _has_field_[1]; }
+ uint32_t sampling_interval_ms() const { return sampling_interval_ms_; }
+ void set_sampling_interval_ms(uint32_t value) { sampling_interval_ms_ = value; _has_field_.set(1); }
+
+ private:
+ uint32_t sampling_interval_ms_{};
+
+ // Allows to preserve unknown protobuf fields for compatibility
+ // with future versions of .proto files.
+ std::string unknown_fields_;
+
+ std::bitset<2> _has_field_{};
+};
+
+} // namespace perfetto
+} // namespace protos
+} // namespace gen
+
+#endif // PERFETTO_PROTOS_PROTOS_PERFETTO_CONFIG_CHROME_STACK_SAMPLING_PROFILER_PROTO_CPP_H_
// gen_amalgamated begin header: gen/protos/perfetto/config/chrome/system_metrics.gen.h
// DO NOT EDIT. Autogenerated by Perfetto cppgen_plugin
#ifndef PERFETTO_PROTOS_PROTOS_PERFETTO_CONFIG_CHROME_SYSTEM_METRICS_PROTO_CPP_H_
@@ -47139,6 +48215,7 @@ namespace perfetto {
namespace protos {
namespace gen {
class EtwConfig;
+class EtwConfig_DebugId;
enum EtwConfig_KernelFlag : int;
} // namespace perfetto
} // namespace protos
@@ -47158,6 +48235,7 @@ enum EtwConfig_KernelFlag : int {
class PERFETTO_EXPORT_COMPONENT EtwConfig : public ::protozero::CppMessageObj {
public:
+ using DebugId = EtwConfig_DebugId;
using KernelFlag = EtwConfig_KernelFlag;
static constexpr auto CSWITCH = EtwConfig_KernelFlag_CSWITCH;
static constexpr auto DISPATCHER = EtwConfig_KernelFlag_DISPATCHER;
@@ -47171,6 +48249,7 @@ class PERFETTO_EXPORT_COMPONENT EtwConfig : public ::protozero::CppMessageObj {
kStackSamplingEventsFieldNumber = 5,
kDiskProviderEventsFieldNumber = 6,
kSystemIoProviderEventsFieldNumber = 7,
+ kStackSamplingDebugIdsFieldNumber = 8,
};
EtwConfig();
@@ -47236,6 +48315,12 @@ class PERFETTO_EXPORT_COMPONENT EtwConfig : public ::protozero::CppMessageObj {
void add_system_io_provider_events(std::string value) { system_io_provider_events_.emplace_back(value); }
std::string* add_system_io_provider_events() { system_io_provider_events_.emplace_back(); return &system_io_provider_events_.back(); }
+ const std::vector<EtwConfig_DebugId>& stack_sampling_debug_ids() const { return stack_sampling_debug_ids_; }
+ std::vector<EtwConfig_DebugId>* mutable_stack_sampling_debug_ids() { return &stack_sampling_debug_ids_; }
+ int stack_sampling_debug_ids_size() const;
+ void clear_stack_sampling_debug_ids();
+ EtwConfig_DebugId* add_stack_sampling_debug_ids();
+
private:
std::vector<EtwConfig_KernelFlag> kernel_flags_;
std::vector<std::string> scheduler_provider_events_;
@@ -47244,12 +48329,54 @@ class PERFETTO_EXPORT_COMPONENT EtwConfig : public ::protozero::CppMessageObj {
std::vector<std::string> stack_sampling_events_;
std::vector<std::string> disk_provider_events_;
std::vector<std::string> system_io_provider_events_;
+ std::vector<EtwConfig_DebugId> stack_sampling_debug_ids_;
// Allows to preserve unknown protobuf fields for compatibility
// with future versions of .proto files.
std::string unknown_fields_;
- std::bitset<8> _has_field_{};
+ std::bitset<9> _has_field_{};
+};
+
+
+class PERFETTO_EXPORT_COMPONENT EtwConfig_DebugId : public ::protozero::CppMessageObj {
+ public:
+ enum FieldNumbers {
+ kPathFieldNumber = 1,
+ kDebugIdFieldNumber = 2,
+ };
+
+ EtwConfig_DebugId();
+ ~EtwConfig_DebugId() override;
+ EtwConfig_DebugId(EtwConfig_DebugId&&) noexcept;
+ EtwConfig_DebugId& operator=(EtwConfig_DebugId&&);
+ EtwConfig_DebugId(const EtwConfig_DebugId&);
+ EtwConfig_DebugId& operator=(const EtwConfig_DebugId&);
+ bool operator==(const EtwConfig_DebugId&) const;
+ bool operator!=(const EtwConfig_DebugId& other) const { return !(*this == other); }
+
+ bool ParseFromArray(const void*, size_t) override;
+ std::string SerializeAsString() const override;
+ std::vector<uint8_t> SerializeAsArray() const override;
+ void Serialize(::protozero::Message*) const;
+
+ bool has_path() const { return _has_field_[1]; }
+ const std::string& path() const { return path_; }
+ void set_path(const std::string& value) { path_ = value; _has_field_.set(1); }
+
+ bool has_debug_id() const { return _has_field_[2]; }
+ const std::string& debug_id() const { return debug_id_; }
+ void set_debug_id(const std::string& value) { debug_id_ = value; _has_field_.set(2); }
+
+ private:
+ std::string path_{};
+ std::string debug_id_{};
+
+ // Allows to preserve unknown protobuf fields for compatibility
+ // with future versions of .proto files.
+ std::string unknown_fields_;
+
+ std::bitset<3> _has_field_{};
};
} // namespace perfetto
@@ -47384,6 +48511,8 @@ class InterceptorConfig;
class ConsoleConfig;
class ChromeConfig;
class SystemInfoConfig;
+class DataSourceConfig_ExperimentalTracingV2Config;
+class DataSourceConfig_ExperimentalTracingV2Config_ChunkSizeOption;
class ProtoVmConfig;
class TraceConfig_BufferConfig;
enum TraceConfig_LockdownModeOperation : int;
@@ -48524,6 +49653,67 @@ class AndroidPolledStateConfig : public ::protozero::Message {
}
};
+} // Namespace.
+} // Namespace.
+} // Namespace.
+#endif // Include guard.
+// gen_amalgamated begin header: gen/protos/perfetto/config/android/android_process_state_config.pbzero.h
+// Autogenerated by the ProtoZero compiler plugin. DO NOT EDIT.
+
+#ifndef PERFETTO_PROTOS_PROTOS_PERFETTO_CONFIG_ANDROID_ANDROID_PROCESS_STATE_CONFIG_PROTO_H_
+#define PERFETTO_PROTOS_PROTOS_PERFETTO_CONFIG_ANDROID_ANDROID_PROCESS_STATE_CONFIG_PROTO_H_
+
+#include <stddef.h>
+#include <stdint.h>
+
+// gen_amalgamated expanded: #include "perfetto/protozero/field_writer.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/message.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/packed_repeated_fields.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/proto_decoder.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/proto_utils.h"
+
+
+namespace perfetto {
+namespace protos {
+namespace pbzero {
+
+class AndroidProcessStateConfig_Decoder : public ::protozero::TypedProtoDecoder</*MAX_FIELD_ID=*/1> {
+ public:
+ AndroidProcessStateConfig_Decoder(const uint8_t* data, size_t len) : TypedProtoDecoder(data, len) {}
+ explicit AndroidProcessStateConfig_Decoder(const std::string& raw) : TypedProtoDecoder(reinterpret_cast<const uint8_t*>(raw.data()), raw.size()) {}
+ explicit AndroidProcessStateConfig_Decoder(const ::protozero::ConstBytes& raw) : TypedProtoDecoder(raw.data, raw.size) {}
+ bool has_dump_process_metadata() const { return at<1>().valid(); }
+ bool dump_process_metadata() const { return at<1>().as_bool(); }
+};
+
+class AndroidProcessStateConfig : public ::protozero::Message {
+ public:
+ using Decoder = AndroidProcessStateConfig_Decoder;
+ enum : int32_t {
+ kDumpProcessMetadataFieldNumber = 1,
+ };
+ static constexpr const char* GetName() { return ".perfetto.protos.AndroidProcessStateConfig"; }
+
+
+ using FieldMetadata_DumpProcessMetadata =
+ ::protozero::proto_utils::FieldMetadata<
+ 1,
+ ::protozero::proto_utils::RepetitionType::kNotRepeated,
+ ::protozero::proto_utils::ProtoSchemaType::kBool,
+ bool,
+ AndroidProcessStateConfig>;
+
+ static constexpr FieldMetadata_DumpProcessMetadata kDumpProcessMetadata{};
+ void set_dump_process_metadata(bool value) {
+ static constexpr uint32_t field_id = FieldMetadata_DumpProcessMetadata::kFieldId;
+ // Call the appropriate protozero::Message::Append(field_id, ...)
+ // method based on the type of the field.
+ ::protozero::internal::FieldWriter<
+ ::protozero::proto_utils::ProtoSchemaType::kBool>
+ ::Append(*this, field_id, value);
+ }
+};
+
} // Namespace.
} // Namespace.
} // Namespace.
@@ -52309,7 +53499,7 @@ namespace perfetto {
namespace protos {
namespace pbzero {
-class GpuRenderStagesConfig_Decoder : public ::protozero::TypedProtoDecoder</*MAX_FIELD_ID=*/3> {
+class GpuRenderStagesConfig_Decoder : public ::protozero::TypedProtoDecoder</*MAX_FIELD_ID=*/4> {
public:
GpuRenderStagesConfig_Decoder(const uint8_t* data, size_t len) : TypedProtoDecoder(data, len) {}
explicit GpuRenderStagesConfig_Decoder(const std::string& raw) : TypedProtoDecoder(reinterpret_cast<const uint8_t*>(raw.data()), raw.size()) {}
@@ -52320,6 +53510,8 @@ class GpuRenderStagesConfig_Decoder : public ::protozero::TypedProtoDecoder</*MA
bool low_overhead() const { return at<2>().as_bool(); }
bool has_trace_metrics() const { return at<3>().valid(); }
::protozero::RepeatedFieldIterator<::protozero::ConstChars> trace_metrics() const { return GetRepeated<::protozero::ConstChars>(3); }
+ bool has_drawcall_stages() const { return at<4>().valid(); }
+ bool drawcall_stages() const { return at<4>().as_bool(); }
};
class GpuRenderStagesConfig : public ::protozero::Message {
@@ -52329,6 +53521,7 @@ class GpuRenderStagesConfig : public ::protozero::Message {
kFullLoadstoreFieldNumber = 1,
kLowOverheadFieldNumber = 2,
kTraceMetricsFieldNumber = 3,
+ kDrawcallStagesFieldNumber = 4,
};
static constexpr const char* GetName() { return ".perfetto.protos.GpuRenderStagesConfig"; }
@@ -52392,6 +53585,24 @@ class GpuRenderStagesConfig : public ::protozero::Message {
::protozero::proto_utils::ProtoSchemaType::kString>
::Append(*this, field_id, value);
}
+
+ using FieldMetadata_DrawcallStages =
+ ::protozero::proto_utils::FieldMetadata<
+ 4,
+ ::protozero::proto_utils::RepetitionType::kNotRepeated,
+ ::protozero::proto_utils::ProtoSchemaType::kBool,
+ bool,
+ GpuRenderStagesConfig>;
+
+ static constexpr FieldMetadata_DrawcallStages kDrawcallStages{};
+ void set_drawcall_stages(bool value) {
+ static constexpr uint32_t field_id = FieldMetadata_DrawcallStages::kFieldId;
+ // Call the appropriate protozero::Message::Append(field_id, ...)
+ // method based on the type of the field.
+ ::protozero::internal::FieldWriter<
+ ::protozero::proto_utils::ProtoSchemaType::kBool>
+ ::Append(*this, field_id, value);
+ }
};
} // Namespace.
@@ -55432,7 +56643,10 @@ class PerfEventConfig_CallstackSampling : public ::protozero::Message {
namespace perfetto {
namespace protos {
namespace pbzero {
+class ProcessSmapsConfig_Scope;
+class ProcessSmapsConfig_Scope_UidRange;
class RedactionRule;
+class SmapsConfig;
namespace perfetto_pbzero_enum_RedactionRule {
enum MatchMode : int32_t;
} // namespace perfetto_pbzero_enum_RedactionRule
@@ -55807,6 +57021,239 @@ class SmapsConfig : public ::protozero::Message {
};
+class ProcessSmapsConfig_Decoder : public ::protozero::TypedProtoDecoder</*MAX_FIELD_ID=*/4> {
+ public:
+ ProcessSmapsConfig_Decoder(const uint8_t* data, size_t len) : TypedProtoDecoder(data, len) {}
+ explicit ProcessSmapsConfig_Decoder(const std::string& raw) : TypedProtoDecoder(reinterpret_cast<const uint8_t*>(raw.data()), raw.size()) {}
+ explicit ProcessSmapsConfig_Decoder(const ::protozero::ConstBytes& raw) : TypedProtoDecoder(raw.data, raw.size) {}
+ bool has_smaps_config() const { return at<1>().valid(); }
+ ::protozero::ConstBytes smaps_config() const { return at<1>().as_bytes(); }
+ bool has_scope() const { return at<2>().valid(); }
+ ::protozero::ConstBytes scope() const { return at<2>().as_bytes(); }
+ bool has_read_period_ms() const { return at<3>().valid(); }
+ uint32_t read_period_ms() const { return at<3>().as_uint32(); }
+ bool has_max_processes_per_period() const { return at<4>().valid(); }
+ uint32_t max_processes_per_period() const { return at<4>().as_uint32(); }
+};
+
+class ProcessSmapsConfig : public ::protozero::Message {
+ public:
+ using Decoder = ProcessSmapsConfig_Decoder;
+ enum : int32_t {
+ kSmapsConfigFieldNumber = 1,
+ kScopeFieldNumber = 2,
+ kReadPeriodMsFieldNumber = 3,
+ kMaxProcessesPerPeriodFieldNumber = 4,
+ };
+ static constexpr const char* GetName() { return ".perfetto.protos.ProcessSmapsConfig"; }
+
+ using Scope = ::perfetto::protos::pbzero::ProcessSmapsConfig_Scope;
+
+ using FieldMetadata_SmapsConfig =
+ ::protozero::proto_utils::FieldMetadata<
+ 1,
+ ::protozero::proto_utils::RepetitionType::kNotRepeated,
+ ::protozero::proto_utils::ProtoSchemaType::kMessage,
+ SmapsConfig,
+ ProcessSmapsConfig>;
+
+ static constexpr FieldMetadata_SmapsConfig kSmapsConfig{};
+ template <typename T = SmapsConfig> T* set_smaps_config() {
+ return BeginNestedMessage<T>(1);
+ }
+
+
+ using FieldMetadata_Scope =
+ ::protozero::proto_utils::FieldMetadata<
+ 2,
+ ::protozero::proto_utils::RepetitionType::kNotRepeated,
+ ::protozero::proto_utils::ProtoSchemaType::kMessage,
+ ProcessSmapsConfig_Scope,
+ ProcessSmapsConfig>;
+
+ static constexpr FieldMetadata_Scope kScope{};
+ template <typename T = ProcessSmapsConfig_Scope> T* set_scope() {
+ return BeginNestedMessage<T>(2);
+ }
+
+
+ using FieldMetadata_ReadPeriodMs =
+ ::protozero::proto_utils::FieldMetadata<
+ 3,
+ ::protozero::proto_utils::RepetitionType::kNotRepeated,
+ ::protozero::proto_utils::ProtoSchemaType::kUint32,
+ uint32_t,
+ ProcessSmapsConfig>;
+
+ static constexpr FieldMetadata_ReadPeriodMs kReadPeriodMs{};
+ void set_read_period_ms(uint32_t value) {
+ static constexpr uint32_t field_id = FieldMetadata_ReadPeriodMs::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_MaxProcessesPerPeriod =
+ ::protozero::proto_utils::FieldMetadata<
+ 4,
+ ::protozero::proto_utils::RepetitionType::kNotRepeated,
+ ::protozero::proto_utils::ProtoSchemaType::kUint32,
+ uint32_t,
+ ProcessSmapsConfig>;
+
+ static constexpr FieldMetadata_MaxProcessesPerPeriod kMaxProcessesPerPeriod{};
+ void set_max_processes_per_period(uint32_t value) {
+ static constexpr uint32_t field_id = FieldMetadata_MaxProcessesPerPeriod::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);
+ }
+};
+
+class ProcessSmapsConfig_Scope_Decoder : public ::protozero::TypedProtoDecoder</*MAX_FIELD_ID=*/2> {
+ public:
+ ProcessSmapsConfig_Scope_Decoder(const uint8_t* data, size_t len) : TypedProtoDecoder(data, len) {}
+ explicit ProcessSmapsConfig_Scope_Decoder(const std::string& raw) : TypedProtoDecoder(reinterpret_cast<const uint8_t*>(raw.data()), raw.size()) {}
+ explicit ProcessSmapsConfig_Scope_Decoder(const ::protozero::ConstBytes& raw) : TypedProtoDecoder(raw.data, raw.size) {}
+ bool has_target_cmdline() const { return at<1>().valid(); }
+ ::protozero::RepeatedFieldIterator<::protozero::ConstChars> target_cmdline() const { return GetRepeated<::protozero::ConstChars>(1); }
+ bool has_target_uid() const { return at<2>().valid(); }
+ ::protozero::RepeatedFieldIterator<::protozero::ConstBytes> target_uid() const { return GetRepeated<::protozero::ConstBytes>(2); }
+};
+
+class ProcessSmapsConfig_Scope : public ::protozero::Message {
+ public:
+ using Decoder = ProcessSmapsConfig_Scope_Decoder;
+ enum : int32_t {
+ kTargetCmdlineFieldNumber = 1,
+ kTargetUidFieldNumber = 2,
+ };
+ static constexpr const char* GetName() { return ".perfetto.protos.ProcessSmapsConfig.Scope"; }
+
+ using UidRange = ::perfetto::protos::pbzero::ProcessSmapsConfig_Scope_UidRange;
+
+ using FieldMetadata_TargetCmdline =
+ ::protozero::proto_utils::FieldMetadata<
+ 1,
+ ::protozero::proto_utils::RepetitionType::kRepeatedNotPacked,
+ ::protozero::proto_utils::ProtoSchemaType::kString,
+ std::string,
+ ProcessSmapsConfig_Scope>;
+
+ static constexpr FieldMetadata_TargetCmdline kTargetCmdline{};
+ void add_target_cmdline(const char* data, size_t size) {
+ AppendBytes(FieldMetadata_TargetCmdline::kFieldId, data, size);
+ }
+ void add_target_cmdline(::protozero::ConstChars chars) {
+ AppendBytes(FieldMetadata_TargetCmdline::kFieldId, chars.data, chars.size);
+ }
+ void add_target_cmdline(std::string value) {
+ static constexpr uint32_t field_id = FieldMetadata_TargetCmdline::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_TargetUid =
+ ::protozero::proto_utils::FieldMetadata<
+ 2,
+ ::protozero::proto_utils::RepetitionType::kRepeatedNotPacked,
+ ::protozero::proto_utils::ProtoSchemaType::kMessage,
+ ProcessSmapsConfig_Scope_UidRange,
+ ProcessSmapsConfig_Scope>;
+
+ static constexpr FieldMetadata_TargetUid kTargetUid{};
+ template <typename T = ProcessSmapsConfig_Scope_UidRange> T* add_target_uid() {
+ return BeginNestedMessage<T>(2);
+ }
+
+};
+
+class ProcessSmapsConfig_Scope_UidRange_Decoder : public ::protozero::TypedProtoDecoder</*MAX_FIELD_ID=*/3> {
+ public:
+ ProcessSmapsConfig_Scope_UidRange_Decoder(const uint8_t* data, size_t len) : TypedProtoDecoder(data, len) {}
+ explicit ProcessSmapsConfig_Scope_UidRange_Decoder(const std::string& raw) : TypedProtoDecoder(reinterpret_cast<const uint8_t*>(raw.data()), raw.size()) {}
+ explicit ProcessSmapsConfig_Scope_UidRange_Decoder(const ::protozero::ConstBytes& raw) : TypedProtoDecoder(raw.data, raw.size) {}
+ bool has_min_uid() const { return at<1>().valid(); }
+ uint32_t min_uid() const { return at<1>().as_uint32(); }
+ bool has_max_uid() const { return at<2>().valid(); }
+ uint32_t max_uid() const { return at<2>().as_uint32(); }
+ bool has_android_match_across_profiles() const { return at<3>().valid(); }
+ bool android_match_across_profiles() const { return at<3>().as_bool(); }
+};
+
+class ProcessSmapsConfig_Scope_UidRange : public ::protozero::Message {
+ public:
+ using Decoder = ProcessSmapsConfig_Scope_UidRange_Decoder;
+ enum : int32_t {
+ kMinUidFieldNumber = 1,
+ kMaxUidFieldNumber = 2,
+ kAndroidMatchAcrossProfilesFieldNumber = 3,
+ };
+ static constexpr const char* GetName() { return ".perfetto.protos.ProcessSmapsConfig.Scope.UidRange"; }
+
+
+ using FieldMetadata_MinUid =
+ ::protozero::proto_utils::FieldMetadata<
+ 1,
+ ::protozero::proto_utils::RepetitionType::kNotRepeated,
+ ::protozero::proto_utils::ProtoSchemaType::kUint32,
+ uint32_t,
+ ProcessSmapsConfig_Scope_UidRange>;
+
+ static constexpr FieldMetadata_MinUid kMinUid{};
+ void set_min_uid(uint32_t value) {
+ static constexpr uint32_t field_id = FieldMetadata_MinUid::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_MaxUid =
+ ::protozero::proto_utils::FieldMetadata<
+ 2,
+ ::protozero::proto_utils::RepetitionType::kNotRepeated,
+ ::protozero::proto_utils::ProtoSchemaType::kUint32,
+ uint32_t,
+ ProcessSmapsConfig_Scope_UidRange>;
+
+ static constexpr FieldMetadata_MaxUid kMaxUid{};
+ void set_max_uid(uint32_t value) {
+ static constexpr uint32_t field_id = FieldMetadata_MaxUid::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_AndroidMatchAcrossProfiles =
+ ::protozero::proto_utils::FieldMetadata<
+ 3,
+ ::protozero::proto_utils::RepetitionType::kNotRepeated,
+ ::protozero::proto_utils::ProtoSchemaType::kBool,
+ bool,
+ ProcessSmapsConfig_Scope_UidRange>;
+
+ static constexpr FieldMetadata_AndroidMatchAcrossProfiles kAndroidMatchAcrossProfiles{};
+ void set_android_match_across_profiles(bool value) {
+ static constexpr uint32_t field_id = FieldMetadata_AndroidMatchAcrossProfiles::kFieldId;
+ // Call the appropriate protozero::Message::Append(field_id, ...)
+ // method based on the type of the field.
+ ::protozero::internal::FieldWriter<
+ ::protozero::proto_utils::ProtoSchemaType::kBool>
+ ::Append(*this, field_id, value);
+ }
+};
+
} // Namespace.
} // Namespace.
} // Namespace.
@@ -62257,6 +63704,88 @@ class ChromiumHistogramSamplesConfig_HistogramSample : public ::protozero::Messa
}
};
+} // Namespace.
+} // Namespace.
+} // Namespace.
+#endif // Include guard.
+// gen_amalgamated begin header: gen/protos/perfetto/config/chrome/sampling_heap_profiler.pbzero.h
+// Autogenerated by the ProtoZero compiler plugin. DO NOT EDIT.
+
+#ifndef PERFETTO_PROTOS_PROTOS_PERFETTO_CONFIG_CHROME_SAMPLING_HEAP_PROFILER_PROTO_H_
+#define PERFETTO_PROTOS_PROTOS_PERFETTO_CONFIG_CHROME_SAMPLING_HEAP_PROFILER_PROTO_H_
+
+#include <stddef.h>
+#include <stdint.h>
+
+// gen_amalgamated expanded: #include "perfetto/protozero/field_writer.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/message.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/packed_repeated_fields.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/proto_decoder.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/proto_utils.h"
+
+
+namespace perfetto {
+namespace protos {
+namespace pbzero {
+
+class ChromiumSamplingHeapProfilerConfig_Decoder : public ::protozero::TypedProtoDecoder</*MAX_FIELD_ID=*/2> {
+ public:
+ ChromiumSamplingHeapProfilerConfig_Decoder(const uint8_t* data, size_t len) : TypedProtoDecoder(data, len) {}
+ explicit ChromiumSamplingHeapProfilerConfig_Decoder(const std::string& raw) : TypedProtoDecoder(reinterpret_cast<const uint8_t*>(raw.data()), raw.size()) {}
+ explicit ChromiumSamplingHeapProfilerConfig_Decoder(const ::protozero::ConstBytes& raw) : TypedProtoDecoder(raw.data, raw.size) {}
+ bool has_sampling_interval_bytes() const { return at<1>().valid(); }
+ uint64_t sampling_interval_bytes() const { return at<1>().as_uint64(); }
+ bool has_sampling_interval_ms() const { return at<2>().valid(); }
+ uint32_t sampling_interval_ms() const { return at<2>().as_uint32(); }
+};
+
+class ChromiumSamplingHeapProfilerConfig : public ::protozero::Message {
+ public:
+ using Decoder = ChromiumSamplingHeapProfilerConfig_Decoder;
+ enum : int32_t {
+ kSamplingIntervalBytesFieldNumber = 1,
+ kSamplingIntervalMsFieldNumber = 2,
+ };
+ static constexpr const char* GetName() { return ".perfetto.protos.ChromiumSamplingHeapProfilerConfig"; }
+
+
+ using FieldMetadata_SamplingIntervalBytes =
+ ::protozero::proto_utils::FieldMetadata<
+ 1,
+ ::protozero::proto_utils::RepetitionType::kNotRepeated,
+ ::protozero::proto_utils::ProtoSchemaType::kUint64,
+ uint64_t,
+ ChromiumSamplingHeapProfilerConfig>;
+
+ static constexpr FieldMetadata_SamplingIntervalBytes kSamplingIntervalBytes{};
+ void set_sampling_interval_bytes(uint64_t value) {
+ static constexpr uint32_t field_id = FieldMetadata_SamplingIntervalBytes::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_SamplingIntervalMs =
+ ::protozero::proto_utils::FieldMetadata<
+ 2,
+ ::protozero::proto_utils::RepetitionType::kNotRepeated,
+ ::protozero::proto_utils::ProtoSchemaType::kUint32,
+ uint32_t,
+ ChromiumSamplingHeapProfilerConfig>;
+
+ static constexpr FieldMetadata_SamplingIntervalMs kSamplingIntervalMs{};
+ void set_sampling_interval_ms(uint32_t value) {
+ static constexpr uint32_t field_id = FieldMetadata_SamplingIntervalMs::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.
} // Namespace.
} // Namespace.
@@ -62958,6 +64487,67 @@ class TriggerRule_HistogramTrigger : public ::protozero::Message {
}
};
+} // Namespace.
+} // Namespace.
+} // Namespace.
+#endif // Include guard.
+// gen_amalgamated begin header: gen/protos/perfetto/config/chrome/stack_sampling_profiler.pbzero.h
+// Autogenerated by the ProtoZero compiler plugin. DO NOT EDIT.
+
+#ifndef PERFETTO_PROTOS_PROTOS_PERFETTO_CONFIG_CHROME_STACK_SAMPLING_PROFILER_PROTO_H_
+#define PERFETTO_PROTOS_PROTOS_PERFETTO_CONFIG_CHROME_STACK_SAMPLING_PROFILER_PROTO_H_
+
+#include <stddef.h>
+#include <stdint.h>
+
+// gen_amalgamated expanded: #include "perfetto/protozero/field_writer.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/message.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/packed_repeated_fields.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/proto_decoder.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/proto_utils.h"
+
+
+namespace perfetto {
+namespace protos {
+namespace pbzero {
+
+class ChromiumStackSamplingProfilerConfig_Decoder : public ::protozero::TypedProtoDecoder</*MAX_FIELD_ID=*/1> {
+ public:
+ ChromiumStackSamplingProfilerConfig_Decoder(const uint8_t* data, size_t len) : TypedProtoDecoder(data, len) {}
+ explicit ChromiumStackSamplingProfilerConfig_Decoder(const std::string& raw) : TypedProtoDecoder(reinterpret_cast<const uint8_t*>(raw.data()), raw.size()) {}
+ explicit ChromiumStackSamplingProfilerConfig_Decoder(const ::protozero::ConstBytes& raw) : TypedProtoDecoder(raw.data, raw.size) {}
+ bool has_sampling_interval_ms() const { return at<1>().valid(); }
+ uint32_t sampling_interval_ms() const { return at<1>().as_uint32(); }
+};
+
+class ChromiumStackSamplingProfilerConfig : public ::protozero::Message {
+ public:
+ using Decoder = ChromiumStackSamplingProfilerConfig_Decoder;
+ enum : int32_t {
+ kSamplingIntervalMsFieldNumber = 1,
+ };
+ static constexpr const char* GetName() { return ".perfetto.protos.ChromiumStackSamplingProfilerConfig"; }
+
+
+ using FieldMetadata_SamplingIntervalMs =
+ ::protozero::proto_utils::FieldMetadata<
+ 1,
+ ::protozero::proto_utils::RepetitionType::kNotRepeated,
+ ::protozero::proto_utils::ProtoSchemaType::kUint32,
+ uint32_t,
+ ChromiumStackSamplingProfilerConfig>;
+
+ static constexpr FieldMetadata_SamplingIntervalMs kSamplingIntervalMs{};
+ void set_sampling_interval_ms(uint32_t value) {
+ static constexpr uint32_t field_id = FieldMetadata_SamplingIntervalMs::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.
} // Namespace.
} // Namespace.
@@ -63129,14 +64719,19 @@ class AndroidInputEventConfig;
class AndroidLogConfig;
class AndroidPolledStateConfig;
class AndroidPowerConfig;
+class AndroidProcessStateConfig;
class AndroidSdkSyspropGuardConfig;
class AndroidSystemPropertyConfig;
class AndroidUserListConfig;
class AppWakelocksConfig;
class ChromeConfig;
class ChromiumHistogramSamplesConfig;
+class ChromiumSamplingHeapProfilerConfig;
+class ChromiumStackSamplingProfilerConfig;
class ChromiumSystemMetricsConfig;
class CpuPerUidConfig;
+class DataSourceConfig_ExperimentalTracingV2Config;
+class DataSourceConfig_ExperimentalTracingV2Config_ChunkSizeOption;
class DisplayVideoConfig;
class EtwConfig;
class FrozenFtraceConfig;
@@ -63154,6 +64749,7 @@ class PackagesListConfig;
class PerfEventConfig;
class PixelModemConfig;
class PriorityBoostConfig;
+class ProcessSmapsConfig;
class ProcessStatsConfig;
class ProtoLogConfig;
class ProtoVmConfig;
@@ -63272,6 +64868,10 @@ class DataSourceConfig_Decoder : public ::protozero::TypedProtoDecoder</*MAX_FIE
::protozero::ConstBytes priority_boost() const { return at<10>().as_bytes(); }
bool has_protovm_config() const { return at<12>().valid(); }
::protozero::ConstBytes protovm_config() const { return at<12>().as_bytes(); }
+ bool has_supports_tracing_v2() const { return at<147>().valid(); }
+ bool supports_tracing_v2() const { return at<147>().as_bool(); }
+ bool has_experimental_tracing_v2() const { return at<148>().valid(); }
+ ::protozero::ConstBytes experimental_tracing_v2() const { return at<148>().as_bytes(); }
bool has_ftrace_config() const { return at<100>().valid(); }
::protozero::ConstBytes ftrace_config() const { return at<100>().as_bytes(); }
bool has_inode_file_config() const { return at<102>().valid(); }
@@ -63356,6 +64956,14 @@ class DataSourceConfig_Decoder : public ::protozero::TypedProtoDecoder</*MAX_FIE
::protozero::ConstBytes journald_config() const { return at<141>().as_bytes(); }
bool has_display_video_config() const { return at<142>().valid(); }
::protozero::ConstBytes display_video_config() const { return at<142>().as_bytes(); }
+ bool has_chromium_stack_sampling_profiler() const { return at<143>().valid(); }
+ ::protozero::ConstBytes chromium_stack_sampling_profiler() const { return at<143>().as_bytes(); }
+ bool has_chromium_sampling_heap_profiler() const { return at<144>().valid(); }
+ ::protozero::ConstBytes chromium_sampling_heap_profiler() const { return at<144>().as_bytes(); }
+ bool has_android_process_state_config() const { return at<145>().valid(); }
+ ::protozero::ConstBytes android_process_state_config() const { return at<145>().as_bytes(); }
+ bool has_process_smaps_config() const { return at<146>().valid(); }
+ ::protozero::ConstBytes process_smaps_config() const { return at<146>().as_bytes(); }
bool has_qnx_config() const { return at<150>().valid(); }
::protozero::ConstBytes qnx_config() const { return at<150>().as_bytes(); }
// field legacy_config omitted because its id is too high
@@ -63378,6 +64986,8 @@ class DataSourceConfig : public ::protozero::Message {
kBufferExhaustedPolicyFieldNumber = 9,
kPriorityBoostFieldNumber = 10,
kProtovmConfigFieldNumber = 12,
+ kSupportsTracingV2FieldNumber = 147,
+ kExperimentalTracingV2FieldNumber = 148,
kFtraceConfigFieldNumber = 100,
kInodeFileConfigFieldNumber = 102,
kProcessStatsConfigFieldNumber = 103,
@@ -63420,12 +65030,17 @@ class DataSourceConfig : public ::protozero::Message {
kAndroidAflagsConfigFieldNumber = 140,
kJournaldConfigFieldNumber = 141,
kDisplayVideoConfigFieldNumber = 142,
+ kChromiumStackSamplingProfilerFieldNumber = 143,
+ kChromiumSamplingHeapProfilerFieldNumber = 144,
+ kAndroidProcessStateConfigFieldNumber = 145,
+ kProcessSmapsConfigFieldNumber = 146,
kQnxConfigFieldNumber = 150,
kLegacyConfigFieldNumber = 1000,
kForTestingFieldNumber = 1001,
};
static constexpr const char* GetName() { return ".perfetto.protos.DataSourceConfig"; }
+ using ExperimentalTracingV2Config = ::perfetto::protos::pbzero::DataSourceConfig_ExperimentalTracingV2Config;
using SessionInitiator = ::perfetto::protos::pbzero::DataSourceConfig_SessionInitiator;
static inline const char* SessionInitiator_Name(SessionInitiator value) {
@@ -63663,6 +65278,38 @@ class DataSourceConfig : public ::protozero::Message {
}
+ using FieldMetadata_SupportsTracingV2 =
+ ::protozero::proto_utils::FieldMetadata<
+ 147,
+ ::protozero::proto_utils::RepetitionType::kNotRepeated,
+ ::protozero::proto_utils::ProtoSchemaType::kBool,
+ bool,
+ DataSourceConfig>;
+
+ static constexpr FieldMetadata_SupportsTracingV2 kSupportsTracingV2{};
+ void set_supports_tracing_v2(bool value) {
+ static constexpr uint32_t field_id = FieldMetadata_SupportsTracingV2::kFieldId;
+ // Call the appropriate protozero::Message::Append(field_id, ...)
+ // method based on the type of the field.
+ ::protozero::internal::FieldWriter<
+ ::protozero::proto_utils::ProtoSchemaType::kBool>
+ ::Append(*this, field_id, value);
+ }
+
+ using FieldMetadata_ExperimentalTracingV2 =
+ ::protozero::proto_utils::FieldMetadata<
+ 148,
+ ::protozero::proto_utils::RepetitionType::kNotRepeated,
+ ::protozero::proto_utils::ProtoSchemaType::kMessage,
+ DataSourceConfig_ExperimentalTracingV2Config,
+ DataSourceConfig>;
+
+ static constexpr FieldMetadata_ExperimentalTracingV2 kExperimentalTracingV2{};
+ template <typename T = DataSourceConfig_ExperimentalTracingV2Config> T* set_experimental_tracing_v2() {
+ return BeginNestedMessage<T>(148);
+ }
+
+
using FieldMetadata_FtraceConfig =
::protozero::proto_utils::FieldMetadata<
100,
@@ -64407,6 +66054,78 @@ class DataSourceConfig : public ::protozero::Message {
}
+ using FieldMetadata_ChromiumStackSamplingProfiler =
+ ::protozero::proto_utils::FieldMetadata<
+ 143,
+ ::protozero::proto_utils::RepetitionType::kNotRepeated,
+ ::protozero::proto_utils::ProtoSchemaType::kMessage,
+ ChromiumStackSamplingProfilerConfig,
+ DataSourceConfig>;
+
+ static constexpr FieldMetadata_ChromiumStackSamplingProfiler kChromiumStackSamplingProfiler{};
+ template <typename T = ChromiumStackSamplingProfilerConfig> T* set_chromium_stack_sampling_profiler() {
+ return BeginNestedMessage<T>(143);
+ }
+
+ void set_chromium_stack_sampling_profiler_raw(const std::string& raw) {
+ return AppendBytes(143, raw.data(), raw.size());
+ }
+
+
+ using FieldMetadata_ChromiumSamplingHeapProfiler =
+ ::protozero::proto_utils::FieldMetadata<
+ 144,
+ ::protozero::proto_utils::RepetitionType::kNotRepeated,
+ ::protozero::proto_utils::ProtoSchemaType::kMessage,
+ ChromiumSamplingHeapProfilerConfig,
+ DataSourceConfig>;
+
+ static constexpr FieldMetadata_ChromiumSamplingHeapProfiler kChromiumSamplingHeapProfiler{};
+ template <typename T = ChromiumSamplingHeapProfilerConfig> T* set_chromium_sampling_heap_profiler() {
+ return BeginNestedMessage<T>(144);
+ }
+
+ void set_chromium_sampling_heap_profiler_raw(const std::string& raw) {
+ return AppendBytes(144, raw.data(), raw.size());
+ }
+
+
+ using FieldMetadata_AndroidProcessStateConfig =
+ ::protozero::proto_utils::FieldMetadata<
+ 145,
+ ::protozero::proto_utils::RepetitionType::kNotRepeated,
+ ::protozero::proto_utils::ProtoSchemaType::kMessage,
+ AndroidProcessStateConfig,
+ DataSourceConfig>;
+
+ static constexpr FieldMetadata_AndroidProcessStateConfig kAndroidProcessStateConfig{};
+ template <typename T = AndroidProcessStateConfig> T* set_android_process_state_config() {
+ return BeginNestedMessage<T>(145);
+ }
+
+ void set_android_process_state_config_raw(const std::string& raw) {
+ return AppendBytes(145, raw.data(), raw.size());
+ }
+
+
+ using FieldMetadata_ProcessSmapsConfig =
+ ::protozero::proto_utils::FieldMetadata<
+ 146,
+ ::protozero::proto_utils::RepetitionType::kNotRepeated,
+ ::protozero::proto_utils::ProtoSchemaType::kMessage,
+ ProcessSmapsConfig,
+ DataSourceConfig>;
+
+ static constexpr FieldMetadata_ProcessSmapsConfig kProcessSmapsConfig{};
+ template <typename T = ProcessSmapsConfig> T* set_process_smaps_config() {
+ return BeginNestedMessage<T>(146);
+ }
+
+ void set_process_smaps_config_raw(const std::string& raw) {
+ return AppendBytes(146, raw.data(), raw.size());
+ }
+
+
using FieldMetadata_QnxConfig =
::protozero::proto_utils::FieldMetadata<
150,
@@ -64464,6 +66183,140 @@ class DataSourceConfig : public ::protozero::Message {
};
+class DataSourceConfig_ExperimentalTracingV2Config_Decoder : public ::protozero::TypedProtoDecoder</*MAX_FIELD_ID=*/3> {
+ public:
+ DataSourceConfig_ExperimentalTracingV2Config_Decoder(const uint8_t* data, size_t len) : TypedProtoDecoder(data, len) {}
+ explicit DataSourceConfig_ExperimentalTracingV2Config_Decoder(const std::string& raw) : TypedProtoDecoder(reinterpret_cast<const uint8_t*>(raw.data()), raw.size()) {}
+ explicit DataSourceConfig_ExperimentalTracingV2Config_Decoder(const ::protozero::ConstBytes& raw) : TypedProtoDecoder(raw.data, raw.size) {}
+ bool has_use_v2_probability_percent() const { return at<1>().valid(); }
+ uint32_t use_v2_probability_percent() const { return at<1>().as_uint32(); }
+ bool has_chunk_size_options() const { return at<2>().valid(); }
+ ::protozero::RepeatedFieldIterator<::protozero::ConstBytes> chunk_size_options() const { return GetRepeated<::protozero::ConstBytes>(2); }
+ bool has_drain_occupancy_percent() const { return at<3>().valid(); }
+ int32_t drain_occupancy_percent() const { return at<3>().as_int32(); }
+};
+
+class DataSourceConfig_ExperimentalTracingV2Config : public ::protozero::Message {
+ public:
+ using Decoder = DataSourceConfig_ExperimentalTracingV2Config_Decoder;
+ enum : int32_t {
+ kUseV2ProbabilityPercentFieldNumber = 1,
+ kChunkSizeOptionsFieldNumber = 2,
+ kDrainOccupancyPercentFieldNumber = 3,
+ };
+ static constexpr const char* GetName() { return ".perfetto.protos.DataSourceConfig.ExperimentalTracingV2Config"; }
+
+ using ChunkSizeOption = ::perfetto::protos::pbzero::DataSourceConfig_ExperimentalTracingV2Config_ChunkSizeOption;
+
+ using FieldMetadata_UseV2ProbabilityPercent =
+ ::protozero::proto_utils::FieldMetadata<
+ 1,
+ ::protozero::proto_utils::RepetitionType::kNotRepeated,
+ ::protozero::proto_utils::ProtoSchemaType::kUint32,
+ uint32_t,
+ DataSourceConfig_ExperimentalTracingV2Config>;
+
+ static constexpr FieldMetadata_UseV2ProbabilityPercent kUseV2ProbabilityPercent{};
+ void set_use_v2_probability_percent(uint32_t value) {
+ static constexpr uint32_t field_id = FieldMetadata_UseV2ProbabilityPercent::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_ChunkSizeOptions =
+ ::protozero::proto_utils::FieldMetadata<
+ 2,
+ ::protozero::proto_utils::RepetitionType::kRepeatedNotPacked,
+ ::protozero::proto_utils::ProtoSchemaType::kMessage,
+ DataSourceConfig_ExperimentalTracingV2Config_ChunkSizeOption,
+ DataSourceConfig_ExperimentalTracingV2Config>;
+
+ static constexpr FieldMetadata_ChunkSizeOptions kChunkSizeOptions{};
+ template <typename T = DataSourceConfig_ExperimentalTracingV2Config_ChunkSizeOption> T* add_chunk_size_options() {
+ return BeginNestedMessage<T>(2);
+ }
+
+
+ using FieldMetadata_DrainOccupancyPercent =
+ ::protozero::proto_utils::FieldMetadata<
+ 3,
+ ::protozero::proto_utils::RepetitionType::kNotRepeated,
+ ::protozero::proto_utils::ProtoSchemaType::kInt32,
+ int32_t,
+ DataSourceConfig_ExperimentalTracingV2Config>;
+
+ static constexpr FieldMetadata_DrainOccupancyPercent kDrainOccupancyPercent{};
+ void set_drain_occupancy_percent(int32_t value) {
+ static constexpr uint32_t field_id = FieldMetadata_DrainOccupancyPercent::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);
+ }
+};
+
+class DataSourceConfig_ExperimentalTracingV2Config_ChunkSizeOption_Decoder : public ::protozero::TypedProtoDecoder</*MAX_FIELD_ID=*/2> {
+ public:
+ DataSourceConfig_ExperimentalTracingV2Config_ChunkSizeOption_Decoder(const uint8_t* data, size_t len) : TypedProtoDecoder(data, len) {}
+ explicit DataSourceConfig_ExperimentalTracingV2Config_ChunkSizeOption_Decoder(const std::string& raw) : TypedProtoDecoder(reinterpret_cast<const uint8_t*>(raw.data()), raw.size()) {}
+ explicit DataSourceConfig_ExperimentalTracingV2Config_ChunkSizeOption_Decoder(const ::protozero::ConstBytes& raw) : TypedProtoDecoder(raw.data, raw.size) {}
+ bool has_size_bytes() const { return at<1>().valid(); }
+ uint32_t size_bytes() const { return at<1>().as_uint32(); }
+ bool has_weight() const { return at<2>().valid(); }
+ uint32_t weight() const { return at<2>().as_uint32(); }
+};
+
+class DataSourceConfig_ExperimentalTracingV2Config_ChunkSizeOption : public ::protozero::Message {
+ public:
+ using Decoder = DataSourceConfig_ExperimentalTracingV2Config_ChunkSizeOption_Decoder;
+ enum : int32_t {
+ kSizeBytesFieldNumber = 1,
+ kWeightFieldNumber = 2,
+ };
+ static constexpr const char* GetName() { return ".perfetto.protos.DataSourceConfig.ExperimentalTracingV2Config.ChunkSizeOption"; }
+
+
+ using FieldMetadata_SizeBytes =
+ ::protozero::proto_utils::FieldMetadata<
+ 1,
+ ::protozero::proto_utils::RepetitionType::kNotRepeated,
+ ::protozero::proto_utils::ProtoSchemaType::kUint32,
+ uint32_t,
+ DataSourceConfig_ExperimentalTracingV2Config_ChunkSizeOption>;
+
+ static constexpr FieldMetadata_SizeBytes kSizeBytes{};
+ void set_size_bytes(uint32_t value) {
+ static constexpr uint32_t field_id = FieldMetadata_SizeBytes::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_Weight =
+ ::protozero::proto_utils::FieldMetadata<
+ 2,
+ ::protozero::proto_utils::RepetitionType::kNotRepeated,
+ ::protozero::proto_utils::ProtoSchemaType::kUint32,
+ uint32_t,
+ DataSourceConfig_ExperimentalTracingV2Config_ChunkSizeOption>;
+
+ static constexpr FieldMetadata_Weight kWeight{};
+ void set_weight(uint32_t value) {
+ static constexpr uint32_t field_id = FieldMetadata_Weight::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.
} // Namespace.
} // Namespace.
@@ -64486,6 +66339,7 @@ class DataSourceConfig : public ::protozero::Message {
namespace perfetto {
namespace protos {
namespace pbzero {
+class EtwConfig_DebugId;
namespace perfetto_pbzero_enum_EtwConfig {
enum KernelFlag : int32_t;
} // namespace perfetto_pbzero_enum_EtwConfig
@@ -64523,7 +66377,7 @@ const char* EtwConfig_KernelFlag_Name(::perfetto::protos::pbzero::EtwConfig_Kern
return "PBZERO_UNKNOWN_ENUM_VALUE";
}
-class EtwConfig_Decoder : public ::protozero::TypedProtoDecoder</*MAX_FIELD_ID=*/7> {
+class EtwConfig_Decoder : public ::protozero::TypedProtoDecoder</*MAX_FIELD_ID=*/8> {
public:
EtwConfig_Decoder(const uint8_t* data, size_t len) : TypedProtoDecoder(data, len) {}
explicit EtwConfig_Decoder(const std::string& raw) : TypedProtoDecoder(reinterpret_cast<const uint8_t*>(raw.data()), raw.size()) {}
@@ -64542,6 +66396,8 @@ class EtwConfig_Decoder : public ::protozero::TypedProtoDecoder</*MAX_FIELD_ID=*
::protozero::RepeatedFieldIterator<::protozero::ConstChars> disk_provider_events() const { return GetRepeated<::protozero::ConstChars>(6); }
bool has_system_io_provider_events() const { return at<7>().valid(); }
::protozero::RepeatedFieldIterator<::protozero::ConstChars> system_io_provider_events() const { return GetRepeated<::protozero::ConstChars>(7); }
+ bool has_stack_sampling_debug_ids() const { return at<8>().valid(); }
+ ::protozero::RepeatedFieldIterator<::protozero::ConstBytes> stack_sampling_debug_ids() const { return GetRepeated<::protozero::ConstBytes>(8); }
};
class EtwConfig : public ::protozero::Message {
@@ -64555,9 +66411,11 @@ class EtwConfig : public ::protozero::Message {
kStackSamplingEventsFieldNumber = 5,
kDiskProviderEventsFieldNumber = 6,
kSystemIoProviderEventsFieldNumber = 7,
+ kStackSamplingDebugIdsFieldNumber = 8,
};
static constexpr const char* GetName() { return ".perfetto.protos.EtwConfig"; }
+ using DebugId = ::perfetto::protos::pbzero::EtwConfig_DebugId;
using KernelFlag = ::perfetto::protos::pbzero::EtwConfig_KernelFlag;
static inline const char* KernelFlag_Name(KernelFlag value) {
@@ -64727,6 +66585,90 @@ class EtwConfig : public ::protozero::Message {
::protozero::proto_utils::ProtoSchemaType::kString>
::Append(*this, field_id, value);
}
+
+ using FieldMetadata_StackSamplingDebugIds =
+ ::protozero::proto_utils::FieldMetadata<
+ 8,
+ ::protozero::proto_utils::RepetitionType::kRepeatedNotPacked,
+ ::protozero::proto_utils::ProtoSchemaType::kMessage,
+ EtwConfig_DebugId,
+ EtwConfig>;
+
+ static constexpr FieldMetadata_StackSamplingDebugIds kStackSamplingDebugIds{};
+ template <typename T = EtwConfig_DebugId> T* add_stack_sampling_debug_ids() {
+ return BeginNestedMessage<T>(8);
+ }
+
+};
+
+class EtwConfig_DebugId_Decoder : public ::protozero::TypedProtoDecoder</*MAX_FIELD_ID=*/2> {
+ public:
+ EtwConfig_DebugId_Decoder(const uint8_t* data, size_t len) : TypedProtoDecoder(data, len) {}
+ explicit EtwConfig_DebugId_Decoder(const std::string& raw) : TypedProtoDecoder(reinterpret_cast<const uint8_t*>(raw.data()), raw.size()) {}
+ explicit EtwConfig_DebugId_Decoder(const ::protozero::ConstBytes& raw) : TypedProtoDecoder(raw.data, raw.size) {}
+ bool has_path() const { return at<1>().valid(); }
+ ::protozero::ConstChars path() const { return at<1>().as_string(); }
+ bool has_debug_id() const { return at<2>().valid(); }
+ ::protozero::ConstChars debug_id() const { return at<2>().as_string(); }
+};
+
+class EtwConfig_DebugId : public ::protozero::Message {
+ public:
+ using Decoder = EtwConfig_DebugId_Decoder;
+ enum : int32_t {
+ kPathFieldNumber = 1,
+ kDebugIdFieldNumber = 2,
+ };
+ static constexpr const char* GetName() { return ".perfetto.protos.EtwConfig.DebugId"; }
+
+
+ using FieldMetadata_Path =
+ ::protozero::proto_utils::FieldMetadata<
+ 1,
+ ::protozero::proto_utils::RepetitionType::kNotRepeated,
+ ::protozero::proto_utils::ProtoSchemaType::kString,
+ std::string,
+ EtwConfig_DebugId>;
+
+ static constexpr FieldMetadata_Path kPath{};
+ void set_path(const char* data, size_t size) {
+ AppendBytes(FieldMetadata_Path::kFieldId, data, size);
+ }
+ void set_path(::protozero::ConstChars chars) {
+ AppendBytes(FieldMetadata_Path::kFieldId, chars.data, chars.size);
+ }
+ void set_path(std::string value) {
+ static constexpr uint32_t field_id = FieldMetadata_Path::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_DebugId =
+ ::protozero::proto_utils::FieldMetadata<
+ 2,
+ ::protozero::proto_utils::RepetitionType::kNotRepeated,
+ ::protozero::proto_utils::ProtoSchemaType::kString,
+ std::string,
+ EtwConfig_DebugId>;
+
+ static constexpr FieldMetadata_DebugId kDebugId{};
+ void set_debug_id(const char* data, size_t size) {
+ AppendBytes(FieldMetadata_DebugId::kFieldId, data, size);
+ }
+ void set_debug_id(::protozero::ConstChars chars) {
+ AppendBytes(FieldMetadata_DebugId::kFieldId, chars.data, chars.size);
+ }
+ void set_debug_id(std::string value) {
+ static constexpr uint32_t field_id = FieldMetadata_DebugId::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.
@@ -66064,13 +68006,15 @@ const char* TraceConfig_BufferConfig_ExperimentalMode_Name(::perfetto::protos::p
return "PBZERO_UNKNOWN_ENUM_VALUE";
}
-class TraceConfig_Decoder : public ::protozero::TypedProtoDecoder</*MAX_FIELD_ID=*/48> {
+class TraceConfig_Decoder : public ::protozero::TypedProtoDecoder</*MAX_FIELD_ID=*/50> {
public:
TraceConfig_Decoder(const uint8_t* data, size_t len) : TypedProtoDecoder(data, len) {}
explicit TraceConfig_Decoder(const std::string& raw) : TypedProtoDecoder(reinterpret_cast<const uint8_t*>(raw.data()), raw.size()) {}
explicit TraceConfig_Decoder(const ::protozero::ConstBytes& raw) : TypedProtoDecoder(raw.data, raw.size) {}
bool has_buffers() const { return at<1>().valid(); }
::protozero::RepeatedFieldIterator<::protozero::ConstBytes> buffers() const { return GetRepeated<::protozero::ConstBytes>(1); }
+ bool has_experimental_trace_buffer_v2_compaction() const { return at<50>().valid(); }
+ bool experimental_trace_buffer_v2_compaction() const { return at<50>().as_bool(); }
bool has_data_sources() const { return at<2>().valid(); }
::protozero::RepeatedFieldIterator<::protozero::ConstBytes> data_sources() const { return GetRepeated<::protozero::ConstBytes>(2); }
bool has_builtin_data_sources() const { return at<20>().valid(); }
@@ -66153,6 +68097,8 @@ class TraceConfig_Decoder : public ::protozero::TypedProtoDecoder</*MAX_FIELD_ID
bool trace_all_machines() const { return at<43>().as_bool(); }
bool has_trace_attributes() const { return at<48>().valid(); }
::protozero::ConstBytes trace_attributes() const { return at<48>().as_bytes(); }
+ bool has_persist_trace_across_reboots() const { return at<49>().valid(); }
+ bool persist_trace_across_reboots() const { return at<49>().as_bool(); }
};
class TraceConfig : public ::protozero::Message {
@@ -66160,6 +68106,7 @@ class TraceConfig : public ::protozero::Message {
using Decoder = TraceConfig_Decoder;
enum : int32_t {
kBuffersFieldNumber = 1,
+ kExperimentalTraceBufferV2CompactionFieldNumber = 50,
kDataSourcesFieldNumber = 2,
kBuiltinDataSourcesFieldNumber = 20,
kDurationMsFieldNumber = 3,
@@ -66201,6 +68148,7 @@ class TraceConfig : public ::protozero::Message {
kFflushPostWriteFieldNumber = 45,
kTraceAllMachinesFieldNumber = 43,
kTraceAttributesFieldNumber = 48,
+ kPersistTraceAcrossRebootsFieldNumber = 49,
};
static constexpr const char* GetName() { return ".perfetto.protos.TraceConfig"; }
@@ -66273,6 +68221,24 @@ class TraceConfig : public ::protozero::Message {
}
+ using FieldMetadata_ExperimentalTraceBufferV2Compaction =
+ ::protozero::proto_utils::FieldMetadata<
+ 50,
+ ::protozero::proto_utils::RepetitionType::kNotRepeated,
+ ::protozero::proto_utils::ProtoSchemaType::kBool,
+ bool,
+ TraceConfig>;
+
+ static constexpr FieldMetadata_ExperimentalTraceBufferV2Compaction kExperimentalTraceBufferV2Compaction{};
+ void set_experimental_trace_buffer_v2_compaction(bool value) {
+ static constexpr uint32_t field_id = FieldMetadata_ExperimentalTraceBufferV2Compaction::kFieldId;
+ // Call the appropriate protozero::Message::Append(field_id, ...)
+ // method based on the type of the field.
+ ::protozero::internal::FieldWriter<
+ ::protozero::proto_utils::ProtoSchemaType::kBool>
+ ::Append(*this, field_id, value);
+ }
+
using FieldMetadata_DataSources =
::protozero::proto_utils::FieldMetadata<
2,
@@ -66974,6 +68940,24 @@ class TraceConfig : public ::protozero::Message {
return BeginNestedMessage<T>(48);
}
+
+ using FieldMetadata_PersistTraceAcrossReboots =
+ ::protozero::proto_utils::FieldMetadata<
+ 49,
+ ::protozero::proto_utils::RepetitionType::kNotRepeated,
+ ::protozero::proto_utils::ProtoSchemaType::kBool,
+ bool,
+ TraceConfig>;
+
+ static constexpr FieldMetadata_PersistTraceAcrossReboots kPersistTraceAcrossReboots{};
+ void set_persist_trace_across_reboots(bool value) {
+ static constexpr uint32_t field_id = FieldMetadata_PersistTraceAcrossReboots::kFieldId;
+ // Call the appropriate protozero::Message::Append(field_id, ...)
+ // method based on the type of the field.
+ ::protozero::internal::FieldWriter<
+ ::protozero::proto_utils::ProtoSchemaType::kBool>
+ ::Append(*this, field_id, value);
+ }
};
class TraceConfig_SessionSemaphore_Decoder : public ::protozero::TypedProtoDecoder</*MAX_FIELD_ID=*/2> {
@@ -71535,7 +73519,7 @@ class PackagesList : public ::protozero::Message {
}
};
-class PackagesList_PackageInfo_Decoder : public ::protozero::TypedProtoDecoder</*MAX_FIELD_ID=*/5> {
+class PackagesList_PackageInfo_Decoder : public ::protozero::TypedProtoDecoder</*MAX_FIELD_ID=*/6> {
public:
PackagesList_PackageInfo_Decoder(const uint8_t* data, size_t len) : TypedProtoDecoder(data, len) {}
explicit PackagesList_PackageInfo_Decoder(const std::string& raw) : TypedProtoDecoder(reinterpret_cast<const uint8_t*>(raw.data()), raw.size()) {}
@@ -71550,6 +73534,8 @@ class PackagesList_PackageInfo_Decoder : public ::protozero::TypedProtoDecoder</
bool profileable_from_shell() const { return at<4>().as_bool(); }
bool has_version_code() const { return at<5>().valid(); }
int64_t version_code() const { return at<5>().as_int64(); }
+ bool has_profileable() const { return at<6>().valid(); }
+ bool profileable() const { return at<6>().as_bool(); }
};
class PackagesList_PackageInfo : public ::protozero::Message {
@@ -71561,6 +73547,7 @@ class PackagesList_PackageInfo : public ::protozero::Message {
kDebuggableFieldNumber = 3,
kProfileableFromShellFieldNumber = 4,
kVersionCodeFieldNumber = 5,
+ kProfileableFieldNumber = 6,
};
static constexpr const char* GetName() { return ".perfetto.protos.PackagesList.PackageInfo"; }
@@ -71660,6 +73647,24 @@ class PackagesList_PackageInfo : public ::protozero::Message {
::protozero::proto_utils::ProtoSchemaType::kInt64>
::Append(*this, field_id, value);
}
+
+ using FieldMetadata_Profileable =
+ ::protozero::proto_utils::FieldMetadata<
+ 6,
+ ::protozero::proto_utils::RepetitionType::kNotRepeated,
+ ::protozero::proto_utils::ProtoSchemaType::kBool,
+ bool,
+ PackagesList_PackageInfo>;
+
+ static constexpr FieldMetadata_Profileable kProfileable{};
+ void set_profileable(bool value) {
+ static constexpr uint32_t field_id = FieldMetadata_Profileable::kFieldId;
+ // Call the appropriate protozero::Message::Append(field_id, ...)
+ // method based on the type of the field.
+ ::protozero::internal::FieldWriter<
+ ::protozero::proto_utils::ProtoSchemaType::kBool>
+ ::Append(*this, field_id, value);
+ }
};
} // Namespace.
@@ -71793,6 +73798,151 @@ class PixelModemEvents : public ::protozero::Message {
}
};
+} // Namespace.
+} // Namespace.
+} // Namespace.
+#endif // Include guard.
+// gen_amalgamated begin header: gen/protos/perfetto/trace/android/recovered_trace_info.pbzero.h
+// Autogenerated by the ProtoZero compiler plugin. DO NOT EDIT.
+
+#ifndef PERFETTO_PROTOS_PROTOS_PERFETTO_TRACE_ANDROID_RECOVERED_TRACE_INFO_PROTO_H_
+#define PERFETTO_PROTOS_PROTOS_PERFETTO_TRACE_ANDROID_RECOVERED_TRACE_INFO_PROTO_H_
+
+#include <stddef.h>
+#include <stdint.h>
+
+// gen_amalgamated expanded: #include "perfetto/protozero/field_writer.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/message.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/packed_repeated_fields.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/proto_decoder.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/proto_utils.h"
+
+namespace perfetto {
+namespace protos {
+namespace pbzero {
+namespace perfetto_pbzero_enum_RecoveredTraceInfo {
+enum Reason : int32_t;
+} // namespace perfetto_pbzero_enum_RecoveredTraceInfo
+using RecoveredTraceInfo_Reason = perfetto_pbzero_enum_RecoveredTraceInfo::Reason;
+} // Namespace pbzero.
+} // Namespace protos.
+} // Namespace perfetto.
+
+namespace perfetto {
+namespace protos {
+namespace pbzero {
+
+namespace perfetto_pbzero_enum_RecoveredTraceInfo {
+enum Reason : int32_t {
+ REASON_UNSPECIFIED = 0,
+ REASON_UNEXPECTED_REBOOT = 1,
+};
+} // namespace perfetto_pbzero_enum_RecoveredTraceInfo
+using RecoveredTraceInfo_Reason = perfetto_pbzero_enum_RecoveredTraceInfo::Reason;
+
+
+constexpr RecoveredTraceInfo_Reason RecoveredTraceInfo_Reason_MIN = RecoveredTraceInfo_Reason::REASON_UNSPECIFIED;
+constexpr RecoveredTraceInfo_Reason RecoveredTraceInfo_Reason_MAX = RecoveredTraceInfo_Reason::REASON_UNEXPECTED_REBOOT;
+
+
+PERFETTO_PROTOZERO_CONSTEXPR14_OR_INLINE
+const char* RecoveredTraceInfo_Reason_Name(::perfetto::protos::pbzero::RecoveredTraceInfo_Reason value) {
+ switch (value) {
+ case ::perfetto::protos::pbzero::RecoveredTraceInfo_Reason::REASON_UNSPECIFIED:
+ return "REASON_UNSPECIFIED";
+
+ case ::perfetto::protos::pbzero::RecoveredTraceInfo_Reason::REASON_UNEXPECTED_REBOOT:
+ return "REASON_UNEXPECTED_REBOOT";
+ }
+ return "PBZERO_UNKNOWN_ENUM_VALUE";
+}
+
+class RecoveredTraceInfo_Decoder : public ::protozero::TypedProtoDecoder</*MAX_FIELD_ID=*/3> {
+ public:
+ RecoveredTraceInfo_Decoder(const uint8_t* data, size_t len) : TypedProtoDecoder(data, len) {}
+ explicit RecoveredTraceInfo_Decoder(const std::string& raw) : TypedProtoDecoder(reinterpret_cast<const uint8_t*>(raw.data()), raw.size()) {}
+ explicit RecoveredTraceInfo_Decoder(const ::protozero::ConstBytes& raw) : TypedProtoDecoder(raw.data, raw.size) {}
+ bool has_reason() const { return at<1>().valid(); }
+ int32_t reason() const { return at<1>().as_int32(); }
+ bool has_original_file_size_bytes() const { return at<2>().valid(); }
+ uint64_t original_file_size_bytes() const { return at<2>().as_uint64(); }
+ bool has_bytes_truncated() const { return at<3>().valid(); }
+ uint64_t bytes_truncated() const { return at<3>().as_uint64(); }
+};
+
+class RecoveredTraceInfo : public ::protozero::Message {
+ public:
+ using Decoder = RecoveredTraceInfo_Decoder;
+ enum : int32_t {
+ kReasonFieldNumber = 1,
+ kOriginalFileSizeBytesFieldNumber = 2,
+ kBytesTruncatedFieldNumber = 3,
+ };
+ static constexpr const char* GetName() { return ".perfetto.protos.RecoveredTraceInfo"; }
+
+
+ using Reason = ::perfetto::protos::pbzero::RecoveredTraceInfo_Reason;
+ static inline const char* Reason_Name(Reason value) {
+ return ::perfetto::protos::pbzero::RecoveredTraceInfo_Reason_Name(value);
+ }
+ static inline const Reason REASON_UNSPECIFIED = Reason::REASON_UNSPECIFIED;
+ static inline const Reason REASON_UNEXPECTED_REBOOT = Reason::REASON_UNEXPECTED_REBOOT;
+
+ using FieldMetadata_Reason =
+ ::protozero::proto_utils::FieldMetadata<
+ 1,
+ ::protozero::proto_utils::RepetitionType::kNotRepeated,
+ ::protozero::proto_utils::ProtoSchemaType::kEnum,
+ RecoveredTraceInfo_Reason,
+ RecoveredTraceInfo>;
+
+ static constexpr FieldMetadata_Reason kReason{};
+ void set_reason(RecoveredTraceInfo_Reason value) {
+ static constexpr uint32_t field_id = FieldMetadata_Reason::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_OriginalFileSizeBytes =
+ ::protozero::proto_utils::FieldMetadata<
+ 2,
+ ::protozero::proto_utils::RepetitionType::kNotRepeated,
+ ::protozero::proto_utils::ProtoSchemaType::kUint64,
+ uint64_t,
+ RecoveredTraceInfo>;
+
+ static constexpr FieldMetadata_OriginalFileSizeBytes kOriginalFileSizeBytes{};
+ void set_original_file_size_bytes(uint64_t value) {
+ static constexpr uint32_t field_id = FieldMetadata_OriginalFileSizeBytes::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_BytesTruncated =
+ ::protozero::proto_utils::FieldMetadata<
+ 3,
+ ::protozero::proto_utils::RepetitionType::kNotRepeated,
+ ::protozero::proto_utils::ProtoSchemaType::kUint64,
+ uint64_t,
+ RecoveredTraceInfo>;
+
+ static constexpr FieldMetadata_BytesTruncated kBytesTruncated{};
+ void set_bytes_truncated(uint64_t value) {
+ static constexpr uint32_t field_id = FieldMetadata_BytesTruncated::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.
} // Namespace.
} // Namespace.
@@ -80223,6 +82373,8 @@ class KvmVcpuWakeupFtraceEvent;
class KvmWfxArm64FtraceEvent;
class LocalTimerEntryFtraceEvent;
class LocalTimerExitFtraceEvent;
+class LongIrqFtraceEvent;
+class LongSoftirqFtraceEvent;
class LowmemoryKillFtraceEvent;
class LwisTracingMarkWriteFtraceEvent;
class MaliGpuPowerStateFtraceEvent;
@@ -80446,7 +82598,7 @@ namespace perfetto {
namespace protos {
namespace pbzero {
-class FtraceEvent_Decoder : public ::protozero::TypedProtoDecoder</*MAX_FIELD_ID=*/615> {
+class FtraceEvent_Decoder : public ::protozero::TypedProtoDecoder</*MAX_FIELD_ID=*/617> {
public:
FtraceEvent_Decoder(const uint8_t* data, size_t len) : TypedProtoDecoder(data, len) {}
explicit FtraceEvent_Decoder(const std::string& raw) : TypedProtoDecoder(reinterpret_cast<const uint8_t*>(raw.data()), raw.size()) {}
@@ -81645,6 +83797,10 @@ class FtraceEvent_Decoder : public ::protozero::TypedProtoDecoder</*MAX_FIELD_ID
::protozero::ConstBytes psci_domain_idle_exit() const { return at<614>().as_bytes(); }
bool has_psci_domain_idle_enter() const { return at<615>().valid(); }
::protozero::ConstBytes psci_domain_idle_enter() const { return at<615>().as_bytes(); }
+ bool has_long_irq() const { return at<616>().valid(); }
+ ::protozero::ConstBytes long_irq() const { return at<616>().as_bytes(); }
+ bool has_long_softirq() const { return at<617>().valid(); }
+ ::protozero::ConstBytes long_softirq() const { return at<617>().as_bytes(); }
};
class FtraceEvent : public ::protozero::Message {
@@ -82248,6 +84404,8 @@ class FtraceEvent : public ::protozero::Message {
kDpuDispDpuLineUnderrunFieldNumber = 613,
kPsciDomainIdleExitFieldNumber = 614,
kPsciDomainIdleEnterFieldNumber = 615,
+ kLongIrqFieldNumber = 616,
+ kLongSoftirqFieldNumber = 617,
};
static constexpr const char* GetName() { return ".perfetto.protos.FtraceEvent"; }
@@ -90621,6 +92779,34 @@ class FtraceEvent : public ::protozero::Message {
return BeginNestedMessage<T>(615);
}
+
+ using FieldMetadata_LongIrq =
+ ::protozero::proto_utils::FieldMetadata<
+ 616,
+ ::protozero::proto_utils::RepetitionType::kNotRepeated,
+ ::protozero::proto_utils::ProtoSchemaType::kMessage,
+ LongIrqFtraceEvent,
+ FtraceEvent>;
+
+ static constexpr FieldMetadata_LongIrq kLongIrq{};
+ template <typename T = LongIrqFtraceEvent> T* set_long_irq() {
+ return BeginNestedMessage<T>(616);
+ }
+
+
+ using FieldMetadata_LongSoftirq =
+ ::protozero::proto_utils::FieldMetadata<
+ 617,
+ ::protozero::proto_utils::RepetitionType::kNotRepeated,
+ ::protozero::proto_utils::ProtoSchemaType::kMessage,
+ LongSoftirqFtraceEvent,
+ FtraceEvent>;
+
+ static constexpr FieldMetadata_LongSoftirq kLongSoftirq{};
+ template <typename T = LongSoftirqFtraceEvent> T* set_long_softirq() {
+ return BeginNestedMessage<T>(617);
+ }
+
};
} // Namespace.
@@ -145757,6 +147943,188 @@ class SchedSwitchWithCtrsFtraceEvent : public ::protozero::Message {
}
};
+} // Namespace.
+} // Namespace.
+} // Namespace.
+#endif // Include guard.
+// gen_amalgamated begin header: gen/protos/perfetto/trace/ftrace/pixel_metrics.pbzero.h
+// Autogenerated by the ProtoZero compiler plugin. DO NOT EDIT.
+
+#ifndef PERFETTO_PROTOS_PROTOS_PERFETTO_TRACE_FTRACE_PIXEL_METRICS_PROTO_H_
+#define PERFETTO_PROTOS_PROTOS_PERFETTO_TRACE_FTRACE_PIXEL_METRICS_PROTO_H_
+
+#include <stddef.h>
+#include <stdint.h>
+
+// gen_amalgamated expanded: #include "perfetto/protozero/field_writer.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/message.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/packed_repeated_fields.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/proto_decoder.h"
+// gen_amalgamated expanded: #include "perfetto/protozero/proto_utils.h"
+
+
+namespace perfetto {
+namespace protos {
+namespace pbzero {
+
+class LongSoftirqFtraceEvent_Decoder : public ::protozero::TypedProtoDecoder</*MAX_FIELD_ID=*/3> {
+ public:
+ LongSoftirqFtraceEvent_Decoder(const uint8_t* data, size_t len) : TypedProtoDecoder(data, len) {}
+ explicit LongSoftirqFtraceEvent_Decoder(const std::string& raw) : TypedProtoDecoder(reinterpret_cast<const uint8_t*>(raw.data()), raw.size()) {}
+ explicit LongSoftirqFtraceEvent_Decoder(const ::protozero::ConstBytes& raw) : TypedProtoDecoder(raw.data, raw.size) {}
+ bool has_vec_nr() const { return at<1>().valid(); }
+ int32_t vec_nr() const { return at<1>().as_int32(); }
+ bool has_latency() const { return at<2>().valid(); }
+ uint32_t latency() const { return at<2>().as_uint32(); }
+ bool has_count() const { return at<3>().valid(); }
+ uint32_t count() const { return at<3>().as_uint32(); }
+};
+
+class LongSoftirqFtraceEvent : public ::protozero::Message {
+ public:
+ using Decoder = LongSoftirqFtraceEvent_Decoder;
+ enum : int32_t {
+ kVecNrFieldNumber = 1,
+ kLatencyFieldNumber = 2,
+ kCountFieldNumber = 3,
+ };
+ static constexpr const char* GetName() { return ".perfetto.protos.LongSoftirqFtraceEvent"; }
+
+
+ using FieldMetadata_VecNr =
+ ::protozero::proto_utils::FieldMetadata<
+ 1,
+ ::protozero::proto_utils::RepetitionType::kNotRepeated,
+ ::protozero::proto_utils::ProtoSchemaType::kInt32,
+ int32_t,
+ LongSoftirqFtraceEvent>;
+
+ static constexpr FieldMetadata_VecNr kVecNr{};
+ void set_vec_nr(int32_t value) {
+ static constexpr uint32_t field_id = FieldMetadata_VecNr::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_Latency =
+ ::protozero::proto_utils::FieldMetadata<
+ 2,
+ ::protozero::proto_utils::RepetitionType::kNotRepeated,
+ ::protozero::proto_utils::ProtoSchemaType::kUint32,
+ uint32_t,
+ LongSoftirqFtraceEvent>;
+
+ static constexpr FieldMetadata_Latency kLatency{};
+ void set_latency(uint32_t value) {
+ static constexpr uint32_t field_id = FieldMetadata_Latency::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_Count =
+ ::protozero::proto_utils::FieldMetadata<
+ 3,
+ ::protozero::proto_utils::RepetitionType::kNotRepeated,
+ ::protozero::proto_utils::ProtoSchemaType::kUint32,
+ uint32_t,
+ LongSoftirqFtraceEvent>;
+
+ static constexpr FieldMetadata_Count kCount{};
+ void set_count(uint32_t value) {
+ static constexpr uint32_t field_id = FieldMetadata_Count::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);
+ }
+};
+
+class LongIrqFtraceEvent_Decoder : public ::protozero::TypedProtoDecoder</*MAX_FIELD_ID=*/3> {
+ public:
+ LongIrqFtraceEvent_Decoder(const uint8_t* data, size_t len) : TypedProtoDecoder(data, len) {}
+ explicit LongIrqFtraceEvent_Decoder(const std::string& raw) : TypedProtoDecoder(reinterpret_cast<const uint8_t*>(raw.data()), raw.size()) {}
+ explicit LongIrqFtraceEvent_Decoder(const ::protozero::ConstBytes& raw) : TypedProtoDecoder(raw.data, raw.size) {}
+ bool has_irq() const { return at<1>().valid(); }
+ int32_t irq() const { return at<1>().as_int32(); }
+ bool has_latency() const { return at<2>().valid(); }
+ uint32_t latency() const { return at<2>().as_uint32(); }
+ bool has_count() const { return at<3>().valid(); }
+ uint32_t count() const { return at<3>().as_uint32(); }
+};
+
+class LongIrqFtraceEvent : public ::protozero::Message {
+ public:
+ using Decoder = LongIrqFtraceEvent_Decoder;
+ enum : int32_t {
+ kIrqFieldNumber = 1,
+ kLatencyFieldNumber = 2,
+ kCountFieldNumber = 3,
+ };
+ static constexpr const char* GetName() { return ".perfetto.protos.LongIrqFtraceEvent"; }
+
+
+ using FieldMetadata_Irq =
+ ::protozero::proto_utils::FieldMetadata<
+ 1,
+ ::protozero::proto_utils::RepetitionType::kNotRepeated,
+ ::protozero::proto_utils::ProtoSchemaType::kInt32,
+ int32_t,
+ LongIrqFtraceEvent>;
+
+ static constexpr FieldMetadata_Irq kIrq{};
+ void set_irq(int32_t value) {
+ static constexpr uint32_t field_id = FieldMetadata_Irq::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_Latency =
+ ::protozero::proto_utils::FieldMetadata<
+ 2,
+ ::protozero::proto_utils::RepetitionType::kNotRepeated,
+ ::protozero::proto_utils::ProtoSchemaType::kUint32,
+ uint32_t,
+ LongIrqFtraceEvent>;
+
+ static constexpr FieldMetadata_Latency kLatency{};
+ void set_latency(uint32_t value) {
+ static constexpr uint32_t field_id = FieldMetadata_Latency::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_Count =
+ ::protozero::proto_utils::FieldMetadata<
+ 3,
+ ::protozero::proto_utils::RepetitionType::kNotRepeated,
+ ::protozero::proto_utils::ProtoSchemaType::kUint32,
+ uint32_t,
+ LongIrqFtraceEvent>;
+
+ static constexpr FieldMetadata_Count kCount{};
+ void set_count(uint32_t value) {
+ static constexpr uint32_t field_id = FieldMetadata_Count::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.
} // Namespace.
} // Namespace.
@@ -148206,7 +150574,7 @@ class SchedGroupTrackerFtraceEvent : public ::protozero::Message {
}
};
-class SchedWakeupTaskAttrFtraceEvent_Decoder : public ::protozero::TypedProtoDecoder</*MAX_FIELD_ID=*/5> {
+class SchedWakeupTaskAttrFtraceEvent_Decoder : public ::protozero::TypedProtoDecoder</*MAX_FIELD_ID=*/9> {
public:
SchedWakeupTaskAttrFtraceEvent_Decoder(const uint8_t* data, size_t len) : TypedProtoDecoder(data, len) {}
explicit SchedWakeupTaskAttrFtraceEvent_Decoder(const std::string& raw) : TypedProtoDecoder(reinterpret_cast<const uint8_t*>(raw.data()), raw.size()) {}
@@ -148221,6 +150589,14 @@ class SchedWakeupTaskAttrFtraceEvent_Decoder : public ::protozero::TypedProtoDec
uint64_t uclamp_min() const { return at<4>().as_uint64(); }
bool has_vruntime() const { return at<5>().valid(); }
uint64_t vruntime() const { return at<5>().as_uint64(); }
+ bool has_sched_qos_user_defined_flag() const { return at<6>().valid(); }
+ uint64_t sched_qos_user_defined_flag() const { return at<6>().as_uint64(); }
+ bool has_rampup_multiplier() const { return at<7>().valid(); }
+ uint32_t rampup_multiplier() const { return at<7>().as_uint32(); }
+ bool has_effect_rampup_multiplier() const { return at<8>().valid(); }
+ uint32_t effect_rampup_multiplier() const { return at<8>().as_uint32(); }
+ bool has_tag_nice() const { return at<9>().valid(); }
+ int32_t tag_nice() const { return at<9>().as_int32(); }
};
class SchedWakeupTaskAttrFtraceEvent : public ::protozero::Message {
@@ -148232,6 +150608,10 @@ class SchedWakeupTaskAttrFtraceEvent : public ::protozero::Message {
kTaskUtilFieldNumber = 3,
kUclampMinFieldNumber = 4,
kVruntimeFieldNumber = 5,
+ kSchedQosUserDefinedFlagFieldNumber = 6,
+ kRampupMultiplierFieldNumber = 7,
+ kEffectRampupMultiplierFieldNumber = 8,
+ kTagNiceFieldNumber = 9,
};
static constexpr const char* GetName() { return ".perfetto.protos.SchedWakeupTaskAttrFtraceEvent"; }
@@ -148325,6 +150705,78 @@ class SchedWakeupTaskAttrFtraceEvent : public ::protozero::Message {
::protozero::proto_utils::ProtoSchemaType::kUint64>
::Append(*this, field_id, value);
}
+
+ using FieldMetadata_SchedQosUserDefinedFlag =
+ ::protozero::proto_utils::FieldMetadata<
+ 6,
+ ::protozero::proto_utils::RepetitionType::kNotRepeated,
+ ::protozero::proto_utils::ProtoSchemaType::kUint64,
+ uint64_t,
+ SchedWakeupTaskAttrFtraceEvent>;
+
+ static constexpr FieldMetadata_SchedQosUserDefinedFlag kSchedQosUserDefinedFlag{};
+ void set_sched_qos_user_defined_flag(uint64_t value) {
+ static constexpr uint32_t field_id = FieldMetadata_SchedQosUserDefinedFlag::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_RampupMultiplier =
+ ::protozero::proto_utils::FieldMetadata<
+ 7,
+ ::protozero::proto_utils::RepetitionType::kNotRepeated,
+ ::protozero::proto_utils::ProtoSchemaType::kUint32,
+ uint32_t,
+ SchedWakeupTaskAttrFtraceEvent>;
+
+ static constexpr FieldMetadata_RampupMultiplier kRampupMultiplier{};
+ void set_rampup_multiplier(uint32_t value) {
+ static constexpr uint32_t field_id = FieldMetadata_RampupMultiplier::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_EffectRampupMultiplier =
+ ::protozero::proto_utils::FieldMetadata<
+ 8,
+ ::protozero::proto_utils::RepetitionType::kNotRepeated,
+ ::protozero::proto_utils::ProtoSchemaType::kUint32,
+ uint32_t,
+ SchedWakeupTaskAttrFtraceEvent>;
+
+ static constexpr FieldMetadata_EffectRampupMultiplier kEffectRampupMultiplier{};
+ void set_effect_rampup_multiplier(uint32_t value) {
+ static constexpr uint32_t field_id = FieldMetadata_EffectRampupMultiplier::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_TagNice =
+ ::protozero::proto_utils::FieldMetadata<
+ 9,
+ ::protozero::proto_utils::RepetitionType::kNotRepeated,
+ ::protozero::proto_utils::ProtoSchemaType::kInt32,
+ int32_t,
+ SchedWakeupTaskAttrFtraceEvent>;
+
+ static constexpr FieldMetadata_TagNice kTagNice{};
+ void set_tag_nice(int32_t value) {
+ static constexpr uint32_t field_id = FieldMetadata_TagNice::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);
+ }
};
class SchedMigrateTaskFtraceEvent_Decoder : public ::protozero::TypedProtoDecoder</*MAX_FIELD_ID=*/7> {
@@ -165426,6 +167878,8 @@ namespace perfetto {
namespace protos {
namespace pbzero {
class ObfuscatedClass;
+class ObfuscatedClass_MergedClass;
+class ObfuscatedClass_MergedClasses;
class ObfuscatedMember;
} // Namespace pbzero.
} // Namespace protos.
@@ -165516,7 +167970,7 @@ class DeobfuscationMapping : public ::protozero::Message {
};
-class ObfuscatedClass_Decoder : public ::protozero::TypedProtoDecoder</*MAX_FIELD_ID=*/4> {
+class ObfuscatedClass_Decoder : public ::protozero::TypedProtoDecoder</*MAX_FIELD_ID=*/5> {
public:
ObfuscatedClass_Decoder(const uint8_t* data, size_t len) : TypedProtoDecoder(data, len) {}
explicit ObfuscatedClass_Decoder(const std::string& raw) : TypedProtoDecoder(reinterpret_cast<const uint8_t*>(raw.data()), raw.size()) {}
@@ -165529,6 +167983,8 @@ class ObfuscatedClass_Decoder : public ::protozero::TypedProtoDecoder</*MAX_FIEL
::protozero::RepeatedFieldIterator<::protozero::ConstBytes> obfuscated_members() const { return GetRepeated<::protozero::ConstBytes>(3); }
bool has_obfuscated_methods() const { return at<4>().valid(); }
::protozero::RepeatedFieldIterator<::protozero::ConstBytes> obfuscated_methods() const { return GetRepeated<::protozero::ConstBytes>(4); }
+ bool has_merged_classes() const { return at<5>().valid(); }
+ ::protozero::ConstBytes merged_classes() const { return at<5>().as_bytes(); }
};
class ObfuscatedClass : public ::protozero::Message {
@@ -165539,9 +167995,12 @@ class ObfuscatedClass : public ::protozero::Message {
kDeobfuscatedNameFieldNumber = 2,
kObfuscatedMembersFieldNumber = 3,
kObfuscatedMethodsFieldNumber = 4,
+ kMergedClassesFieldNumber = 5,
};
static constexpr const char* GetName() { return ".perfetto.protos.ObfuscatedClass"; }
+ using MergedClass = ::perfetto::protos::pbzero::ObfuscatedClass_MergedClass;
+ using MergedClasses = ::perfetto::protos::pbzero::ObfuscatedClass_MergedClasses;
using FieldMetadata_ObfuscatedName =
::protozero::proto_utils::FieldMetadata<
@@ -165618,6 +168077,182 @@ class ObfuscatedClass : public ::protozero::Message {
return BeginNestedMessage<T>(4);
}
+
+ using FieldMetadata_MergedClasses =
+ ::protozero::proto_utils::FieldMetadata<
+ 5,
+ ::protozero::proto_utils::RepetitionType::kNotRepeated,
+ ::protozero::proto_utils::ProtoSchemaType::kMessage,
+ ObfuscatedClass_MergedClasses,
+ ObfuscatedClass>;
+
+ static constexpr FieldMetadata_MergedClasses kMergedClasses{};
+ template <typename T = ObfuscatedClass_MergedClasses> T* set_merged_classes() {
+ return BeginNestedMessage<T>(5);
+ }
+
+};
+
+class ObfuscatedClass_MergedClasses_Decoder : public ::protozero::TypedProtoDecoder</*MAX_FIELD_ID=*/3> {
+ public:
+ ObfuscatedClass_MergedClasses_Decoder(const uint8_t* data, size_t len) : TypedProtoDecoder(data, len) {}
+ explicit ObfuscatedClass_MergedClasses_Decoder(const std::string& raw) : TypedProtoDecoder(reinterpret_cast<const uint8_t*>(raw.data()), raw.size()) {}
+ explicit ObfuscatedClass_MergedClasses_Decoder(const ::protozero::ConstBytes& raw) : TypedProtoDecoder(raw.data, raw.size) {}
+ bool has_class_id_field_name() const { return at<1>().valid(); }
+ ::protozero::ConstChars class_id_field_name() const { return at<1>().as_string(); }
+ bool has_merged_classes() const { return at<2>().valid(); }
+ ::protozero::RepeatedFieldIterator<::protozero::ConstBytes> merged_classes() const { return GetRepeated<::protozero::ConstBytes>(2); }
+ bool has_unknown_merged_classes() const { return at<3>().valid(); }
+ bool unknown_merged_classes() const { return at<3>().as_bool(); }
+};
+
+class ObfuscatedClass_MergedClasses : public ::protozero::Message {
+ public:
+ using Decoder = ObfuscatedClass_MergedClasses_Decoder;
+ enum : int32_t {
+ kClassIdFieldNameFieldNumber = 1,
+ kMergedClassesFieldNumber = 2,
+ kUnknownMergedClassesFieldNumber = 3,
+ };
+ static constexpr const char* GetName() { return ".perfetto.protos.ObfuscatedClass.MergedClasses"; }
+
+
+ using FieldMetadata_ClassIdFieldName =
+ ::protozero::proto_utils::FieldMetadata<
+ 1,
+ ::protozero::proto_utils::RepetitionType::kNotRepeated,
+ ::protozero::proto_utils::ProtoSchemaType::kString,
+ std::string,
+ ObfuscatedClass_MergedClasses>;
+
+ static constexpr FieldMetadata_ClassIdFieldName kClassIdFieldName{};
+ void set_class_id_field_name(const char* data, size_t size) {
+ AppendBytes(FieldMetadata_ClassIdFieldName::kFieldId, data, size);
+ }
+ void set_class_id_field_name(::protozero::ConstChars chars) {
+ AppendBytes(FieldMetadata_ClassIdFieldName::kFieldId, chars.data, chars.size);
+ }
+ void set_class_id_field_name(std::string value) {
+ static constexpr uint32_t field_id = FieldMetadata_ClassIdFieldName::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_MergedClasses =
+ ::protozero::proto_utils::FieldMetadata<
+ 2,
+ ::protozero::proto_utils::RepetitionType::kRepeatedNotPacked,
+ ::protozero::proto_utils::ProtoSchemaType::kMessage,
+ ObfuscatedClass_MergedClass,
+ ObfuscatedClass_MergedClasses>;
+
+ static constexpr FieldMetadata_MergedClasses kMergedClasses{};
+ template <typename T = ObfuscatedClass_MergedClass> T* add_merged_classes() {
+ return BeginNestedMessage<T>(2);
+ }
+
+
+ using FieldMetadata_UnknownMergedClasses =
+ ::protozero::proto_utils::FieldMetadata<
+ 3,
+ ::protozero::proto_utils::RepetitionType::kNotRepeated,
+ ::protozero::proto_utils::ProtoSchemaType::kBool,
+ bool,
+ ObfuscatedClass_MergedClasses>;
+
+ static constexpr FieldMetadata_UnknownMergedClasses kUnknownMergedClasses{};
+ void set_unknown_merged_classes(bool value) {
+ static constexpr uint32_t field_id = FieldMetadata_UnknownMergedClasses::kFieldId;
+ // Call the appropriate protozero::Message::Append(field_id, ...)
+ // method based on the type of the field.
+ ::protozero::internal::FieldWriter<
+ ::protozero::proto_utils::ProtoSchemaType::kBool>
+ ::Append(*this, field_id, value);
+ }
+};
+
+class ObfuscatedClass_MergedClass_Decoder : public ::protozero::TypedProtoDecoder</*MAX_FIELD_ID=*/3> {
+ public:
+ ObfuscatedClass_MergedClass_Decoder(const uint8_t* data, size_t len) : TypedProtoDecoder(data, len) {}
+ explicit ObfuscatedClass_MergedClass_Decoder(const std::string& raw) : TypedProtoDecoder(reinterpret_cast<const uint8_t*>(raw.data()), raw.size()) {}
+ explicit ObfuscatedClass_MergedClass_Decoder(const ::protozero::ConstBytes& raw) : TypedProtoDecoder(raw.data, raw.size) {}
+ bool has_name() const { return at<1>().valid(); }
+ ::protozero::ConstChars name() const { return at<1>().as_string(); }
+ bool has_class_id() const { return at<2>().valid(); }
+ int32_t class_id() const { return at<2>().as_int32(); }
+ bool has_merged_classes() const { return at<3>().valid(); }
+ ::protozero::ConstBytes merged_classes() const { return at<3>().as_bytes(); }
+};
+
+class ObfuscatedClass_MergedClass : public ::protozero::Message {
+ public:
+ using Decoder = ObfuscatedClass_MergedClass_Decoder;
+ enum : int32_t {
+ kNameFieldNumber = 1,
+ kClassIdFieldNumber = 2,
+ kMergedClassesFieldNumber = 3,
+ };
+ static constexpr const char* GetName() { return ".perfetto.protos.ObfuscatedClass.MergedClass"; }
+
+
+ using FieldMetadata_Name =
+ ::protozero::proto_utils::FieldMetadata<
+ 1,
+ ::protozero::proto_utils::RepetitionType::kNotRepeated,
+ ::protozero::proto_utils::ProtoSchemaType::kString,
+ std::string,
+ ObfuscatedClass_MergedClass>;
+
+ static constexpr FieldMetadata_Name kName{};
+ void set_name(const char* data, size_t size) {
+ AppendBytes(FieldMetadata_Name::kFieldId, data, size);
+ }
+ void set_name(::protozero::ConstChars chars) {
+ AppendBytes(FieldMetadata_Name::kFieldId, chars.data, chars.size);
+ }
+ void set_name(std::string value) {
+ static constexpr uint32_t field_id = FieldMetadata_Name::kFieldId;
+ // Call the appropriate protozero::Message::Append(field_id, ...)
+ // method based on the type of the field.
+ ::protozero::internal::FieldWriter<
+ ::protozero::proto_utils::ProtoSchemaType::kString>
+ ::Append(*this, field_id, value);
+ }
+
+ using FieldMetadata_ClassId =
+ ::protozero::proto_utils::FieldMetadata<
+ 2,
+ ::protozero::proto_utils::RepetitionType::kNotRepeated,
+ ::protozero::proto_utils::ProtoSchemaType::kInt32,
+ int32_t,
+ ObfuscatedClass_MergedClass>;
+
+ static constexpr FieldMetadata_ClassId kClassId{};
+ void set_class_id(int32_t value) {
+ static constexpr uint32_t field_id = FieldMetadata_ClassId::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_MergedClasses =
+ ::protozero::proto_utils::FieldMetadata<
+ 3,
+ ::protozero::proto_utils::RepetitionType::kNotRepeated,
+ ::protozero::proto_utils::ProtoSchemaType::kMessage,
+ ObfuscatedClass_MergedClasses,
+ ObfuscatedClass_MergedClass>;
+
+ static constexpr FieldMetadata_MergedClasses kMergedClasses{};
+ template <typename T = ObfuscatedClass_MergedClasses> T* set_merged_classes() {
+ return BeginNestedMessage<T>(3);
+ }
+
};
class ObfuscatedMember_Decoder : public ::protozero::TypedProtoDecoder</*MAX_FIELD_ID=*/6> {
@@ -190398,14 +193033,6 @@ class TracingServiceState;
class TracingServiceState_TracingSession;
class TracingServiceState_DataSource;
class DataSourceDescriptor;
-class VmProgram;
-class VmInstruction;
-class VmOpDel;
-class VmOpSet;
-class VmOpMerge;
-class VmOpRegLoad;
-class VmOpSelect;
-class VmOpSelect_PathComponent;
class TracingServiceState_Producer;
class QueryServiceStateRequest;
class ObserveEventsResponse;
@@ -190449,6 +193076,8 @@ class InterceptorConfig;
class ConsoleConfig;
class ChromeConfig;
class SystemInfoConfig;
+class DataSourceConfig_ExperimentalTracingV2Config;
+class DataSourceConfig_ExperimentalTracingV2Config_ChunkSizeOption;
class ProtoVmConfig;
class TraceConfig_BufferConfig;
class AttachRequest;
@@ -190470,8 +193099,6 @@ class StartTracingRequest;
class EnableTracingResponse;
class EnableTracingRequest;
enum ObservableEvents_Type : int;
-enum VmInstruction_AbortLevel : int;
-enum VmCursorEnum : int;
enum ObservableEvents_DataSourceInstanceState : int;
enum TraceStats_FinalFlushOutcome : int;
enum TraceConfig_LockdownModeOperation : int;
@@ -191663,6 +194290,8 @@ class InterceptorConfig;
class ConsoleConfig;
class ChromeConfig;
class SystemInfoConfig;
+class DataSourceConfig_ExperimentalTracingV2Config;
+class DataSourceConfig_ExperimentalTracingV2Config_ChunkSizeOption;
class ProtoVmConfig;
class PriorityBoostConfig;
class GetAsyncCommandResponse_SetupDataSource;
@@ -191684,25 +194313,20 @@ class UnregisterDataSourceRequest;
class UpdateDataSourceResponse;
class UpdateDataSourceRequest;
class DataSourceDescriptor;
-class VmProgram;
-class VmInstruction;
-class VmOpDel;
-class VmOpSet;
-class VmOpMerge;
-class VmOpRegLoad;
-class VmOpSelect;
-class VmOpSelect_PathComponent;
class RegisterDataSourceResponse;
class RegisterDataSourceRequest;
+class DrainV2RingBufferResponse;
+class DrainV2RingBufferRequest;
+class AttachV2RingBufferResponse;
+class AttachV2RingBufferRequest;
class InitializeConnectionResponse;
class InitializeConnectionRequest;
+enum ProtocolAbiVersion : int;
enum DataSourceConfig_SessionInitiator : int;
enum DataSourceConfig_BufferExhaustedPolicy : int;
enum ConsoleConfig_Output : int;
enum ChromeConfig_ClientPriority : int;
enum PriorityBoostConfig_BoostPolicy : int;
-enum VmInstruction_AbortLevel : int;
-enum VmCursorEnum : int;
enum InitializeConnectionRequest_ProducerSMBScrapingMode : int;
} // namespace perfetto
} // namespace protos
@@ -191715,6 +194339,11 @@ class Message;
namespace perfetto {
namespace protos {
namespace gen {
+enum ProtocolAbiVersion : int {
+ PROTOCOL_ABI_VERSION_UNSPECIFIED = 0,
+ PROTOCOL_ABI_VERSION_V1 = 1,
+ PROTOCOL_ABI_VERSION_V2 = 2,
+};
enum InitializeConnectionRequest_ProducerSMBScrapingMode : int {
InitializeConnectionRequest_ProducerSMBScrapingMode_SMB_SCRAPING_UNSPECIFIED = 0,
InitializeConnectionRequest_ProducerSMBScrapingMode_SMB_SCRAPING_ENABLED = 1,
@@ -192681,12 +195310,135 @@ class PERFETTO_EXPORT_COMPONENT RegisterDataSourceRequest : public ::protozero::
};
+class PERFETTO_EXPORT_COMPONENT DrainV2RingBufferResponse : public ::protozero::CppMessageObj {
+ public:
+ enum FieldNumbers {
+ };
+
+ DrainV2RingBufferResponse();
+ ~DrainV2RingBufferResponse() override;
+ DrainV2RingBufferResponse(DrainV2RingBufferResponse&&) noexcept;
+ DrainV2RingBufferResponse& operator=(DrainV2RingBufferResponse&&);
+ DrainV2RingBufferResponse(const DrainV2RingBufferResponse&);
+ DrainV2RingBufferResponse& operator=(const DrainV2RingBufferResponse&);
+ bool operator==(const DrainV2RingBufferResponse&) const;
+ bool operator!=(const DrainV2RingBufferResponse& other) const { return !(*this == other); }
+
+ bool ParseFromArray(const void*, size_t) override;
+ std::string SerializeAsString() const override;
+ std::vector<uint8_t> SerializeAsArray() const override;
+ void Serialize(::protozero::Message*) const;
+
+ private:
+
+ // Allows to preserve unknown protobuf fields for compatibility
+ // with future versions of .proto files.
+ std::string unknown_fields_;
+
+ std::bitset<2> _has_field_{};
+};
+
+
+class PERFETTO_EXPORT_COMPONENT DrainV2RingBufferRequest : public ::protozero::CppMessageObj {
+ public:
+ enum FieldNumbers {
+ };
+
+ DrainV2RingBufferRequest();
+ ~DrainV2RingBufferRequest() override;
+ DrainV2RingBufferRequest(DrainV2RingBufferRequest&&) noexcept;
+ DrainV2RingBufferRequest& operator=(DrainV2RingBufferRequest&&);
+ DrainV2RingBufferRequest(const DrainV2RingBufferRequest&);
+ DrainV2RingBufferRequest& operator=(const DrainV2RingBufferRequest&);
+ bool operator==(const DrainV2RingBufferRequest&) const;
+ bool operator!=(const DrainV2RingBufferRequest& other) const { return !(*this == other); }
+
+ bool ParseFromArray(const void*, size_t) override;
+ std::string SerializeAsString() const override;
+ std::vector<uint8_t> SerializeAsArray() const override;
+ void Serialize(::protozero::Message*) const;
+
+ private:
+
+ // Allows to preserve unknown protobuf fields for compatibility
+ // with future versions of .proto files.
+ std::string unknown_fields_;
+
+ std::bitset<2> _has_field_{};
+};
+
+
+class PERFETTO_EXPORT_COMPONENT AttachV2RingBufferResponse : public ::protozero::CppMessageObj {
+ public:
+ enum FieldNumbers {
+ };
+
+ AttachV2RingBufferResponse();
+ ~AttachV2RingBufferResponse() override;
+ AttachV2RingBufferResponse(AttachV2RingBufferResponse&&) noexcept;
+ AttachV2RingBufferResponse& operator=(AttachV2RingBufferResponse&&);
+ AttachV2RingBufferResponse(const AttachV2RingBufferResponse&);
+ AttachV2RingBufferResponse& operator=(const AttachV2RingBufferResponse&);
+ bool operator==(const AttachV2RingBufferResponse&) const;
+ bool operator!=(const AttachV2RingBufferResponse& other) const { return !(*this == other); }
+
+ bool ParseFromArray(const void*, size_t) override;
+ std::string SerializeAsString() const override;
+ std::vector<uint8_t> SerializeAsArray() const override;
+ void Serialize(::protozero::Message*) const;
+
+ private:
+
+ // Allows to preserve unknown protobuf fields for compatibility
+ // with future versions of .proto files.
+ std::string unknown_fields_;
+
+ std::bitset<2> _has_field_{};
+};
+
+
+class PERFETTO_EXPORT_COMPONENT AttachV2RingBufferRequest : public ::protozero::CppMessageObj {
+ public:
+ enum FieldNumbers {
+ kChunkSizeBytesFieldNumber = 1,
+ };
+
+ AttachV2RingBufferRequest();
+ ~AttachV2RingBufferRequest() override;
+ AttachV2RingBufferRequest(AttachV2RingBufferRequest&&) noexcept;
+ AttachV2RingBufferRequest& operator=(AttachV2RingBufferRequest&&);
+ AttachV2RingBufferRequest(const AttachV2RingBufferRequest&);
+ AttachV2RingBufferRequest& operator=(const AttachV2RingBufferRequest&);
+ bool operator==(const AttachV2RingBufferRequest&) const;
+ bool operator!=(const AttachV2RingBufferRequest& other) const { return !(*this == other); }
+
+ bool ParseFromArray(const void*, size_t) override;
+ std::string SerializeAsString() const override;
+ std::vector<uint8_t> SerializeAsArray() const override;
+ void Serialize(::protozero::Message*) const;
+
+ bool has_chunk_size_bytes() const { return _has_field_[1]; }
+ uint32_t chunk_size_bytes() const { return chunk_size_bytes_; }
+ void set_chunk_size_bytes(uint32_t value) { chunk_size_bytes_ = value; _has_field_.set(1); }
+
+ private:
+ uint32_t chunk_size_bytes_{};
+
+ // Allows to preserve unknown protobuf fields for compatibility
+ // with future versions of .proto files.
+ std::string unknown_fields_;
+
+ std::bitset<2> _has_field_{};
+};
+
+
class PERFETTO_EXPORT_COMPONENT InitializeConnectionResponse : public ::protozero::CppMessageObj {
public:
enum FieldNumbers {
kUsingShmemProvidedByProducerFieldNumber = 1,
kDirectSmbPatchingSupportedFieldNumber = 2,
kUseShmemEmulationFieldNumber = 3,
+ kProtocolAbiVersionsFieldNumber = 4,
};
InitializeConnectionResponse();
@@ -192715,16 +195467,21 @@ class PERFETTO_EXPORT_COMPONENT InitializeConnectionResponse : public ::protozer
bool use_shmem_emulation() const { return use_shmem_emulation_; }
void set_use_shmem_emulation(bool value) { use_shmem_emulation_ = value; _has_field_.set(3); }
+ bool has_protocol_abi_versions() const { return _has_field_[4]; }
+ uint32_t protocol_abi_versions() const { return protocol_abi_versions_; }
+ void set_protocol_abi_versions(uint32_t value) { protocol_abi_versions_ = value; _has_field_.set(4); }
+
private:
bool using_shmem_provided_by_producer_{};
bool direct_smb_patching_supported_{};
bool use_shmem_emulation_{};
+ uint32_t protocol_abi_versions_{};
// Allows to preserve unknown protobuf fields for compatibility
// with future versions of .proto files.
std::string unknown_fields_;
- std::bitset<4> _has_field_{};
+ std::bitset<5> _has_field_{};
};
@@ -192744,6 +195501,7 @@ class PERFETTO_EXPORT_COMPONENT InitializeConnectionRequest : public ::protozero
kProducerProvidedShmemFieldNumber = 6,
kSdkVersionFieldNumber = 8,
kShmKeyWindowsFieldNumber = 7,
+ kSupportedProtocolAbiVersionsFieldNumber = 9,
};
InitializeConnectionRequest();
@@ -192788,6 +195546,10 @@ class PERFETTO_EXPORT_COMPONENT InitializeConnectionRequest : public ::protozero
const std::string& shm_key_windows() const { return shm_key_windows_; }
void set_shm_key_windows(const std::string& value) { shm_key_windows_ = value; _has_field_.set(7); }
+ bool has_supported_protocol_abi_versions() const { return _has_field_[9]; }
+ uint32_t supported_protocol_abi_versions() const { return supported_protocol_abi_versions_; }
+ void set_supported_protocol_abi_versions(uint32_t value) { supported_protocol_abi_versions_ = value; _has_field_.set(9); }
+
private:
uint32_t shared_memory_page_size_hint_bytes_{};
uint32_t shared_memory_size_hint_bytes_{};
@@ -192796,12 +195558,13 @@ class PERFETTO_EXPORT_COMPONENT InitializeConnectionRequest : public ::protozero
bool producer_provided_shmem_{};
std::string sdk_version_{};
std::string shm_key_windows_{};
+ uint32_t supported_protocol_abi_versions_{};
// Allows to preserve unknown protobuf fields for compatibility
// with future versions of .proto files.
std::string unknown_fields_;
- std::bitset<9> _has_field_{};
+ std::bitset<10> _has_field_{};
};
} // namespace perfetto