Merge "Do not block on control socket."
diff --git a/Android.bp b/Android.bp
index e6487db..bad324b 100644
--- a/Android.bp
+++ b/Android.bp
@@ -33,6 +33,7 @@
"src/trace_processor/metrics/android/android_startup_launches.sql",
"src/trace_processor/metrics/android/android_task_state.sql",
"src/trace_processor/metrics/android/heap_profile_callsites.sql",
+ "src/trace_processor/metrics/android/java_heap_stats.sql",
"src/trace_processor/metrics/android/mem_stats_priority_breakdown.sql",
"src/trace_processor/metrics/android/process_mem.sql",
"src/trace_processor/metrics/android/process_unagg_mem_view.sql",
@@ -2397,6 +2398,7 @@
"protos/perfetto/metrics/android/cpu_metric.proto",
"protos/perfetto/metrics/android/heap_profile_callsites.proto",
"protos/perfetto/metrics/android/ion_metric.proto",
+ "protos/perfetto/metrics/android/java_heap_stats.proto",
"protos/perfetto/metrics/android/lmk_metric.proto",
"protos/perfetto/metrics/android/mem_metric.proto",
"protos/perfetto/metrics/android/mem_unagg_metric.proto",
@@ -2416,6 +2418,7 @@
"external/perfetto/protos/perfetto/metrics/android/cpu_metric.pbzero.cc",
"external/perfetto/protos/perfetto/metrics/android/heap_profile_callsites.pbzero.cc",
"external/perfetto/protos/perfetto/metrics/android/ion_metric.pbzero.cc",
+ "external/perfetto/protos/perfetto/metrics/android/java_heap_stats.pbzero.cc",
"external/perfetto/protos/perfetto/metrics/android/lmk_metric.pbzero.cc",
"external/perfetto/protos/perfetto/metrics/android/mem_metric.pbzero.cc",
"external/perfetto/protos/perfetto/metrics/android/mem_unagg_metric.pbzero.cc",
@@ -2435,6 +2438,7 @@
"protos/perfetto/metrics/android/cpu_metric.proto",
"protos/perfetto/metrics/android/heap_profile_callsites.proto",
"protos/perfetto/metrics/android/ion_metric.proto",
+ "protos/perfetto/metrics/android/java_heap_stats.proto",
"protos/perfetto/metrics/android/lmk_metric.proto",
"protos/perfetto/metrics/android/mem_metric.proto",
"protos/perfetto/metrics/android/mem_unagg_metric.proto",
@@ -2454,6 +2458,7 @@
"external/perfetto/protos/perfetto/metrics/android/cpu_metric.pbzero.h",
"external/perfetto/protos/perfetto/metrics/android/heap_profile_callsites.pbzero.h",
"external/perfetto/protos/perfetto/metrics/android/ion_metric.pbzero.h",
+ "external/perfetto/protos/perfetto/metrics/android/java_heap_stats.pbzero.h",
"external/perfetto/protos/perfetto/metrics/android/lmk_metric.pbzero.h",
"external/perfetto/protos/perfetto/metrics/android/mem_metric.pbzero.h",
"external/perfetto/protos/perfetto/metrics/android/mem_unagg_metric.pbzero.h",
@@ -4093,7 +4098,6 @@
name: "perfetto_src_base_unittests",
srcs: [
"src/base/circular_queue_unittest.cc",
- "src/base/copyable_ptr_unittest.cc",
"src/base/metatrace_unittest.cc",
"src/base/no_destructor_unittest.cc",
"src/base/optional_unittest.cc",
@@ -4502,6 +4506,7 @@
filegroup {
name: "perfetto_src_protozero_unittests",
srcs: [
+ "src/protozero/copyable_ptr_unittest.cc",
"src/protozero/message_handle_unittest.cc",
"src/protozero/message_unittest.cc",
"src/protozero/proto_decoder_unittest.cc",
@@ -4548,7 +4553,6 @@
srcs: [
"src/trace_processor/android_logs_table.cc",
"src/trace_processor/args_table.cc",
- "src/trace_processor/counter_definitions_table.cc",
"src/trace_processor/counter_values_table.cc",
"src/trace_processor/cpu_profile_stack_sample_table.cc",
"src/trace_processor/filtered_row_index.cc",
diff --git a/BUILD b/BUILD
index 80ba731..8dd4ff4 100644
--- a/BUILD
+++ b/BUILD
@@ -208,7 +208,6 @@
srcs = [
"include/perfetto/base/build_config.h",
"include/perfetto/base/compiler.h",
- "include/perfetto/base/copyable_ptr.h",
"include/perfetto/base/export.h",
"include/perfetto/base/logging.h",
"include/perfetto/base/task_runner.h",
@@ -346,6 +345,7 @@
name = "include_perfetto_protozero_protozero",
srcs = [
"include/perfetto/protozero/contiguous_memory_range.h",
+ "include/perfetto/protozero/copyable_ptr.h",
"include/perfetto/protozero/field.h",
"include/perfetto/protozero/message.h",
"include/perfetto/protozero/message_handle.h",
@@ -425,6 +425,7 @@
"include/perfetto/tracing/track_event.h",
"include/perfetto/tracing/track_event_category_registry.h",
"include/perfetto/tracing/track_event_context.h",
+ "include/perfetto/tracing/track_event_interned_data_index.h",
],
)
@@ -575,6 +576,7 @@
"src/trace_processor/metrics/android/android_startup_launches.sql",
"src/trace_processor/metrics/android/android_task_state.sql",
"src/trace_processor/metrics/android/heap_profile_callsites.sql",
+ "src/trace_processor/metrics/android/java_heap_stats.sql",
"src/trace_processor/metrics/android/mem_stats_priority_breakdown.sql",
"src/trace_processor/metrics/android/process_mem.sql",
"src/trace_processor/metrics/android/process_unagg_mem_view.sql",
@@ -678,8 +680,6 @@
"src/trace_processor/android_logs_table.h",
"src/trace_processor/args_table.cc",
"src/trace_processor/args_table.h",
- "src/trace_processor/counter_definitions_table.cc",
- "src/trace_processor/counter_definitions_table.h",
"src/trace_processor/counter_values_table.cc",
"src/trace_processor/counter_values_table.h",
"src/trace_processor/cpu_profile_stack_sample_table.cc",
@@ -1617,6 +1617,7 @@
"protos/perfetto/metrics/android/cpu_metric.proto",
"protos/perfetto/metrics/android/heap_profile_callsites.proto",
"protos/perfetto/metrics/android/ion_metric.proto",
+ "protos/perfetto/metrics/android/java_heap_stats.proto",
"protos/perfetto/metrics/android/lmk_metric.proto",
"protos/perfetto/metrics/android/mem_metric.proto",
"protos/perfetto/metrics/android/mem_unagg_metric.proto",
diff --git a/include/perfetto/base/BUILD.gn b/include/perfetto/base/BUILD.gn
index 9dc0893..e490551 100644
--- a/include/perfetto/base/BUILD.gn
+++ b/include/perfetto/base/BUILD.gn
@@ -18,7 +18,6 @@
sources = [
"build_config.h",
"compiler.h",
- "copyable_ptr.h",
"export.h",
"logging.h",
"task_runner.h",
diff --git a/include/perfetto/base/compiler.h b/include/perfetto/base/compiler.h
index fa44b6b..0b2efbf 100644
--- a/include/perfetto/base/compiler.h
+++ b/include/perfetto/base/compiler.h
@@ -57,6 +57,15 @@
#define PERFETTO_IS_TRIVIALLY_COPYABLE(T) std::is_trivially_copyable<T>::value
#endif
+#if defined(__GNUC__) || defined(__clang__)
+#define PERFETTO_DEBUG_FUNCTION_IDENTIFIER() __PRETTY_FUNCTION__
+#elif defined(_MSC_VER)
+#define PERFETTO_DEBUG_FUNCTION_IDENTIFIER() __FUNCSIG__
+#else
+#define PERFETTO_DEBUG_FUNCTION_IDENTIFIER() \
+ static_assert(false, "Not implemented for this compiler")
+#endif
+
namespace perfetto {
namespace base {
diff --git a/include/perfetto/protozero/BUILD.gn b/include/perfetto/protozero/BUILD.gn
index 7749684..994ff60 100644
--- a/include/perfetto/protozero/BUILD.gn
+++ b/include/perfetto/protozero/BUILD.gn
@@ -18,6 +18,7 @@
]
sources = [
"contiguous_memory_range.h",
+ "copyable_ptr.h",
"field.h",
"message.h",
"message_handle.h",
diff --git a/include/perfetto/base/copyable_ptr.h b/include/perfetto/protozero/copyable_ptr.h
similarity index 92%
rename from include/perfetto/base/copyable_ptr.h
rename to include/perfetto/protozero/copyable_ptr.h
index 236382f..2fe5ff6 100644
--- a/include/perfetto/base/copyable_ptr.h
+++ b/include/perfetto/protozero/copyable_ptr.h
@@ -14,13 +14,12 @@
* limitations under the License.
*/
-#ifndef INCLUDE_PERFETTO_BASE_COPYABLE_PTR_H_
-#define INCLUDE_PERFETTO_BASE_COPYABLE_PTR_H_
+#ifndef INCLUDE_PERFETTO_PROTOZERO_COPYABLE_PTR_H_
+#define INCLUDE_PERFETTO_PROTOZERO_COPYABLE_PTR_H_
#include <memory>
-namespace perfetto {
-namespace base {
+namespace protozero {
// This class is essentially a std::vector<T> of fixed size = 1.
// It's a pointer wrapper with deep copying and deep equality comparison.
@@ -83,7 +82,6 @@
std::unique_ptr<T> ptr_;
};
-} // namespace base
-} // namespace perfetto
+} // namespace protozero
-#endif // INCLUDE_PERFETTO_BASE_COPYABLE_PTR_H_
+#endif // INCLUDE_PERFETTO_PROTOZERO_COPYABLE_PTR_H_
diff --git a/include/perfetto/protozero/scattered_heap_buffer.h b/include/perfetto/protozero/scattered_heap_buffer.h
index c8fb5fc..bc6a0d2 100644
--- a/include/perfetto/protozero/scattered_heap_buffer.h
+++ b/include/perfetto/protozero/scattered_heap_buffer.h
@@ -34,9 +34,11 @@
public:
class PERFETTO_EXPORT Slice {
public:
+ Slice();
explicit Slice(size_t size);
Slice(Slice&& slice) noexcept;
~Slice();
+ Slice& operator=(Slice&&);
inline protozero::ContiguousMemoryRange GetTotalRange() const {
return {buffer_.get(), buffer_.get() + size_};
@@ -54,9 +56,11 @@
unused_bytes_ = unused_bytes;
}
+ void Clear();
+
private:
std::unique_ptr<uint8_t[]> buffer_;
- const size_t size_;
+ size_t size_;
size_t unused_bytes_;
};
@@ -70,6 +74,10 @@
// Stitch all the slices into a single contiguous buffer.
std::vector<uint8_t> StitchSlices();
+ // Note that the returned ranges point back to this buffer and thus cannot
+ // outlive it.
+ std::vector<protozero::ContiguousMemoryRange> GetRanges();
+
const std::vector<Slice>& slices() const { return slices_; }
void set_writer(protozero::ScatteredStreamWriter* writer) {
@@ -82,11 +90,18 @@
// Returns the total size the slices occupy in heap memory (including unused).
size_t GetTotalSize();
+ // Reset the contents of this buffer but retain one slice allocation (if it
+ // exists) to be reused for future writes.
+ void Reset();
+
private:
size_t next_slice_size_;
const size_t maximum_slice_size_;
protozero::ScatteredStreamWriter* writer_ = nullptr;
std::vector<Slice> slices_;
+
+ // Used to keep an allocated slice around after this buffer is reset.
+ Slice cached_slice_;
};
// Helper function to create heap-based protozero messages in one line.
@@ -123,6 +138,8 @@
T* get() { return &msg_; }
T* operator->() { return &msg_; }
+ bool empty() const { return shb_.slices().empty(); }
+
std::vector<uint8_t> SerializeAsArray() {
msg_.Finalize();
return shb_.StitchSlices();
@@ -133,6 +150,18 @@
return std::string(reinterpret_cast<const char*>(vec.data()), vec.size());
}
+ std::vector<protozero::ContiguousMemoryRange> GetRanges() {
+ msg_.Finalize();
+ return shb_.GetRanges();
+ }
+
+ void Reset() {
+ shb_.Reset();
+ writer_.Reset(protozero::ContiguousMemoryRange{});
+ msg_.Reset(&writer_);
+ PERFETTO_DCHECK(empty());
+ }
+
private:
ScatteredHeapBuffer shb_;
ScatteredStreamWriter writer_;
diff --git a/include/perfetto/tracing.h b/include/perfetto/tracing.h
index 25171c4..be9ef6d 100644
--- a/include/perfetto/tracing.h
+++ b/include/perfetto/tracing.h
@@ -32,5 +32,6 @@
#include "perfetto/tracing/tracing.h"
#include "perfetto/tracing/tracing_backend.h"
#include "perfetto/tracing/track_event.h"
+#include "perfetto/tracing/track_event_interned_data_index.h"
#endif // INCLUDE_PERFETTO_TRACING_H_
diff --git a/include/perfetto/tracing/BUILD.gn b/include/perfetto/tracing/BUILD.gn
index 0ddaff2..e40d43f 100644
--- a/include/perfetto/tracing/BUILD.gn
+++ b/include/perfetto/tracing/BUILD.gn
@@ -17,6 +17,7 @@
"../../../gn:default_deps",
"../../../protos/perfetto/common:cpp",
"../../../protos/perfetto/trace:zero",
+ "../../../protos/perfetto/trace/interned_data:zero",
"../../../protos/perfetto/trace/track_event:zero",
"../base",
"../protozero",
@@ -40,5 +41,6 @@
"track_event.h",
"track_event_category_registry.h",
"track_event_context.h",
+ "track_event_interned_data_index.h",
]
}
diff --git a/include/perfetto/tracing/internal/track_event_internal.h b/include/perfetto/tracing/internal/track_event_internal.h
index bf770fb..c303938 100644
--- a/include/perfetto/tracing/internal/track_event_internal.h
+++ b/include/perfetto/tracing/internal/track_event_internal.h
@@ -17,7 +17,9 @@
#ifndef INCLUDE_PERFETTO_TRACING_INTERNAL_TRACK_EVENT_INTERNAL_H_
#define INCLUDE_PERFETTO_TRACING_INTERNAL_TRACK_EVENT_INTERNAL_H_
+#include "perfetto/protozero/scattered_heap_buffer.h"
#include "perfetto/tracing/trace_writer_base.h"
+#include "protos/perfetto/trace/interned_data/interned_data.pbzero.h"
#include "protos/perfetto/trace/track_event/track_event.pbzero.h"
#include <unordered_map>
@@ -30,14 +32,39 @@
namespace internal {
class TrackEventCategoryRegistry;
+class BaseTrackEventInternedDataIndex {
+ public:
+ virtual ~BaseTrackEventInternedDataIndex();
+
+#if PERFETTO_DCHECK_IS_ON()
+ const char* type_id_ = nullptr;
+#endif // PERFETTO_DCHECK_IS_ON()
+};
+
struct TrackEventIncrementalState {
+ static constexpr size_t kMaxInternedDataFields = 32;
+
bool was_cleared = true;
- // Interned data.
- // TODO(skyostil): Replace this with something more clever that supports
- // dynamic strings too.
- std::unordered_map<const char*, uint64_t> event_names;
- std::unordered_map<const char*, uint64_t> categories;
+ // A heap-allocated message for storing newly seen interned data while we are
+ // in the middle of writing a track event. When a track event wants to write
+ // new interned data into the trace, it is first serialized into this message
+ // and then flushed to the real trace in TrackEventContext when the packet
+ // ends. The message is cached here as a part of incremental state so that we
+ // can reuse the underlying buffer allocation for subsequently written
+ // interned data.
+ protozero::HeapBuffered<protos::pbzero::InternedData>
+ serialized_interned_data;
+
+ // In-memory indices for looking up interned data ids.
+ // For each intern-able field (up to a max of 32) we keep a dictionary of
+ // field-value -> interning-key. Depending on the type we either keep the full
+ // value or a hash of it (See track_event_interned_data_index.h)
+ using InternedDataIndex =
+ std::pair</* interned_data.proto field number */ size_t,
+ std::unique_ptr<BaseTrackEventInternedDataIndex>>;
+ std::array<InternedDataIndex, kMaxInternedDataFields> interned_data_indices =
+ {};
};
// The backend portion of the track event trace point implemention. Outlined to
diff --git a/include/perfetto/tracing/track_event.h b/include/perfetto/tracing/track_event.h
index 23fd3fa..83907ab 100644
--- a/include/perfetto/tracing/track_event.h
+++ b/include/perfetto/tracing/track_event.h
@@ -58,6 +58,42 @@
// TRACK_EVENT_END("category");
// ...
// }
+//
+// ====================
+// Implementation notes
+// ====================
+//
+// The track event library consists of the following layers and components. The
+// classes the internal namespace shouldn't be considered part of the public
+// API.
+// .--------------------------------.
+// .----| TRACE_EVENT |----.
+// write | | - App instrumentation point | | write
+// event | '--------------------------------' | arguments
+// V V
+// .----------------------------------. .-----------------------------.
+// | TrackEvent | | TrackEventContext |
+// | - Registry of event categories | | - One track event instance |
+// '----------------------------------' '-----------------------------'
+// | |
+// | | look up
+// | is | interning ids
+// V V
+// .----------------------------------. .-----------------------------.
+// | internal::TrackEventDataSource | | TrackEventInternedDataIndex |
+// | - Perfetto data source | | - Corresponds to a field in |
+// | - Has TrackEventIncrementalState | | in interned_data.proto |
+// '----------------------------------' '-----------------------------'
+// | | ^
+// | | owns (1:many) |
+// | write event '-------------------------'
+// V
+// .----------------------------------.
+// | internal::TrackEventInternal |
+// | - Outlined code to serialize |
+// | one track event |
+// '----------------------------------'
+//
// Each compilation unit can be in exactly one track event namespace,
// allowing the overall program to use multiple track event data sources and
diff --git a/include/perfetto/tracing/track_event_context.h b/include/perfetto/tracing/track_event_context.h
index b89bbe2..5cf657a 100644
--- a/include/perfetto/tracing/track_event_context.h
+++ b/include/perfetto/tracing/track_event_context.h
@@ -18,6 +18,7 @@
#define INCLUDE_PERFETTO_TRACING_TRACK_EVENT_CONTEXT_H_
#include "perfetto/protozero/message_handle.h"
+#include "perfetto/tracing/internal/track_event_internal.h"
#include "protos/perfetto/trace/trace_packet.pbzero.h"
namespace perfetto {
@@ -42,15 +43,19 @@
protos::pbzero::TrackEvent* track_event() const { return track_event_; }
private:
+ template <typename, size_t, typename, typename>
+ friend class TrackEventInternedDataIndex;
+ friend class internal::TrackEventInternal;
+
using TracePacketHandle =
::protozero::MessageHandle<protos::pbzero::TracePacket>;
- friend class internal::TrackEventInternal;
- TrackEventContext(TracePacketHandle);
+ TrackEventContext(TracePacketHandle, internal::TrackEventIncrementalState*);
TrackEventContext(const TrackEventContext&) = delete;
TracePacketHandle trace_packet_;
protos::pbzero::TrackEvent* track_event_;
+ internal::TrackEventIncrementalState* incremental_state_;
};
} // namespace perfetto
diff --git a/include/perfetto/tracing/track_event_interned_data_index.h b/include/perfetto/tracing/track_event_interned_data_index.h
new file mode 100644
index 0000000..e1ef7ee
--- /dev/null
+++ b/include/perfetto/tracing/track_event_interned_data_index.h
@@ -0,0 +1,233 @@
+/*
+ * 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_TRACING_TRACK_EVENT_INTERNED_DATA_INDEX_H_
+#define INCLUDE_PERFETTO_TRACING_TRACK_EVENT_INTERNED_DATA_INDEX_H_
+
+#include "perfetto/tracing/internal/track_event_internal.h"
+
+#include "perfetto/base/compiler.h"
+
+#include <map>
+#include <type_traits>
+#include <unordered_map>
+
+// This file has templates for defining your own interned data types to be used
+// with track event. Interned data can be useful for avoiding repeating the same
+// constant data (e.g., strings) throughout the trace.
+//
+// =============
+// Example usage
+// =============
+//
+// First define an interning index for your type. It should map to a specific
+// field of interned_data.proto and define how the interned data is written into
+// that message.
+//
+// struct MyInternedData
+// : public perfetto::TrackEventInternedDataIndex<
+// MyInternedData,
+// perfetto::protos::pbzero::InternedData::kMyInternedDataFieldNumber,
+// const char*> {
+// static void Add(perfetto::protos::pbzero::InternedData* interned_data,
+// size_t iid,
+// const char* value) {
+// auto my_data = interned_data->add_my_interned_data();
+// my_data->set_iid(iid);
+// my_data->set_value(value);
+// }
+// };
+//
+// Next, use your interned data in a trace point as shown below. The interned
+// string will only be emitted the first time the trace point is hit.
+//
+// TRACE_EVENT_BEGIN(
+// "category", "Event", [&](perfetto::TrackEventContext ctx) {
+// auto my_message = ctx.track_event()->set_my_message();
+// size_t iid = MyInternedData::Get(&ctx, "Some data");
+// my_message->set_iid(iid);
+// });
+//
+
+namespace perfetto {
+
+// By default, the interning index stores a full copy of the interned data. This
+// ensures the same data is always mapped to the same interning id, and there is
+// no danger of collisions. This comes at the cost of memory usage, however, so
+// consider using HashedInternedDataTraits if that may be an issue.
+//
+// This type of index also performs hashing on the stored data for lookups; for
+// types where this isn't necessary (e.g., raw const char*), use
+// SmallInternedDataTraits.
+struct BigInternedDataTraits {
+ template <typename ValueType>
+ class Index {
+ public:
+ bool LookUpOrInsert(size_t* iid, const ValueType& value) {
+ size_t next_id = data_.size() + 1;
+ auto it_and_inserted = data_.insert(std::make_pair(value, next_id));
+ if (!it_and_inserted.second) {
+ *iid = it_and_inserted.first->second;
+ return true;
+ }
+ *iid = next_id;
+ return false;
+ }
+
+ private:
+ std::unordered_map<ValueType, size_t> data_;
+ };
+};
+
+// This type of interning index keeps full copies of interned data without
+// hashing the values. This is a good fit for small types that can be directly
+// used as index keys.
+struct SmallInternedDataTraits {
+ template <typename ValueType>
+ class Index {
+ public:
+ bool LookUpOrInsert(size_t* iid, const ValueType& value) {
+ size_t next_id = data_.size() + 1;
+ auto it_and_inserted = data_.insert(std::make_pair(value, next_id));
+ if (!it_and_inserted.second) {
+ *iid = it_and_inserted.first->second;
+ return true;
+ }
+ *iid = next_id;
+ return false;
+ }
+
+ private:
+ std::map<ValueType, size_t> data_;
+ };
+};
+
+// This type of interning index only stores the hash of the interned values
+// instead of the values themselves. This is more efficient in terms of memory
+// usage, but assumes that there are no hash collisions. If a hash collision
+// occurs, two or more values will be mapped to the same interning id.
+//
+// Note that the given type must have a specialization for std::hash.
+struct HashedInternedDataTraits {
+ template <typename ValueType>
+ class Index {
+ public:
+ bool LookUpOrInsert(size_t* iid, const ValueType& value) {
+ auto key = std::hash<ValueType>()(value);
+ size_t next_id = data_.size() + 1;
+ auto it_and_inserted = data_.insert(std::make_pair(key, next_id));
+ if (!it_and_inserted.second) {
+ *iid = it_and_inserted.first->second;
+ return true;
+ }
+ *iid = next_id;
+ return false;
+ }
+
+ private:
+ std::map<size_t, size_t> data_;
+ };
+};
+
+// A templated base class for an interned data type which corresponds to a field
+// in interned_data.proto.
+//
+// |InternedDataType| must be the type of the subclass.
+// |FieldNumber| is the corresponding protobuf field in InternedData.
+// |ValueType| is the type which is stored in the index. It must be copyable.
+// |Traits| can be used to customize the storage and lookup mechanism.
+//
+// The subclass should define a static method with the following signature for
+// committing interned data together with the interning id |iid| into the trace:
+//
+// static void Add(perfetto::protos::pbzero::InternedData*,
+// size_t iid,
+// const ValueType& value);
+//
+template <typename InternedDataType,
+ size_t FieldNumber,
+ typename ValueType,
+ // Avoid unnecessary hashing for pointers by default.
+ typename Traits =
+ typename std::conditional<(std::is_pointer<ValueType>::value),
+ SmallInternedDataTraits,
+ BigInternedDataTraits>::type>
+class TrackEventInternedDataIndex
+ : public internal::BaseTrackEventInternedDataIndex {
+ public:
+ // Return an interning id for |value|. The returned id can be immediately
+ // written to the trace.
+ static size_t Get(TrackEventContext* ctx, const ValueType& value) {
+ // First check if the value exists in the dictionary.
+ auto index_for_field = GetOrCreateIndexForField(ctx->incremental_state_);
+ size_t iid;
+ if (PERFETTO_LIKELY(index_for_field->index_.LookUpOrInsert(&iid, value))) {
+ PERFETTO_DCHECK(iid);
+ return iid;
+ }
+
+ // If not, we need to serialize the definition of the interned value into
+ // the heap buffered message (which is committed to the trace when the
+ // packet ends).
+ PERFETTO_DCHECK(iid);
+ InternedDataType::Add(
+ ctx->incremental_state_->serialized_interned_data.get(), iid,
+ std::move(value));
+ return iid;
+ }
+
+ private:
+ static InternedDataType* GetOrCreateIndexForField(
+ internal::TrackEventIncrementalState* incremental_state) {
+ // Fast path: look for matching field number.
+ for (const auto& entry : incremental_state->interned_data_indices) {
+ if (entry.first == FieldNumber) {
+#if PERFETTO_DCHECK_IS_ON()
+ if (strcmp(PERFETTO_DEBUG_FUNCTION_IDENTIFIER(),
+ entry.second->type_id_)) {
+ PERFETTO_FATAL(
+ "Interned data accessed under different types! Previous type: "
+ "%s. New type: %s.",
+ entry.second->type_id_, PERFETTO_DEBUG_FUNCTION_IDENTIFIER());
+ }
+#endif // PERFETTO_DCHECK_IS_ON()
+ return reinterpret_cast<InternedDataType*>(entry.second.get());
+ }
+ }
+ // No match -- add a new entry for this field.
+ for (auto& entry : incremental_state->interned_data_indices) {
+ if (!entry.first) {
+ entry.first = FieldNumber;
+ entry.second.reset(new InternedDataType());
+#if PERFETTO_DCHECK_IS_ON()
+ entry.second->type_id_ = PERFETTO_DEBUG_FUNCTION_IDENTIFIER();
+#endif // PERFETTO_DCHECK_IS_ON()
+ return reinterpret_cast<InternedDataType*>(entry.second.get());
+ }
+ }
+ // Out of space in the interned data index table.
+ PERFETTO_CHECK(false);
+ }
+
+ // The actual interning dictionary for this type of interned data. The actual
+ // container type is defined by |Traits|, hence the extra layer of template
+ // indirection here.
+ typename Traits::template Index<ValueType> index_;
+};
+
+} // namespace perfetto
+
+#endif // INCLUDE_PERFETTO_TRACING_TRACK_EVENT_INTERNED_DATA_INDEX_H_
diff --git a/protos/perfetto/config/ftrace/ftrace_config.proto b/protos/perfetto/config/ftrace/ftrace_config.proto
index 56dc0d0..3b1e6a2 100644
--- a/protos/perfetto/config/ftrace/ftrace_config.proto
+++ b/protos/perfetto/config/ftrace/ftrace_config.proto
@@ -27,16 +27,13 @@
optional uint32 buffer_size_kb = 10;
optional uint32 drain_period_ms = 11;
- // Configuration for compact encoding of scheduler events. If enabled, this
- // records a small subset of fields of selected scheduling events, and
- // encodes them in a denser proto format than normal. This is useful due to
- // scheduling events being abundant in a typical trace, and dominating its
- // size via a combination of unnecessary data being retained, and proto
- // format overheads.
+ // Configuration for compact encoding of scheduler events. When enabled (and
+ // recording the relevant ftrace events), the most high-volume events are
+ // encoded in a denser format than normal.
// TODO(rsavitski): unstable, do not use.
message CompactSchedConfig {
- // If true, and sched_switch ftrace event is enabled, record those events
- // in the compact format.
+ // If true, and sched_switch or sched_waking ftrace events are enabled,
+ // record those events in the compact format.
optional bool enabled = 1;
}
optional CompactSchedConfig compact_sched = 12;
diff --git a/protos/perfetto/config/perfetto_config.proto b/protos/perfetto/config/perfetto_config.proto
index 49e5a66..670e584 100644
--- a/protos/perfetto/config/perfetto_config.proto
+++ b/protos/perfetto/config/perfetto_config.proto
@@ -631,16 +631,13 @@
optional uint32 buffer_size_kb = 10;
optional uint32 drain_period_ms = 11;
- // Configuration for compact encoding of scheduler events. If enabled, this
- // records a small subset of fields of selected scheduling events, and
- // encodes them in a denser proto format than normal. This is useful due to
- // scheduling events being abundant in a typical trace, and dominating its
- // size via a combination of unnecessary data being retained, and proto
- // format overheads.
+ // Configuration for compact encoding of scheduler events. When enabled (and
+ // recording the relevant ftrace events), the most high-volume events are
+ // encoded in a denser format than normal.
// TODO(rsavitski): unstable, do not use.
message CompactSchedConfig {
- // If true, and sched_switch ftrace event is enabled, record those events
- // in the compact format.
+ // If true, and sched_switch or sched_waking ftrace events are enabled,
+ // record those events in the compact format.
optional bool enabled = 1;
}
optional CompactSchedConfig compact_sched = 12;
diff --git a/protos/perfetto/metrics/android/BUILD.gn b/protos/perfetto/metrics/android/BUILD.gn
index 9d1d001..41353b0 100644
--- a/protos/perfetto/metrics/android/BUILD.gn
+++ b/protos/perfetto/metrics/android/BUILD.gn
@@ -20,6 +20,7 @@
"cpu_metric.proto",
"heap_profile_callsites.proto",
"ion_metric.proto",
+ "java_heap_stats.proto",
"lmk_metric.proto",
"mem_metric.proto",
"mem_unagg_metric.proto",
diff --git a/protos/perfetto/metrics/android/heap_profile_callsites.proto b/protos/perfetto/metrics/android/heap_profile_callsites.proto
index ce0bdca..d19bba3 100644
--- a/protos/perfetto/metrics/android/heap_profile_callsites.proto
+++ b/protos/perfetto/metrics/android/heap_profile_callsites.proto
@@ -51,10 +51,16 @@
}
// Callsites per process instance.
+ // Next id: 6
message InstanceStats {
optional uint32 pid = 1;
optional string process_name = 2;
repeated Callsite callsites = 3;
+
+ // Bytes allocated via malloc but not freed.
+ optional int64 profile_delta_bytes = 4;
+ // Bytes allocated via malloc irrespective of whether they were freed.
+ optional int64 profile_total_bytes = 5;
}
repeated InstanceStats instance_stats = 1;
diff --git a/protos/perfetto/metrics/android/java_heap_stats.proto b/protos/perfetto/metrics/android/java_heap_stats.proto
new file mode 100644
index 0000000..a5e1513
--- /dev/null
+++ b/protos/perfetto/metrics/android/java_heap_stats.proto
@@ -0,0 +1,37 @@
+/*
+ * 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.
+ */
+syntax = "proto2";
+option optimize_for = LITE_RUNTIME;
+
+package perfetto.protos;
+
+message JavaHeapStats {
+ message Sample {
+ optional int64 ts = 1;
+ optional int64 heap_size = 2;
+ optional int64 reachable_heap_size = 3;
+ }
+
+ // Heap stats per process. One sample per dump (can be > 1 if continuous
+ // dump is enabled).
+ message InstanceStats {
+ optional uint32 upid = 1;
+ optional string process_name = 2;
+ repeated Sample samples = 3;
+ }
+
+ repeated InstanceStats instance_stats = 1;
+}
diff --git a/protos/perfetto/metrics/metrics.proto b/protos/perfetto/metrics/metrics.proto
index d0c7a1f..508e830 100644
--- a/protos/perfetto/metrics/metrics.proto
+++ b/protos/perfetto/metrics/metrics.proto
@@ -31,6 +31,7 @@
import "protos/perfetto/metrics/android/heap_profile_callsites.proto";
import "protos/perfetto/metrics/android/package_list.proto";
import "protos/perfetto/metrics/android/unsymbolized_frames.proto";
+import "protos/perfetto/metrics/android/java_heap_stats.proto";
// Trace processor metadata (taken from the stats table schema and contents).
// TODO: perhaps add the other columns once we have enum support
@@ -43,11 +44,12 @@
repeated Entry error_stats_entry = 1;
optional int64 trace_duration_ns = 2;
+ optional string trace_uuid = 3;
}
// Root message for all Perfetto-based metrics.
//
-// Next id: 17
+// Next id: 18
message TraceMetrics {
reserved 4, 13, 14;
@@ -93,6 +95,9 @@
// Returns stack frames missing symbols.
optional UnsymbolizedFrames unsymbolized_frames = 15;
+ // If the trace contains a heap graph, output allocation statistics.
+ optional JavaHeapStats java_heap_stats = 17;
+
// Demo extensions.
extensions 450 to 499;
diff --git a/protos/perfetto/trace/ftrace/ftrace_event_bundle.proto b/protos/perfetto/trace/ftrace/ftrace_event_bundle.proto
index e61377a..a65191d 100644
--- a/protos/perfetto/trace/ftrace/ftrace_event_bundle.proto
+++ b/protos/perfetto/trace/ftrace/ftrace_event_bundle.proto
@@ -38,6 +38,9 @@
// entry in each repeated field per event.
// TODO(rsavitski): unstable, do not use.
message CompactSched {
+ // Interned table of unique strings for this bundle.
+ repeated string intern_table = 5;
+
// Delta-encoded timestamps across all sched_switch events within this
// bundle. The first is absolute, each next one is relative to its
// predecessor.
@@ -45,12 +48,20 @@
repeated int64 switch_prev_state = 2 [packed = true];
repeated int32 switch_next_pid = 3 [packed = true];
repeated int32 switch_next_prio = 4 [packed = true];
-
- // Interned table of unique comm strings for this bundle.
- repeated string switch_next_comm_table = 5;
- // One per event, index into |switch_next_comm_table| corresponding to the
+ // One per event, index into |intern_table| corresponding to the
// next_comm field of the event.
repeated uint32 switch_next_comm_index = 6 [packed = true];
+
+ // Delta-encoded timestamps across all sched_waking events within this
+ // bundle. The first is absolute, each next one is relative to its
+ // predecessor.
+ repeated uint64 waking_timestamp = 7 [packed = true];
+ repeated int32 waking_pid = 8 [packed = true];
+ repeated int32 waking_target_cpu = 9 [packed = true];
+ repeated int32 waking_prio = 10 [packed = true];
+ // One per event, index into |intern_table| corresponding to the
+ // comm field of the event.
+ repeated uint32 waking_comm_index = 11 [packed = true];
}
optional CompactSched compact_sched = 4;
}
diff --git a/protos/perfetto/trace/perfetto_trace.proto b/protos/perfetto/trace/perfetto_trace.proto
index f59d182..a9cc0ff 100644
--- a/protos/perfetto/trace/perfetto_trace.proto
+++ b/protos/perfetto/trace/perfetto_trace.proto
@@ -2318,6 +2318,9 @@
// entry in each repeated field per event.
// TODO(rsavitski): unstable, do not use.
message CompactSched {
+ // Interned table of unique strings for this bundle.
+ repeated string intern_table = 5;
+
// Delta-encoded timestamps across all sched_switch events within this
// bundle. The first is absolute, each next one is relative to its
// predecessor.
@@ -2325,12 +2328,20 @@
repeated int64 switch_prev_state = 2 [packed = true];
repeated int32 switch_next_pid = 3 [packed = true];
repeated int32 switch_next_prio = 4 [packed = true];
-
- // Interned table of unique comm strings for this bundle.
- repeated string switch_next_comm_table = 5;
- // One per event, index into |switch_next_comm_table| corresponding to the
+ // One per event, index into |intern_table| corresponding to the
// next_comm field of the event.
repeated uint32 switch_next_comm_index = 6 [packed = true];
+
+ // Delta-encoded timestamps across all sched_waking events within this
+ // bundle. The first is absolute, each next one is relative to its
+ // predecessor.
+ repeated uint64 waking_timestamp = 7 [packed = true];
+ repeated int32 waking_pid = 8 [packed = true];
+ repeated int32 waking_target_cpu = 9 [packed = true];
+ repeated int32 waking_prio = 10 [packed = true];
+ // One per event, index into |intern_table| corresponding to the
+ // comm field of the event.
+ repeated uint32 waking_comm_index = 11 [packed = true];
}
optional CompactSched compact_sched = 4;
}
@@ -4457,16 +4468,13 @@
optional uint32 buffer_size_kb = 10;
optional uint32 drain_period_ms = 11;
- // Configuration for compact encoding of scheduler events. If enabled, this
- // records a small subset of fields of selected scheduling events, and
- // encodes them in a denser proto format than normal. This is useful due to
- // scheduling events being abundant in a typical trace, and dominating its
- // size via a combination of unnecessary data being retained, and proto
- // format overheads.
+ // Configuration for compact encoding of scheduler events. When enabled (and
+ // recording the relevant ftrace events), the most high-volume events are
+ // encoded in a denser format than normal.
// TODO(rsavitski): unstable, do not use.
message CompactSchedConfig {
- // If true, and sched_switch ftrace event is enabled, record those events
- // in the compact format.
+ // If true, and sched_switch or sched_waking ftrace events are enabled,
+ // record those events in the compact format.
optional bool enabled = 1;
}
optional CompactSchedConfig compact_sched = 12;
diff --git a/src/base/BUILD.gn b/src/base/BUILD.gn
index 9f53d4b..0e7a0d0 100644
--- a/src/base/BUILD.gn
+++ b/src/base/BUILD.gn
@@ -122,7 +122,6 @@
sources = [
"circular_queue_unittest.cc",
- "copyable_ptr_unittest.cc",
"no_destructor_unittest.cc",
"optional_unittest.cc",
"paged_memory_unittest.cc",
diff --git a/src/perfetto_cmd/perfetto_config.descriptor.h b/src/perfetto_cmd/perfetto_config.descriptor.h
index 666bac9..f480e88 100644
--- a/src/perfetto_cmd/perfetto_config.descriptor.h
+++ b/src/perfetto_cmd/perfetto_config.descriptor.h
@@ -12,7 +12,7 @@
// SHA1(tools/gen_binary_descriptors)
// 192b582ae52bb07b3d3ba66a94bcfd3127a5f42f
// SHA1(protos/perfetto/config/perfetto_config.proto)
-// 267f9d49ca0c50158496fd5dc90ab15480500724
+// 7e29ded10dd6cff450d72d81dbaba1f8ef65c64f
// This is the proto PerfettoConfig encoded as a ProtoFileDescriptor to allow
// for reflection without libprotobuf full/non-lite protos.
diff --git a/src/protozero/BUILD.gn b/src/protozero/BUILD.gn
index bcc34e0..b2cc13a 100644
--- a/src/protozero/BUILD.gn
+++ b/src/protozero/BUILD.gn
@@ -57,6 +57,7 @@
"../base:test_support",
]
sources = [
+ "copyable_ptr_unittest.cc",
"message_handle_unittest.cc",
"message_unittest.cc",
"proto_decoder_unittest.cc",
diff --git a/src/base/copyable_ptr_unittest.cc b/src/protozero/copyable_ptr_unittest.cc
similarity index 94%
rename from src/base/copyable_ptr_unittest.cc
rename to src/protozero/copyable_ptr_unittest.cc
index ecbd1ef..d9be950 100644
--- a/src/base/copyable_ptr_unittest.cc
+++ b/src/protozero/copyable_ptr_unittest.cc
@@ -14,12 +14,11 @@
* limitations under the License.
*/
-#include "perfetto/base/copyable_ptr.h"
+#include "perfetto/protozero/copyable_ptr.h"
#include "test/gtest_and_gmock.h"
-namespace perfetto {
-namespace base {
+namespace protozero {
namespace {
struct X {
@@ -116,5 +115,4 @@
}
} // namespace
-} // namespace base
-} // namespace perfetto
+} // namespace protozero
diff --git a/src/protozero/protoc_plugin/cppgen_plugin.cc b/src/protozero/protoc_plugin/cppgen_plugin.cc
index b396a67..e50c01e 100644
--- a/src/protozero/protoc_plugin/cppgen_plugin.cc
+++ b/src/protozero/protoc_plugin/cppgen_plugin.cc
@@ -121,7 +121,7 @@
h_printer.Print("#include <vector>\n");
h_printer.Print("#include <string>\n");
h_printer.Print("#include <type_traits>\n\n");
- h_printer.Print("#include \"perfetto/base/copyable_ptr.h\"\n");
+ h_printer.Print("#include \"perfetto/protozero/copyable_ptr.h\"\n");
h_printer.Print("#include \"perfetto/base/export.h\"\n\n");
cc_printer.Print(kHeader);
@@ -426,7 +426,7 @@
} else if (!field->is_repeated()) {
std::string type = GetCppType(field, false);
if (field->type() == TYPE_MESSAGE) {
- type = "::perfetto::base::CopyablePtr<" + type + ">";
+ type = "::protozero::CopyablePtr<" + type + ">";
p->Print("$t$ $n$_;\n", "t", type, "n", field->lowercase_name());
} else {
p->Print("$t$ $n$_{};\n", "t", type, "n", field->lowercase_name());
diff --git a/src/protozero/scattered_heap_buffer.cc b/src/protozero/scattered_heap_buffer.cc
index 682a059..389c36e 100644
--- a/src/protozero/scattered_heap_buffer.cc
+++ b/src/protozero/scattered_heap_buffer.cc
@@ -20,20 +20,31 @@
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);
-#if PERFETTO_DCHECK_IS_ON()
- memset(start(), 0xff, size_);
-#endif // PERFETTO_DCHECK_IS_ON()
+ Clear();
}
ScatteredHeapBuffer::Slice::Slice(Slice&& slice) noexcept = default;
ScatteredHeapBuffer::Slice::~Slice() = default;
+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()
+}
+
ScatteredHeapBuffer::ScatteredHeapBuffer(size_t initial_slice_size_bytes,
size_t maximum_slice_size_bytes)
: next_slice_size_(initial_slice_size_bytes),
@@ -48,7 +59,12 @@
PERFETTO_CHECK(writer_);
AdjustUsedSizeOfCurrentSlice();
- slices_.emplace_back(next_slice_size_);
+ 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();
}
@@ -63,6 +79,14 @@
return buffer;
}
+std::vector<protozero::ContiguousMemoryRange> ScatteredHeapBuffer::GetRanges() {
+ AdjustUsedSizeOfCurrentSlice();
+ std::vector<protozero::ContiguousMemoryRange> ranges;
+ for (const auto& slice : slices_)
+ ranges.push_back(slice.GetUsedRange());
+ return ranges;
+}
+
void ScatteredHeapBuffer::AdjustUsedSizeOfCurrentSlice() {
if (!slices_.empty())
slices_.back().set_unused_bytes(writer_->bytes_available());
@@ -76,4 +100,12 @@
return total_size;
}
+void ScatteredHeapBuffer::Reset() {
+ if (slices_.empty())
+ return;
+ cached_slice_ = std::move(slices_.front());
+ cached_slice_.Clear();
+ slices_.clear();
+}
+
} // namespace protozero
diff --git a/src/trace_processor/BUILD.gn b/src/trace_processor/BUILD.gn
index eda227b..80d394d 100644
--- a/src/trace_processor/BUILD.gn
+++ b/src/trace_processor/BUILD.gn
@@ -236,8 +236,6 @@
"android_logs_table.h",
"args_table.cc",
"args_table.h",
- "counter_definitions_table.cc",
- "counter_definitions_table.h",
"counter_values_table.cc",
"counter_values_table.h",
"cpu_profile_stack_sample_table.cc",
diff --git a/src/trace_processor/android_logs_table.cc b/src/trace_processor/android_logs_table.cc
index b104280..d58508b 100644
--- a/src/trace_processor/android_logs_table.cc
+++ b/src/trace_processor/android_logs_table.cc
@@ -47,14 +47,13 @@
int AndroidLogsTable::BestIndex(const QueryConstraints& qc,
BestIndexInfo* info) {
info->estimated_cost = static_cast<uint32_t>(storage_->android_logs().size());
-
- info->order_by_consumed = true;
+ info->sqlite_omit_order_by = true;
// Only the string columns are handled by SQLite.
size_t tag_index = schema().ColumnIndexFromName("tag");
size_t msg_index = schema().ColumnIndexFromName("msg");
for (size_t i = 0; i < qc.constraints().size(); i++) {
- info->omit[i] =
+ info->constraint_info[i].sqlite_omit =
qc.constraints()[i].iColumn != static_cast<int>(tag_index) &&
qc.constraints()[i].iColumn != static_cast<int>(msg_index);
}
diff --git a/src/trace_processor/counter_definitions_table.cc b/src/trace_processor/counter_definitions_table.cc
deleted file mode 100644
index ae31ec1..0000000
--- a/src/trace_processor/counter_definitions_table.cc
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- * 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.
- */
-
-#include "src/trace_processor/counter_definitions_table.h"
-
-#include <string>
-
-#include "src/trace_processor/storage_columns.h"
-
-namespace perfetto {
-namespace trace_processor {
-
-CounterDefinitionsTable::CounterDefinitionsTable(sqlite3*,
- const TraceStorage* storage)
- : storage_(storage) {}
-
-void CounterDefinitionsTable::RegisterTable(sqlite3* db,
- const TraceStorage* storage) {
- SqliteTable::Register<CounterDefinitionsTable>(db, storage,
- "counter_definitions");
-}
-
-StorageSchema CounterDefinitionsTable::CreateStorageSchema() {
- const auto& cs = storage_->counter_definitions();
- return StorageSchema::Builder()
- .AddGenericNumericColumn("counter_id", RowAccessor())
- .AddStringColumn("name", &cs.name_ids(), &storage_->string_pool())
- .AddNumericColumn("ref", &cs.refs())
- .AddStringColumn("ref_type", &cs.types(), &GetRefTypeStringMap())
- .AddStringColumn("description", &cs.desc_ids(), &storage_->string_pool())
- .AddStringColumn("unit", &cs.unit_ids(), &storage_->string_pool())
- .Build({"counter_id"});
-}
-
-uint32_t CounterDefinitionsTable::RowCount() {
- return storage_->counter_definitions().size();
-}
-
-int CounterDefinitionsTable::BestIndex(const QueryConstraints& qc,
- BestIndexInfo* info) {
- info->estimated_cost = EstimateCost(qc);
-
- // Only the string columns are handled by SQLite
- size_t name_index = schema().ColumnIndexFromName("name");
- size_t ref_type_index = schema().ColumnIndexFromName("ref_type");
- info->order_by_consumed = true;
- for (size_t i = 0; i < qc.constraints().size(); i++) {
- auto col = static_cast<size_t>(qc.constraints()[i].iColumn);
- info->omit[i] = col != name_index && col != ref_type_index;
- }
-
- return SQLITE_OK;
-}
-
-uint32_t CounterDefinitionsTable::EstimateCost(const QueryConstraints& qc) {
- // If there is a constraint on the counter id, we can efficiently filter
- // to a single row.
- if (HasEqConstraint(qc, "counter_id"))
- return 1;
-
- auto eq_name = HasEqConstraint(qc, "name");
- auto eq_ref = HasEqConstraint(qc, "ref");
- auto eq_ref_type = HasEqConstraint(qc, "ref_type");
-
- // If there is a constraint on all three columns, we are going to only return
- // exaclty one row for sure so make the cost 1.
- if (eq_name && eq_ref && eq_ref_type)
- return 1;
- else if (eq_name && eq_ref)
- return 10;
- else if (eq_name)
- return 100;
- return RowCount();
-}
-
-} // namespace trace_processor
-} // namespace perfetto
diff --git a/src/trace_processor/counter_definitions_table.h b/src/trace_processor/counter_definitions_table.h
deleted file mode 100644
index 539eaac..0000000
--- a/src/trace_processor/counter_definitions_table.h
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * 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 SRC_TRACE_PROCESSOR_COUNTER_DEFINITIONS_TABLE_H_
-#define SRC_TRACE_PROCESSOR_COUNTER_DEFINITIONS_TABLE_H_
-
-#include "src/trace_processor/storage_table.h"
-#include "src/trace_processor/trace_storage.h"
-
-namespace perfetto {
-namespace trace_processor {
-
-class CounterDefinitionsTable : public StorageTable {
- public:
- static void RegisterTable(sqlite3* db, const TraceStorage* storage);
-
- CounterDefinitionsTable(sqlite3*, const TraceStorage*);
-
- // StorageTable implementation.
- StorageSchema CreateStorageSchema() override;
- uint32_t RowCount() override;
- int BestIndex(const QueryConstraints&, BestIndexInfo*) override;
-
- private:
- uint32_t EstimateCost(const QueryConstraints&);
-
- const TraceStorage* const storage_;
-};
-
-} // namespace trace_processor
-} // namespace perfetto
-
-#endif // SRC_TRACE_PROCESSOR_COUNTER_DEFINITIONS_TABLE_H_
diff --git a/src/trace_processor/counter_values_table.cc b/src/trace_processor/counter_values_table.cc
index cda1705..7176fd3 100644
--- a/src/trace_processor/counter_values_table.cc
+++ b/src/trace_processor/counter_values_table.cc
@@ -24,15 +24,14 @@
void CounterValuesTable::RegisterTable(sqlite3* db,
const TraceStorage* storage) {
- SqliteTable::Register<CounterValuesTable>(db, storage, "counter_values");
+ SqliteTable::Register<CounterValuesTable>(db, storage, "counter");
}
StorageSchema CounterValuesTable::CreateStorageSchema() {
const auto& cs = storage_->counter_values();
return StorageSchema::Builder()
.AddGenericNumericColumn("id", RowIdAccessor(TableId::kCounterValues))
- .AddNumericColumn("counter_id", &cs.counter_ids(),
- &cs.rows_for_counter_id())
+ .AddNumericColumn("track_id", &cs.track_ids(), &cs.rows_for_track_id())
.AddOrderedNumericColumn("ts", &cs.timestamps())
.AddNumericColumn("value", &cs.values())
.AddNumericColumn("arg_set_id", &cs.arg_set_ids())
@@ -46,17 +45,15 @@
int CounterValuesTable::BestIndex(const QueryConstraints& qc,
BestIndexInfo* info) {
info->estimated_cost = EstimateCost(qc);
-
- info->order_by_consumed = true;
- for (size_t i = 0; i < qc.constraints().size(); i++) {
- info->omit[i] = true;
- }
+ info->sqlite_omit_order_by = true;
+ for (auto& c_info : info->constraint_info)
+ c_info.sqlite_omit = true;
return SQLITE_OK;
}
uint32_t CounterValuesTable::EstimateCost(const QueryConstraints& qc) {
- if (HasEqConstraint(qc, "counter_id"))
+ if (HasEqConstraint(qc, "track_id"))
return RowCount() / 100;
return RowCount();
}
diff --git a/src/trace_processor/cpu_profile_stack_sample_table.cc b/src/trace_processor/cpu_profile_stack_sample_table.cc
index bb51404..1226020 100644
--- a/src/trace_processor/cpu_profile_stack_sample_table.cc
+++ b/src/trace_processor/cpu_profile_stack_sample_table.cc
@@ -46,7 +46,7 @@
int CpuProfileStackSampleTable::BestIndex(const QueryConstraints& qc,
BestIndexInfo* info) {
- info->order_by_consumed = true;
+ info->sqlite_omit_order_by = true;
info->estimated_cost = HasEqConstraint(qc, "id") ? 1 : RowCount();
return SQLITE_OK;
}
diff --git a/src/trace_processor/event_tracker.cc b/src/trace_processor/event_tracker.cc
index f6d933c..2e9babf 100644
--- a/src/trace_processor/event_tracker.cc
+++ b/src/trace_processor/event_tracker.cc
@@ -24,6 +24,7 @@
#include "src/trace_processor/process_tracker.h"
#include "src/trace_processor/stats.h"
#include "src/trace_processor/trace_processor_context.h"
+#include "src/trace_processor/track_tracker.h"
#include "src/trace_processor/variadic.h"
namespace perfetto {
@@ -34,27 +35,16 @@
EventTracker::~EventTracker() = default;
-RowId EventTracker::PushCounter(int64_t timestamp,
- double value,
- StringId name_id,
- int64_t ref,
- RefType ref_type,
- bool resolve_utid_to_upid) {
- PERFETTO_DCHECK(!resolve_utid_to_upid || ref_type == RefType::kRefUtid);
-
- auto* definitions = context_->storage->mutable_counter_definitions();
- TraceStorage::CounterDefinitions::Id defn_id;
- if (resolve_utid_to_upid) {
- defn_id = TraceStorage::CounterDefinitions::kInvalidId;
- } else {
- defn_id = definitions->AddCounterDefinition(name_id, ref, ref_type);
- }
- RowId row_id = PushCounter(timestamp, value, defn_id);
- if (resolve_utid_to_upid && row_id != kInvalidRowId) {
+RowId EventTracker::PushProcessCounterForThread(int64_t timestamp,
+ double value,
+ StringId name_id,
+ UniqueTid utid) {
+ RowId row_id = PushCounter(timestamp, value, kInvalidTrackId);
+ if (row_id != kInvalidRowId) {
auto table_and_row = TraceStorage::ParseRowId(row_id);
PendingUpidResolutionCounter pending;
pending.row = table_and_row.second;
- pending.utid = static_cast<UniqueTid>(ref);
+ pending.utid = utid;
pending.name_id = name_id;
pending_upid_resolution_counter_.emplace_back(pending);
}
@@ -63,7 +53,7 @@
RowId EventTracker::PushCounter(int64_t timestamp,
double value,
- TraceStorage::CounterDefinitions::Id defn_id) {
+ TrackId track_id) {
if (timestamp < max_timestamp_) {
PERFETTO_DLOG("counter event (ts: %" PRId64
") out of order by %.4f ms, skipping",
@@ -74,7 +64,7 @@
max_timestamp_ = timestamp;
auto* counter_values = context_->storage->mutable_counter_values();
- uint32_t idx = counter_values->AddCounterValue(defn_id, timestamp, value);
+ uint32_t idx = counter_values->AddCounterValue(track_id, timestamp, value);
return TraceStorage::CreateRowId(TableId::kCounterValues,
static_cast<uint32_t>(idx));
}
@@ -107,10 +97,9 @@
// TODO(lalitm): having upid == 0 is probably not the correct approach here
// but it's unclear what may be better.
UniquePid upid = thread.upid.value_or(0);
- auto id =
- context_->storage->mutable_counter_definitions()->AddCounterDefinition(
- pending_counter.name_id, upid, RefType::kRefUpid);
- context_->storage->mutable_counter_values()->set_counter_id(
+ auto id = context_->track_tracker->InternProcessCounterTrack(
+ pending_counter.name_id, upid);
+ context_->storage->mutable_counter_values()->set_track_id(
pending_counter.row, id);
}
diff --git a/src/trace_processor/event_tracker.h b/src/trace_processor/event_tracker.h
index 66ba7ba..906443a 100644
--- a/src/trace_processor/event_tracker.h
+++ b/src/trace_processor/event_tracker.h
@@ -37,18 +37,20 @@
EventTracker& operator=(const EventTracker&) = delete;
virtual ~EventTracker();
- // This method is called when a counter event is seen in the trace.
- virtual RowId PushCounter(int64_t timestamp,
- double value,
- StringId name_id,
- int64_t ref,
- RefType ref_type,
- bool resolve_utid_to_upid = false);
+ // Adds a counter event to the counters table returning the RowId of the
+ // newly added row.
+ virtual RowId PushCounter(int64_t timestamp, double value, TrackId track_id);
- // This method is called when a counter event is seen in the trace.
- virtual RowId PushCounter(int64_t timestamp,
- double value,
- TraceStorage::CounterDefinitions::Id defn_id);
+ // Adds a counter event to the counters table for counter events which
+ // should be associated with a process but only have a thread context
+ // (e.g. rss_stat events).
+ //
+ // This function will resolve the utid to a upid when the events are
+ // flushed (see |FlushPendingEvents()|).
+ virtual RowId PushProcessCounterForThread(int64_t timestamp,
+ double value,
+ StringId name_id,
+ UniqueTid utid);
// This method is called when a instant event is seen in the trace.
virtual RowId PushInstant(int64_t timestamp,
diff --git a/src/trace_processor/event_tracker_unittest.cc b/src/trace_processor/event_tracker_unittest.cc
index 0f0240b..58b905f 100644
--- a/src/trace_processor/event_tracker_unittest.cc
+++ b/src/trace_processor/event_tracker_unittest.cc
@@ -20,6 +20,7 @@
#include "src/trace_processor/args_tracker.h"
#include "src/trace_processor/importers/ftrace/sched_event_tracker.h"
#include "src/trace_processor/process_tracker.h"
+#include "src/trace_processor/track_tracker.h"
#include "test/gtest_and_gmock.h"
namespace perfetto {
@@ -37,6 +38,7 @@
context.args_tracker.reset(new ArgsTracker(&context));
context.process_tracker.reset(new ProcessTracker(&context));
context.event_tracker.reset(new EventTracker(&context));
+ context.track_tracker.reset(new TrackTracker(&context));
#if PERFETTO_BUILDFLAG(PERFETTO_TP_FTRACE)
context.sched_tracker.reset(new SchedEventTracker(&context));
#endif // PERFETTO_BUILDFLAG(PERFETTO_TP_FTRACE)
@@ -116,16 +118,14 @@
uint32_t cpu = 3;
int64_t timestamp = 100;
StringId name_id = 0;
- context.event_tracker->PushCounter(timestamp, 1000, name_id, cpu,
- RefType::kRefCpuId);
- context.event_tracker->PushCounter(timestamp + 1, 4000, name_id, cpu,
- RefType::kRefCpuId);
- context.event_tracker->PushCounter(timestamp + 3, 5000, name_id, cpu,
- RefType::kRefCpuId);
- context.event_tracker->PushCounter(timestamp + 9, 1000, name_id, cpu,
- RefType::kRefCpuId);
- ASSERT_EQ(context.storage->counter_definitions().size(), 1ul);
+ TrackId track = context.track_tracker->InternCpuCounterTrack(name_id, cpu);
+ context.event_tracker->PushCounter(timestamp, 1000, track);
+ context.event_tracker->PushCounter(timestamp + 1, 4000, track);
+ context.event_tracker->PushCounter(timestamp + 3, 5000, track);
+ context.event_tracker->PushCounter(timestamp + 9, 1000, track);
+
+ ASSERT_EQ(context.storage->counter_track_table().size(), 1ul);
ASSERT_EQ(context.storage->counter_values().size(), 4ul);
ASSERT_EQ(context.storage->counter_values().timestamps().at(0), timestamp);
diff --git a/src/trace_processor/heap_profile_allocation_table.cc b/src/trace_processor/heap_profile_allocation_table.cc
index 8bd050e..dcdb825 100644
--- a/src/trace_processor/heap_profile_allocation_table.cc
+++ b/src/trace_processor/heap_profile_allocation_table.cc
@@ -48,7 +48,7 @@
int HeapProfileAllocationTable::BestIndex(const QueryConstraints& qc,
BestIndexInfo* info) {
- info->order_by_consumed = true;
+ info->sqlite_omit_order_by = true;
info->estimated_cost = HasEqConstraint(qc, "id") ? 1 : RowCount();
return SQLITE_OK;
}
diff --git a/src/trace_processor/importers/ftrace/ftrace_parser.cc b/src/trace_processor/importers/ftrace/ftrace_parser.cc
index 01598b2..f325192 100644
--- a/src/trace_processor/importers/ftrace/ftrace_parser.cc
+++ b/src/trace_processor/importers/ftrace/ftrace_parser.cc
@@ -474,24 +474,27 @@
protos::pbzero::CpuFrequencyFtraceEvent::Decoder freq(blob.data, blob.size);
uint32_t cpu = freq.cpu_id();
uint32_t new_freq = freq.state();
- context_->event_tracker->PushCounter(ts, new_freq, cpu_freq_name_id_, cpu,
- RefType::kRefCpuId);
+ TrackId track =
+ context_->track_tracker->InternCpuCounterTrack(cpu_freq_name_id_, cpu);
+ context_->event_tracker->PushCounter(ts, new_freq, track);
}
void FtraceParser::ParseGpuFreq(int64_t ts, ConstBytes blob) {
protos::pbzero::GpuFrequencyFtraceEvent::Decoder freq(blob.data, blob.size);
uint32_t gpu = freq.gpu_id();
uint32_t new_freq = freq.state();
- context_->event_tracker->PushCounter(ts, new_freq, gpu_freq_name_id_, gpu,
- RefType::kRefGpuId);
+ TrackId track =
+ context_->track_tracker->InternGpuCounterTrack(gpu_freq_name_id_, gpu);
+ context_->event_tracker->PushCounter(ts, new_freq, track);
}
void FtraceParser::ParseCpuIdle(int64_t ts, ConstBytes blob) {
protos::pbzero::CpuIdleFtraceEvent::Decoder idle(blob.data, blob.size);
uint32_t cpu = idle.cpu_id();
uint32_t new_state = idle.state();
- context_->event_tracker->PushCounter(ts, new_state, cpu_idle_name_id_, cpu,
- RefType::kRefCpuId);
+ TrackId track =
+ context_->track_tracker->InternCpuCounterTrack(cpu_idle_name_id_, cpu);
+ context_->event_tracker->PushCounter(ts, new_state, track);
}
void FtraceParser::ParsePrint(uint32_t,
@@ -524,8 +527,8 @@
if (size >= 0) {
UniqueTid utid = context_->process_tracker->GetOrCreateThread(pid);
- context_->event_tracker->PushCounter(ts, size, rss_members_[member], utid,
- RefType::kRefUtid, true);
+ context_->event_tracker->PushProcessCounterForThread(
+ ts, size, rss_members_[member], utid);
} else {
context_->storage->IncrementStats(stats::rss_stat_negative_size);
}
@@ -555,17 +558,18 @@
}
// Push the global counter.
- context_->event_tracker->PushCounter(ts, total_bytes, global_name_id, 0,
- RefType::kRefNoRef);
+ TrackId track =
+ context_->track_tracker->InternGlobalCounterTrack(global_name_id);
+ context_->event_tracker->PushCounter(ts, total_bytes, track);
// Push the change counter.
// TODO(b/121331269): these should really be instant events. For now we
// manually reset them to 0 after 1ns.
UniqueTid utid = context_->process_tracker->GetOrCreateThread(pid);
- context_->event_tracker->PushCounter(ts, change_bytes, change_name_id, utid,
- RefType::kRefUtid);
- context_->event_tracker->PushCounter(ts + 1, 0, change_name_id, utid,
- RefType::kRefUtid);
+ track =
+ context_->track_tracker->InternThreadCounterTrack(change_name_id, utid);
+ context_->event_tracker->PushCounter(ts, change_bytes, track);
+ context_->event_tracker->PushCounter(ts + 1, 0, track);
// We are reusing the same function for ion_heap_grow and ion_heap_shrink.
// It is fine as the arguments are the same, but we need to be sure that the
@@ -638,8 +642,8 @@
int16_t oom_adj = static_cast<int16_t>(evt.oom_score_adj());
uint32_t tid = static_cast<uint32_t>(evt.pid());
UniqueTid utid = context_->process_tracker->GetOrCreateThread(tid);
- context_->event_tracker->PushCounter(ts, oom_adj, oom_score_adj_id_, utid,
- RefType::kRefUtid, true);
+ context_->event_tracker->PushProcessCounterForThread(ts, oom_adj,
+ oom_score_adj_id_, utid);
}
void FtraceParser::ParseMmEventRecord(int64_t ts,
@@ -655,12 +659,12 @@
}
const auto& counter_names = mm_event_counter_names_[type];
- context_->event_tracker->PushCounter(ts, evt.count(), counter_names.count,
- utid, RefType::kRefUtid, true);
- context_->event_tracker->PushCounter(ts, evt.max_lat(), counter_names.max_lat,
- utid, RefType::kRefUtid, true);
- context_->event_tracker->PushCounter(ts, evt.avg_lat(), counter_names.avg_lat,
- utid, RefType::kRefUtid, true);
+ context_->event_tracker->PushProcessCounterForThread(
+ ts, evt.count(), counter_names.count, utid);
+ context_->event_tracker->PushProcessCounterForThread(
+ ts, evt.max_lat(), counter_names.max_lat, utid);
+ context_->event_tracker->PushProcessCounterForThread(
+ ts, evt.avg_lat(), counter_names.avg_lat, utid);
}
void FtraceParser::ParseSysEvent(int64_t ts,
diff --git a/src/trace_processor/importers/ftrace/ftrace_tokenizer.cc b/src/trace_processor/importers/ftrace/ftrace_tokenizer.cc
index 8a183a7..10c6aaf 100644
--- a/src/trace_processor/importers/ftrace/ftrace_tokenizer.cc
+++ b/src/trace_processor/importers/ftrace/ftrace_tokenizer.cc
@@ -73,7 +73,7 @@
// Build the interning table for next_comm fields.
std::vector<StringId> string_table;
string_table.reserve(512);
- for (auto it = compact.switch_next_comm_table(); it; it++) {
+ for (auto it = compact.intern_table(); it; it++) {
StringId value = context_->storage->InternString(*it);
string_table.push_back(value);
}
diff --git a/src/trace_processor/importers/fuchsia/fuchsia_trace_parser.cc b/src/trace_processor/importers/fuchsia/fuchsia_trace_parser.cc
index 56854ff..a362d8e 100644
--- a/src/trace_processor/importers/fuchsia/fuchsia_trace_parser.cc
+++ b/src/trace_processor/importers/fuchsia/fuchsia_trace_parser.cc
@@ -305,11 +305,11 @@
break;
}
if (is_valid_value) {
- context_->event_tracker->PushCounter(
- ts, counter_value,
- context_->storage->InternString(
- base::StringView(counter_name_str)),
- utid, RefType::kRefUtid);
+ StringId counter_name_id = context_->storage->InternString(
+ base::StringView(counter_name_str));
+ TrackId track = context_->track_tracker->InternThreadCounterTrack(
+ counter_name_id, utid);
+ context_->event_tracker->PushCounter(ts, counter_value, track);
}
}
break;
diff --git a/src/trace_processor/importers/proto/android_probes_parser.cc b/src/trace_processor/importers/proto/android_probes_parser.cc
index a72d354..f193885 100644
--- a/src/trace_processor/importers/proto/android_probes_parser.cc
+++ b/src/trace_processor/importers/proto/android_probes_parser.cc
@@ -51,21 +51,25 @@
void AndroidProbesParser::ParseBatteryCounters(int64_t ts, ConstBytes blob) {
protos::pbzero::BatteryCounters::Decoder evt(blob.data, blob.size);
if (evt.has_charge_counter_uah()) {
- context_->event_tracker->PushCounter(
- ts, evt.charge_counter_uah(), batt_charge_id_, 0, RefType::kRefNoRef);
+ TrackId track =
+ context_->track_tracker->InternGlobalCounterTrack(batt_charge_id_);
+ context_->event_tracker->PushCounter(ts, evt.charge_counter_uah(), track);
}
if (evt.has_capacity_percent()) {
+ TrackId track =
+ context_->track_tracker->InternGlobalCounterTrack(batt_capacity_id_);
context_->event_tracker->PushCounter(
- ts, static_cast<double>(evt.capacity_percent()), batt_capacity_id_, 0,
- RefType::kRefNoRef);
+ ts, static_cast<double>(evt.capacity_percent()), track);
}
if (evt.has_current_ua()) {
- context_->event_tracker->PushCounter(ts, evt.current_ua(), batt_current_id_,
- 0, RefType::kRefNoRef);
+ TrackId track =
+ context_->track_tracker->InternGlobalCounterTrack(batt_current_id_);
+ context_->event_tracker->PushCounter(ts, evt.current_ua(), track);
}
if (evt.has_current_avg_ua()) {
- context_->event_tracker->PushCounter(
- ts, evt.current_avg_ua(), batt_current_avg_id_, 0, RefType::kRefNoRef);
+ TrackId track =
+ context_->track_tracker->InternGlobalCounterTrack(batt_current_avg_id_);
+ context_->event_tracker->PushCounter(ts, evt.current_avg_ua(), track);
}
}
@@ -97,9 +101,9 @@
desc.has_timestamp_ms()
? static_cast<int64_t>(desc.timestamp_ms()) * 1000000
: ts;
- context_->event_tracker->PushCounter(actual_ts, desc.energy(),
- power_rails_strs_id_[desc.index()],
- 0, RefType::kRefNoRef);
+ TrackId track = context_->track_tracker->InternGlobalCounterTrack(
+ power_rails_strs_id_[desc.index()]);
+ context_->event_tracker->PushCounter(actual_ts, desc.energy(), track);
} else {
context_->storage->IncrementStats(stats::power_rail_unknown_index);
}
diff --git a/src/trace_processor/importers/proto/graphics_event_parser.cc b/src/trace_processor/importers/proto/graphics_event_parser.cc
index 2764a8f..9b08198 100644
--- a/src/trace_processor/importers/proto/graphics_event_parser.cc
+++ b/src/trace_processor/importers/proto/graphics_event_parser.cc
@@ -116,7 +116,8 @@
auto counter_id = spec.counter_id();
auto name = spec.name();
- if (gpu_counter_ids_.find(counter_id) == gpu_counter_ids_.end()) {
+ if (gpu_counter_track_ids_.find(counter_id) ==
+ gpu_counter_track_ids_.end()) {
auto desc = spec.description();
StringId unit_id = 0;
@@ -140,10 +141,9 @@
auto name_id = context_->storage->InternString(name);
auto desc_id = context_->storage->InternString(desc);
- auto* definitions = context_->storage->mutable_counter_definitions();
- auto defn_id = definitions->AddCounterDefinition(
- name_id, 0, RefType::kRefGpuId, desc_id, unit_id);
- gpu_counter_ids_.emplace(counter_id, defn_id);
+ auto track_id = context_->track_tracker->CreateGpuCounterTrack(
+ name_id, 0 /* gpu_id */, desc_id, unit_id);
+ gpu_counter_track_ids_.emplace(counter_id, track_id);
} else {
// Either counter spec was repeated or it came after counter data.
PERFETTO_ELOG("Duplicated counter spec found. (counter_id=%d, name=%s)",
@@ -158,25 +158,26 @@
(counter.has_int_value() || counter.has_double_value())) {
auto counter_id = counter.counter_id();
// Check missing counter_id
- if (gpu_counter_ids_.find(counter_id) == gpu_counter_ids_.end()) {
+ if (gpu_counter_track_ids_.find(counter_id) ==
+ gpu_counter_track_ids_.end()) {
char buffer[64];
base::StringWriter writer(buffer, sizeof(buffer));
writer.AppendString("gpu_counter(");
writer.AppendUnsignedInt(counter_id);
writer.AppendString(")");
auto name_id = context_->storage->InternString(writer.GetStringView());
- auto* definitions = context_->storage->mutable_counter_definitions();
- auto defn_id =
- definitions->AddCounterDefinition(name_id, 0, RefType::kRefGpuId);
- gpu_counter_ids_.emplace(counter_id, defn_id);
+
+ TrackId track = context_->track_tracker->CreateGpuCounterTrack(
+ name_id, 0 /* gpu_id */);
+ gpu_counter_track_ids_.emplace(counter_id, track);
context_->storage->IncrementStats(stats::gpu_counters_missing_spec);
}
if (counter.has_int_value()) {
- context_->event_tracker->PushCounter(ts, counter.int_value(),
- gpu_counter_ids_[counter_id]);
+ context_->event_tracker->PushCounter(
+ ts, counter.int_value(), gpu_counter_track_ids_[counter_id]);
} else {
- context_->event_tracker->PushCounter(ts, counter.double_value(),
- gpu_counter_ids_[counter_id]);
+ context_->event_tracker->PushCounter(
+ ts, counter.double_value(), gpu_counter_track_ids_[counter_id]);
}
}
}
@@ -337,61 +338,71 @@
} else if (type == VulkanMemoryEvent::DESTROY) {
vulkan_allocated_host_memory_ -= allocation_size;
}
+ TrackId track = context_->track_tracker->InternProcessCounterTrack(
+ vulkan_allocated_host_memory_id_, upid);
context_->event_tracker->PushCounter(ts, vulkan_allocated_host_memory_,
- vulkan_allocated_host_memory_id_, upid,
- RefType::kRefUpid);
+ track);
} else if (source == VulkanMemoryEvent::GPU_DEVICE_MEMORY) {
if (type == VulkanMemoryEvent::CREATE) {
vulkan_allocated_gpu_memory_ += allocation_size;
} else if (type == VulkanMemoryEvent::DESTROY) {
vulkan_allocated_gpu_memory_ -= allocation_size;
}
+ TrackId track = context_->track_tracker->InternProcessCounterTrack(
+ vulkan_allocated_gpu_memory_id_, upid);
context_->event_tracker->PushCounter(ts, vulkan_allocated_gpu_memory_,
- vulkan_allocated_gpu_memory_id_, upid,
- RefType::kRefUpid);
+ track);
} else if (source == VulkanMemoryEvent::GPU_BUFFER) {
if (type == VulkanMemoryEvent::CREATE) {
vulkan_live_buffer_objects_ += 1;
+ TrackId track = context_->track_tracker->InternProcessCounterTrack(
+ vulkan_live_buffer_objects_id_, upid);
context_->event_tracker->PushCounter(ts, vulkan_live_buffer_objects_,
- vulkan_live_buffer_objects_id_, upid,
- RefType::kRefUpid);
+ track);
} else if (type == VulkanMemoryEvent::DESTROY) {
vulkan_live_buffer_objects_ -= 1;
+ TrackId track = context_->track_tracker->InternProcessCounterTrack(
+ vulkan_live_buffer_objects_id_, upid);
context_->event_tracker->PushCounter(ts, vulkan_live_buffer_objects_,
- vulkan_live_buffer_objects_id_, upid,
- RefType::kRefUpid);
+ track);
} else if (type == VulkanMemoryEvent::BIND) {
vulkan_bound_buffer_objects_ += 1;
+ TrackId track = context_->track_tracker->InternProcessCounterTrack(
+ vulkan_bound_buffer_objects_id_, upid);
context_->event_tracker->PushCounter(ts, vulkan_bound_buffer_objects_,
- vulkan_bound_buffer_objects_id_,
- upid, RefType::kRefUpid);
+ track);
} else if (type == VulkanMemoryEvent::DESTROY_BOUND) {
vulkan_bound_buffer_objects_ -= 1;
+ TrackId track = context_->track_tracker->InternProcessCounterTrack(
+ vulkan_bound_buffer_objects_id_, upid);
context_->event_tracker->PushCounter(ts, vulkan_bound_buffer_objects_,
- vulkan_bound_buffer_objects_id_,
- upid, RefType::kRefUpid);
+ track);
}
} else if (source == VulkanMemoryEvent::GPU_IMAGE) {
if (type == VulkanMemoryEvent::CREATE) {
vulkan_live_image_objects_ += 1;
+ TrackId track = context_->track_tracker->InternProcessCounterTrack(
+ vulkan_live_image_objects_id_, upid);
context_->event_tracker->PushCounter(ts, vulkan_live_image_objects_,
- vulkan_live_image_objects_id_, upid,
- RefType::kRefUpid);
+ track);
} else if (type == VulkanMemoryEvent::DESTROY) {
vulkan_live_image_objects_ -= 1;
+ TrackId track = context_->track_tracker->InternProcessCounterTrack(
+ vulkan_live_image_objects_id_, upid);
context_->event_tracker->PushCounter(ts, vulkan_live_image_objects_,
- vulkan_live_image_objects_id_, upid,
- RefType::kRefUpid);
+ track);
} else if (type == VulkanMemoryEvent::BIND) {
vulkan_bound_image_objects_ += 1;
+ TrackId track = context_->track_tracker->InternProcessCounterTrack(
+ vulkan_bound_image_objects_id_, upid);
context_->event_tracker->PushCounter(ts, vulkan_bound_image_objects_,
- vulkan_bound_image_objects_id_, upid,
- RefType::kRefUpid);
+ track);
} else if (type == VulkanMemoryEvent::DESTROY_BOUND) {
vulkan_bound_image_objects_ -= 1;
+ TrackId track = context_->track_tracker->InternProcessCounterTrack(
+ vulkan_bound_image_objects_id_, upid);
context_->event_tracker->PushCounter(ts, vulkan_bound_image_objects_,
- vulkan_bound_image_objects_id_, upid,
- RefType::kRefUpid);
+ track);
}
}
}
diff --git a/src/trace_processor/importers/proto/graphics_event_parser.h b/src/trace_processor/importers/proto/graphics_event_parser.h
index 99e5635..35a9c2f 100644
--- a/src/trace_processor/importers/proto/graphics_event_parser.h
+++ b/src/trace_processor/importers/proto/graphics_event_parser.h
@@ -55,8 +55,7 @@
private:
TraceProcessorContext* const context_;
// For GpuCounterEvent
- std::unordered_map<uint32_t, const TraceStorage::CounterDefinitions::Id>
- gpu_counter_ids_;
+ std::unordered_map<uint32_t, TrackId> gpu_counter_track_ids_;
// For GpuRenderStageEvent
const StringId gpu_render_stage_scope_id_;
std::vector<TrackId> gpu_hw_queue_ids_;
diff --git a/src/trace_processor/importers/proto/heap_graph_walker_unittest.cc b/src/trace_processor/importers/proto/heap_graph_walker_unittest.cc
index 74b98e7..29b2a3f 100644
--- a/src/trace_processor/importers/proto/heap_graph_walker_unittest.cc
+++ b/src/trace_processor/importers/proto/heap_graph_walker_unittest.cc
@@ -356,6 +356,37 @@
EXPECT_EQ(delegate.UniqueRetained(2), 3);
}
+// We defined unique_retained as follows:
+// the number of bytes that are only retained through this object.
+// if this object were destroyed, this many bytes would be freed up.
+// The following test-case is a counter-example for the current
+// implementation.
+// 2<->3 |
+// ^ |
+// | |
+// 1 |
+TEST(HeapGraphWalkerTest, DISABLED_UnreachableComponent) {
+ HeapGraphWalkerTestDelegate delegate;
+ HeapGraphWalker walker(&delegate);
+ walker.AddNode(1, 1);
+ walker.AddNode(2, 2);
+ walker.AddNode(3, 3);
+
+ walker.AddEdge(1, 2);
+ walker.AddEdge(2, 3);
+ walker.AddEdge(3, 2);
+
+ walker.MarkRoot(1);
+ walker.CalculateRetained();
+
+ EXPECT_EQ(delegate.Retained(1), 6);
+ EXPECT_EQ(delegate.Retained(2), 5);
+ EXPECT_EQ(delegate.Retained(3), 5);
+
+ EXPECT_EQ(delegate.UniqueRetained(1), 6);
+ EXPECT_EQ(delegate.UniqueRetained(2), 5);
+ EXPECT_EQ(delegate.UniqueRetained(3), 3);
+}
} // namespace
} // namespace trace_processor
} // namespace perfetto
diff --git a/src/trace_processor/importers/proto/packet_sequence_state.h b/src/trace_processor/importers/proto/packet_sequence_state.h
index 8ee597b..b6bc5a6 100644
--- a/src/trace_processor/importers/proto/packet_sequence_state.h
+++ b/src/trace_processor/importers/proto/packet_sequence_state.h
@@ -22,6 +22,7 @@
#include <unordered_map>
#include <vector>
+#include "perfetto/base/compiler.h"
#include "perfetto/protozero/proto_decoder.h"
#include "src/trace_processor/stack_profile_tracker.h"
#include "src/trace_processor/trace_blob_view.h"
@@ -31,13 +32,13 @@
namespace perfetto {
namespace trace_processor {
-#if PERFETTO_DCHECK_IS_ON() && defined(__GNUC__)
-// When called from GetOrCreateDecoder(), __PRETTY_FUNCTION__ (supported by GCC
-// + clang) should include the stringified name of the MessageType.
-#define PERFETTO_TYPE_IDENTIFIER __PRETTY_FUNCTION__
-#else // PERFETTO_DCHECK_IS_ON() && defined(__GNUC__)
+#if PERFETTO_DCHECK_IS_ON()
+// When called from GetOrCreateDecoder(), should include the stringified name of
+// the MessageType.
+#define PERFETTO_TYPE_IDENTIFIER PERFETTO_DEBUG_FUNCTION_IDENTIFIER()
+#else // PERFETTO_DCHECK_IS_ON()
#define PERFETTO_TYPE_IDENTIFIER nullptr
-#endif // PERFETTO_DCHECK_IS_ON() && defined(__GNUC__)
+#endif // PERFETTO_DCHECK_IS_ON()
class PacketSequenceState {
public:
diff --git a/src/trace_processor/importers/proto/proto_trace_parser.cc b/src/trace_processor/importers/proto/proto_trace_parser.cc
index 6144550..0811da4 100644
--- a/src/trace_processor/importers/proto/proto_trace_parser.cc
+++ b/src/trace_processor/importers/proto/proto_trace_parser.cc
@@ -588,8 +588,9 @@
sprintf(fallback, "Counter %d", cid);
name_id = context_->storage->InternString(fallback);
}
- context_->event_tracker->PushCounter(ts, event.counter_value(), name_id,
- utid, RefType::kRefUtid);
+ TrackId track =
+ context_->track_tracker->InternThreadCounterTrack(name_id, utid);
+ context_->event_tracker->PushCounter(ts, event.counter_value(), track);
}
if (event.has_overruns())
diff --git a/src/trace_processor/importers/proto/proto_trace_parser_unittest.cc b/src/trace_processor/importers/proto/proto_trace_parser_unittest.cc
index f53c951..0d184a4 100644
--- a/src/trace_processor/importers/proto/proto_trace_parser_unittest.cc
+++ b/src/trace_processor/importers/proto/proto_trace_parser_unittest.cc
@@ -37,6 +37,7 @@
#include "src/trace_processor/slice_tracker.h"
#include "src/trace_processor/stack_profile_tracker.h"
#include "src/trace_processor/trace_sorter.h"
+#include "src/trace_processor/trace_storage.h"
#include "src/trace_processor/track_tracker.h"
#include "src/trace_processor/vulkan_memory_tracker.h"
#include "test/gtest_and_gmock.h"
@@ -136,13 +137,8 @@
base::StringView next_comm,
int32_t next_prio));
- MOCK_METHOD6(PushCounter,
- RowId(int64_t timestamp,
- double value,
- StringId name_id,
- int64_t ref,
- RefType ref_type,
- bool resolve_utid_to_upid));
+ MOCK_METHOD3(PushCounter,
+ RowId(int64_t timestamp, double value, uint32_t track_id));
MOCK_METHOD6(PushInstant,
RowId(int64_t timestamp,
@@ -609,9 +605,10 @@
cpu_freq->set_cpu_id(10);
cpu_freq->set_state(2000);
- EXPECT_CALL(*event_, PushCounter(1000, DoubleEq(2000), _, 10,
- RefType::kRefCpuId, false));
+ EXPECT_CALL(*event_, PushCounter(1000, DoubleEq(2000), 0));
Tokenize();
+
+ EXPECT_EQ(context_.storage->cpu_counter_track_table().cpu()[0], 10u);
}
#endif // PERFETTO_BUILDFLAG(PERFETTO_TP_FTRACE)
@@ -628,10 +625,11 @@
uint32_t value = 10;
meminfo->set_value(value);
- EXPECT_CALL(*event_,
- PushCounter(static_cast<int64_t>(ts), DoubleEq(value * 1024.0), _,
- 0, RefType::kRefNoRef, false));
+ EXPECT_CALL(*event_, PushCounter(static_cast<int64_t>(ts),
+ DoubleEq(value * 1024.0), 0u));
Tokenize();
+
+ EXPECT_EQ(context_.storage->track_table().size(), 1u);
}
TEST_F(ProtoTraceParserTest, LoadVmStats) {
@@ -644,9 +642,11 @@
uint32_t value = 10;
meminfo->set_value(value);
- EXPECT_CALL(*event_, PushCounter(static_cast<int64_t>(ts), DoubleEq(value), _,
- 0, RefType::kRefNoRef, false));
+ EXPECT_CALL(*event_,
+ PushCounter(static_cast<int64_t>(ts), DoubleEq(value), 0u));
Tokenize();
+
+ EXPECT_EQ(context_.storage->track_table().size(), 1u);
}
TEST_F(ProtoTraceParserTest, LoadProcessPacket) {
diff --git a/src/trace_processor/importers/proto/system_probes_parser.cc b/src/trace_processor/importers/proto/system_probes_parser.cc
index 3abfc85..14afab1 100644
--- a/src/trace_processor/importers/proto/system_probes_parser.cc
+++ b/src/trace_processor/importers/proto/system_probes_parser.cc
@@ -102,8 +102,9 @@
continue;
}
// /proc/meminfo counters are in kB, convert to bytes
- context_->event_tracker->PushCounter(
- ts, mi.value() * 1024L, meminfo_strs_id_[key], 0, RefType::kRefNoRef);
+ TrackId track = context_->track_tracker->InternGlobalCounterTrack(
+ meminfo_strs_id_[key]);
+ context_->event_tracker->PushCounter(ts, mi.value() * 1024L, track);
}
for (auto it = sys_stats.vmstat(); it; ++it) {
@@ -114,8 +115,9 @@
context_->storage->IncrementStats(stats::vmstat_unknown_keys);
continue;
}
- context_->event_tracker->PushCounter(ts, vm.value(), vmstat_strs_id_[key],
- 0, RefType::kRefNoRef);
+ TrackId track =
+ context_->track_tracker->InternGlobalCounterTrack(vmstat_strs_id_[key]);
+ context_->event_tracker->PushCounter(ts, vm.value(), track);
}
for (auto it = sys_stats.cpu_stat(); it; ++it) {
@@ -125,55 +127,69 @@
context_->storage->IncrementStats(stats::invalid_cpu_times);
continue;
}
- context_->event_tracker->PushCounter(ts, ct.user_ns(),
- cpu_times_user_ns_id_, ct.cpu_id(),
- RefType::kRefCpuId);
- context_->event_tracker->PushCounter(ts, ct.user_ice_ns(),
- cpu_times_user_nice_ns_id_,
- ct.cpu_id(), RefType::kRefCpuId);
- context_->event_tracker->PushCounter(ts, ct.system_mode_ns(),
- cpu_times_system_mode_ns_id_,
- ct.cpu_id(), RefType::kRefCpuId);
- context_->event_tracker->PushCounter(ts, ct.idle_ns(),
- cpu_times_idle_ns_id_, ct.cpu_id(),
- RefType::kRefCpuId);
- context_->event_tracker->PushCounter(ts, ct.io_wait_ns(),
- cpu_times_io_wait_ns_id_, ct.cpu_id(),
- RefType::kRefCpuId);
- context_->event_tracker->PushCounter(ts, ct.irq_ns(), cpu_times_irq_ns_id_,
- ct.cpu_id(), RefType::kRefCpuId);
- context_->event_tracker->PushCounter(ts, ct.softirq_ns(),
- cpu_times_softirq_ns_id_, ct.cpu_id(),
- RefType::kRefCpuId);
+
+ TrackId track = context_->track_tracker->InternCpuCounterTrack(
+ cpu_times_user_ns_id_, ct.cpu_id());
+ context_->event_tracker->PushCounter(ts, ct.user_ns(), track);
+
+ track = context_->track_tracker->InternCpuCounterTrack(
+ cpu_times_user_nice_ns_id_, ct.cpu_id());
+ context_->event_tracker->PushCounter(ts, ct.user_ice_ns(), track);
+
+ track = context_->track_tracker->InternCpuCounterTrack(
+ cpu_times_system_mode_ns_id_, ct.cpu_id());
+ context_->event_tracker->PushCounter(ts, ct.system_mode_ns(), track);
+
+ track = context_->track_tracker->InternCpuCounterTrack(
+ cpu_times_idle_ns_id_, ct.cpu_id());
+ context_->event_tracker->PushCounter(ts, ct.idle_ns(), track);
+
+ track = context_->track_tracker->InternCpuCounterTrack(
+ cpu_times_io_wait_ns_id_, ct.cpu_id());
+ context_->event_tracker->PushCounter(ts, ct.io_wait_ns(), track);
+
+ track = context_->track_tracker->InternCpuCounterTrack(cpu_times_irq_ns_id_,
+ ct.cpu_id());
+ context_->event_tracker->PushCounter(ts, ct.irq_ns(), track);
+
+ track = context_->track_tracker->InternCpuCounterTrack(
+ cpu_times_softirq_ns_id_, ct.cpu_id());
+ context_->event_tracker->PushCounter(ts, ct.softirq_ns(), track);
}
for (auto it = sys_stats.num_irq(); it; ++it) {
protos::pbzero::SysStats::InterruptCount::Decoder ic(*it);
- context_->event_tracker->PushCounter(ts, ic.count(), num_irq_name_id_,
- ic.irq(), RefType::kRefIrq);
+
+ TrackId track = context_->track_tracker->InternIrqCounterTrack(
+ num_irq_name_id_, ic.irq());
+ context_->event_tracker->PushCounter(ts, ic.count(), track);
}
for (auto it = sys_stats.num_softirq(); it; ++it) {
protos::pbzero::SysStats::InterruptCount::Decoder ic(*it);
- context_->event_tracker->PushCounter(ts, ic.count(), num_softirq_name_id_,
- ic.irq(), RefType::kRefSoftIrq);
+
+ TrackId track = context_->track_tracker->InternSoftirqCounterTrack(
+ num_softirq_name_id_, ic.irq());
+ context_->event_tracker->PushCounter(ts, ic.count(), track);
}
if (sys_stats.has_num_forks()) {
- context_->event_tracker->PushCounter(
- ts, sys_stats.num_forks(), num_forks_name_id_, 0, RefType::kRefNoRef);
+ TrackId track =
+ context_->track_tracker->InternGlobalCounterTrack(num_forks_name_id_);
+ context_->event_tracker->PushCounter(ts, sys_stats.num_forks(), track);
}
if (sys_stats.has_num_irq_total()) {
- context_->event_tracker->PushCounter(ts, sys_stats.num_irq_total(),
- num_irq_total_name_id_, 0,
- RefType::kRefNoRef);
+ TrackId track = context_->track_tracker->InternGlobalCounterTrack(
+ num_irq_total_name_id_);
+ context_->event_tracker->PushCounter(ts, sys_stats.num_irq_total(), track);
}
if (sys_stats.has_num_softirq_total()) {
+ TrackId track = context_->track_tracker->InternGlobalCounterTrack(
+ num_softirq_total_name_id_);
context_->event_tracker->PushCounter(ts, sys_stats.num_softirq_total(),
- num_softirq_total_name_id_, 0,
- RefType::kRefNoRef);
+ track);
}
}
@@ -254,8 +270,9 @@
StringId name = proc_stats_process_names_[field_id];
int64_t value = counter_values[field_id];
UniquePid upid = context_->process_tracker->GetOrCreateProcess(pid);
- context_->event_tracker->PushCounter(ts, value, name, upid,
- RefType::kRefUpid);
+ TrackId track =
+ context_->track_tracker->InternProcessCounterTrack(name, upid);
+ context_->event_tracker->PushCounter(ts, value, track);
}
}
}
diff --git a/src/trace_processor/importers/systrace/systrace_parser.cc b/src/trace_processor/importers/systrace/systrace_parser.cc
index 1587b32..9e336a6 100644
--- a/src/trace_processor/importers/systrace/systrace_parser.cc
+++ b/src/trace_processor/importers/systrace/systrace_parser.cc
@@ -131,8 +131,9 @@
UniquePid upid =
context_->process_tracker->GetOrCreateProcess(point.tgid);
StringId name_id = context_->storage->InternString(point.name);
- context_->event_tracker->PushCounter(ts, point.value, name_id, upid,
- RefType::kRefUpid);
+ TrackId track =
+ context_->track_tracker->InternProcessCounterTrack(name_id, upid);
+ context_->event_tracker->PushCounter(ts, point.value, track);
}
}
}
diff --git a/src/trace_processor/importers/systrace/systrace_trace_parser.cc b/src/trace_processor/importers/systrace/systrace_trace_parser.cc
index 6010be6..33d5cb1 100644
--- a/src/trace_processor/importers/systrace/systrace_trace_parser.cc
+++ b/src/trace_processor/importers/systrace/systrace_trace_parser.cc
@@ -24,6 +24,7 @@
#include "src/trace_processor/importers/systrace/systrace_parser.h"
#include "src/trace_processor/process_tracker.h"
#include "src/trace_processor/slice_tracker.h"
+#include "src/trace_processor/track_tracker.h"
#include <inttypes.h>
#include <string>
@@ -222,9 +223,10 @@
if (!event_cpu.has_value()) {
return util::Status("Could not convert state");
}
- context_->event_tracker->PushCounter(ts, new_state.value(),
- cpu_idle_name_id_, event_cpu.value(),
- RefType::kRefCpuId);
+
+ TrackId track = context_->track_tracker->InternCpuCounterTrack(
+ cpu_idle_name_id_, event_cpu.value());
+ context_->event_tracker->PushCounter(ts, new_state.value(), track);
}
return util::OkStatus();
diff --git a/src/trace_processor/instants_table.cc b/src/trace_processor/instants_table.cc
index 279e36c..e0a52ad 100644
--- a/src/trace_processor/instants_table.cc
+++ b/src/trace_processor/instants_table.cc
@@ -50,13 +50,13 @@
int InstantsTable::BestIndex(const QueryConstraints& qc, BestIndexInfo* info) {
info->estimated_cost =
static_cast<uint32_t>(storage_->instants().instant_count());
+ info->sqlite_omit_order_by = true;
// Only the string columns are handled by SQLite
- info->order_by_consumed = true;
size_t name_index = schema().ColumnIndexFromName("name");
size_t ref_type_index = schema().ColumnIndexFromName("ref_type");
for (size_t i = 0; i < qc.constraints().size(); i++) {
- info->omit[i] =
+ info->constraint_info[i].sqlite_omit =
qc.constraints()[i].iColumn != static_cast<int>(name_index) &&
qc.constraints()[i].iColumn != static_cast<int>(ref_type_index);
}
diff --git a/src/trace_processor/metrics/BUILD.gn b/src/trace_processor/metrics/BUILD.gn
index bfa95de..28d6f01 100644
--- a/src/trace_processor/metrics/BUILD.gn
+++ b/src/trace_processor/metrics/BUILD.gn
@@ -32,6 +32,7 @@
"android/android_startup_cpu.sql",
"android/android_package_list.sql",
"android/heap_profile_callsites.sql",
+ "android/java_heap_stats.sql",
"android/process_unagg_mem_view.sql",
"android/process_mem.sql",
"android/mem_stats_priority_breakdown.sql",
diff --git a/src/trace_processor/metrics/android/heap_profile_callsites.sql b/src/trace_processor/metrics/android/heap_profile_callsites.sql
index a0cd0c4..ce2aeb4 100644
--- a/src/trace_processor/metrics/android/heap_profile_callsites.sql
+++ b/src/trace_processor/metrics/android/heap_profile_callsites.sql
@@ -14,6 +14,17 @@
-- limitations under the License.
--
+CREATE VIEW memory_delta AS
+SELECT upid, SUM(size) AS delta
+FROM heap_profile_allocation
+GROUP BY 1;
+
+CREATE VIEW memory_total AS
+SELECT upid, SUM(size) AS total
+FROM heap_profile_allocation
+WHERE size > 0
+GROUP BY 1;
+
-- Join frames with symbols and mappings to get a textual representation.
CREATE TABLE symbolized_frame AS
SELECT
@@ -205,9 +216,14 @@
SELECT HeapProfileCallsites_InstanceStats(
'pid', process.pid,
'process_name', process.name,
- 'callsites', repeated_callsite_proto
+ 'callsites', repeated_callsite_proto,
+ 'profile_delta_bytes', memory_delta.delta,
+ 'profile_total_bytes', memory_total.total
) AS instance_stats_proto
-FROM process_callsite_proto JOIN process USING (upid);
+FROM process_callsite_proto
+JOIN memory_total USING (upid)
+JOIN memory_delta USING (upid)
+JOIN process USING (upid);
CREATE VIEW heap_profile_callsites_output AS
SELECT HeapProfileCallsites(
diff --git a/src/trace_processor/metrics/android/java_heap_stats.sql b/src/trace_processor/metrics/android/java_heap_stats.sql
new file mode 100644
index 0000000..d8f2f34
--- /dev/null
+++ b/src/trace_processor/metrics/android/java_heap_stats.sql
@@ -0,0 +1,58 @@
+--
+-- Copyright 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
+--
+-- https://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 VIEW total_size_samples AS
+SELECT upid, graph_sample_ts, SUM(self_size) AS total_size
+FROM heap_graph_object
+GROUP BY 1, 2;
+
+CREATE VIEW total_reachable_size_samples AS
+SELECT upid, graph_sample_ts, SUM(self_size) AS total_reachable_size
+FROM heap_graph_object
+WHERE reachable = TRUE
+GROUP BY 1, 2;
+
+CREATE TABLE heap_graph_samples AS
+SELECT upid, graph_sample_ts, total_size, total_reachable_size
+FROM total_size_samples JOIN total_reachable_size_samples
+USING (upid, graph_sample_ts);
+
+CREATE VIEW heap_graph_sample_protos AS
+SELECT
+ upid,
+ JavaHeapStats_Sample(
+ 'ts', graph_sample_ts,
+ 'heap_size', total_size,
+ 'reachable_heap_size', total_reachable_size
+ ) sample_proto
+FROM heap_graph_samples;
+
+CREATE TABLE heap_graph_instance_stats AS
+SELECT
+ upid,
+ process.name process_name,
+ RepeatedField(sample_proto) AS sample_protos
+FROM heap_graph_sample_protos JOIN process USING (upid)
+GROUP BY 1, 2;
+
+CREATE VIEW java_heap_stats_output AS
+SELECT JavaHeapStats(
+ 'instance_stats', RepeatedField(JavaHeapStats_InstanceStats(
+ 'upid', upid,
+ 'process_name', process_name,
+ 'samples', sample_protos
+ )))
+FROM heap_graph_instance_stats;
diff --git a/src/trace_processor/metrics/metrics.descriptor.h b/src/trace_processor/metrics/metrics.descriptor.h
index 9a19aa6..df7696c 100644
--- a/src/trace_processor/metrics/metrics.descriptor.h
+++ b/src/trace_processor/metrics/metrics.descriptor.h
@@ -12,14 +12,14 @@
// SHA1(tools/gen_binary_descriptors)
// 192b582ae52bb07b3d3ba66a94bcfd3127a5f42f
// SHA1(protos/perfetto/metrics/metrics.proto)
-// 9410d04aaa3afacc42cdfa881f34ab41f3bff56b
+// 4279eeace6a7d9647e484e65b8265ea211a02b6c
// This is the proto Metrics encoded as a ProtoFileDescriptor to allow
// for reflection without libprotobuf full/non-lite protos.
namespace perfetto {
-constexpr std::array<uint8_t, 9635> kMetricsDescriptor{
+constexpr std::array<uint8_t, 10312> kMetricsDescriptor{
{0x0a, 0x98, 0x03, 0x0a, 0x31, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2f,
0x70, 0x65, 0x72, 0x66, 0x65, 0x74, 0x74, 0x6f, 0x2f, 0x6d, 0x65, 0x74,
0x72, 0x69, 0x63, 0x73, 0x2f, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64,
@@ -540,14 +540,14 @@
0x72, 0x74, 0x75, 0x70, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x2e, 0x54,
0x6f, 0x46, 0x69, 0x72, 0x73, 0x74, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x52,
0x0c, 0x74, 0x6f, 0x46, 0x69, 0x72, 0x73, 0x74, 0x46, 0x72, 0x61, 0x6d,
- 0x65, 0x42, 0x02, 0x48, 0x03, 0x0a, 0xd7, 0x06, 0x0a, 0x3c, 0x70, 0x72,
+ 0x65, 0x42, 0x02, 0x48, 0x03, 0x0a, 0xb7, 0x07, 0x0a, 0x3c, 0x70, 0x72,
0x6f, 0x74, 0x6f, 0x73, 0x2f, 0x70, 0x65, 0x72, 0x66, 0x65, 0x74, 0x74,
0x6f, 0x2f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2f, 0x61, 0x6e,
0x64, 0x72, 0x6f, 0x69, 0x64, 0x2f, 0x68, 0x65, 0x61, 0x70, 0x5f, 0x70,
0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x5f, 0x63, 0x61, 0x6c, 0x6c, 0x73,
0x69, 0x74, 0x65, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0f,
0x70, 0x65, 0x72, 0x66, 0x65, 0x74, 0x74, 0x6f, 0x2e, 0x70, 0x72, 0x6f,
- 0x74, 0x6f, 0x73, 0x22, 0x81, 0x06, 0x0a, 0x14, 0x48, 0x65, 0x61, 0x70,
+ 0x74, 0x6f, 0x73, 0x22, 0xe1, 0x06, 0x0a, 0x14, 0x48, 0x65, 0x61, 0x70,
0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x43, 0x61, 0x6c, 0x6c, 0x73,
0x69, 0x74, 0x65, 0x73, 0x12, 0x5a, 0x0a, 0x0e, 0x69, 0x6e, 0x73, 0x74,
0x61, 0x6e, 0x63, 0x65, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x73, 0x18, 0x01,
@@ -599,7 +599,7 @@
0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x43, 0x61, 0x6c, 0x6c, 0x73,
0x69, 0x74, 0x65, 0x73, 0x2e, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72,
0x73, 0x52, 0x0b, 0x63, 0x68, 0x69, 0x6c, 0x64, 0x41, 0x6c, 0x6c, 0x6f,
- 0x63, 0x73, 0x1a, 0x92, 0x01, 0x0a, 0x0d, 0x49, 0x6e, 0x73, 0x74, 0x61,
+ 0x63, 0x73, 0x1a, 0xf2, 0x01, 0x0a, 0x0d, 0x49, 0x6e, 0x73, 0x74, 0x61,
0x6e, 0x63, 0x65, 0x53, 0x74, 0x61, 0x74, 0x73, 0x12, 0x10, 0x0a, 0x03,
0x70, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x03, 0x70,
0x69, 0x64, 0x12, 0x21, 0x0a, 0x0c, 0x70, 0x72, 0x6f, 0x63, 0x65, 0x73,
@@ -611,7 +611,15 @@
0x6f, 0x73, 0x2e, 0x48, 0x65, 0x61, 0x70, 0x50, 0x72, 0x6f, 0x66, 0x69,
0x6c, 0x65, 0x43, 0x61, 0x6c, 0x6c, 0x73, 0x69, 0x74, 0x65, 0x73, 0x2e,
0x43, 0x61, 0x6c, 0x6c, 0x73, 0x69, 0x74, 0x65, 0x52, 0x09, 0x63, 0x61,
- 0x6c, 0x6c, 0x73, 0x69, 0x74, 0x65, 0x73, 0x42, 0x02, 0x48, 0x03, 0x0a,
+ 0x6c, 0x6c, 0x73, 0x69, 0x74, 0x65, 0x73, 0x12, 0x2e, 0x0a, 0x13, 0x70,
+ 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x5f, 0x64, 0x65, 0x6c, 0x74, 0x61,
+ 0x5f, 0x62, 0x79, 0x74, 0x65, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03,
+ 0x52, 0x11, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x44, 0x65, 0x6c,
+ 0x74, 0x61, 0x42, 0x79, 0x74, 0x65, 0x73, 0x12, 0x2e, 0x0a, 0x13, 0x70,
+ 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x5f, 0x74, 0x6f, 0x74, 0x61, 0x6c,
+ 0x5f, 0x62, 0x79, 0x74, 0x65, 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x03,
+ 0x52, 0x11, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x54, 0x6f, 0x74,
+ 0x61, 0x6c, 0x42, 0x79, 0x74, 0x65, 0x73, 0x42, 0x02, 0x48, 0x03, 0x0a,
0x8c, 0x02, 0x0a, 0x32, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2f, 0x70,
0x65, 0x72, 0x66, 0x65, 0x74, 0x74, 0x6f, 0x2f, 0x6d, 0x65, 0x74, 0x72,
0x69, 0x63, 0x73, 0x2f, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x2f,
@@ -656,173 +664,222 @@
0x62, 0x75, 0x69, 0x6c, 0x64, 0x49, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x61,
0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03,
0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x42, 0x02, 0x48,
- 0x03, 0x0a, 0xcf, 0x0f, 0x0a, 0x25, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73,
- 0x2f, 0x70, 0x65, 0x72, 0x66, 0x65, 0x74, 0x74, 0x6f, 0x2f, 0x6d, 0x65,
- 0x74, 0x72, 0x69, 0x63, 0x73, 0x2f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63,
- 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0f, 0x70, 0x65, 0x72,
- 0x66, 0x65, 0x74, 0x74, 0x6f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73,
- 0x1a, 0x31, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2f, 0x70, 0x65, 0x72,
- 0x66, 0x65, 0x74, 0x74, 0x6f, 0x2f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63,
- 0x73, 0x2f, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x2f, 0x62, 0x61,
- 0x74, 0x74, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x2e, 0x70, 0x72,
- 0x6f, 0x74, 0x6f, 0x1a, 0x30, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2f,
- 0x70, 0x65, 0x72, 0x66, 0x65, 0x74, 0x74, 0x6f, 0x2f, 0x6d, 0x65, 0x74,
- 0x72, 0x69, 0x63, 0x73, 0x2f, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64,
- 0x2f, 0x63, 0x70, 0x75, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x2e,
- 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x30, 0x70, 0x72, 0x6f, 0x74, 0x6f,
- 0x73, 0x2f, 0x70, 0x65, 0x72, 0x66, 0x65, 0x74, 0x74, 0x6f, 0x2f, 0x6d,
- 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2f, 0x61, 0x6e, 0x64, 0x72, 0x6f,
- 0x69, 0x64, 0x2f, 0x6d, 0x65, 0x6d, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69,
- 0x63, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x36, 0x70, 0x72, 0x6f,
- 0x74, 0x6f, 0x73, 0x2f, 0x70, 0x65, 0x72, 0x66, 0x65, 0x74, 0x74, 0x6f,
- 0x2f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2f, 0x61, 0x6e, 0x64,
- 0x72, 0x6f, 0x69, 0x64, 0x2f, 0x6d, 0x65, 0x6d, 0x5f, 0x75, 0x6e, 0x61,
- 0x67, 0x67, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x2e, 0x70, 0x72,
- 0x6f, 0x74, 0x6f, 0x1a, 0x34, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2f,
- 0x70, 0x65, 0x72, 0x66, 0x65, 0x74, 0x74, 0x6f, 0x2f, 0x6d, 0x65, 0x74,
- 0x72, 0x69, 0x63, 0x73, 0x2f, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64,
- 0x2f, 0x70, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x5f, 0x67, 0x72, 0x6f,
- 0x77, 0x74, 0x68, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x30, 0x70,
- 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2f, 0x70, 0x65, 0x72, 0x66, 0x65, 0x74,
- 0x74, 0x6f, 0x2f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2f, 0x61,
- 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x2f, 0x69, 0x6f, 0x6e, 0x5f, 0x6d,
- 0x65, 0x74, 0x72, 0x69, 0x63, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a,
- 0x30, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2f, 0x70, 0x65, 0x72, 0x66,
- 0x65, 0x74, 0x74, 0x6f, 0x2f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73,
- 0x2f, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x2f, 0x6c, 0x6d, 0x6b,
- 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x2e, 0x70, 0x72, 0x6f, 0x74,
- 0x6f, 0x1a, 0x35, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2f, 0x70, 0x65,
- 0x72, 0x66, 0x65, 0x74, 0x74, 0x6f, 0x2f, 0x6d, 0x65, 0x74, 0x72, 0x69,
- 0x63, 0x73, 0x2f, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x2f, 0x70,
- 0x6f, 0x77, 0x72, 0x61, 0x69, 0x6c, 0x73, 0x5f, 0x6d, 0x65, 0x74, 0x72,
- 0x69, 0x63, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x34, 0x70, 0x72,
- 0x6f, 0x74, 0x6f, 0x73, 0x2f, 0x70, 0x65, 0x72, 0x66, 0x65, 0x74, 0x74,
- 0x6f, 0x2f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2f, 0x61, 0x6e,
- 0x64, 0x72, 0x6f, 0x69, 0x64, 0x2f, 0x73, 0x74, 0x61, 0x72, 0x74, 0x75,
- 0x70, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x2e, 0x70, 0x72, 0x6f,
- 0x74, 0x6f, 0x1a, 0x3c, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2f, 0x70,
- 0x65, 0x72, 0x66, 0x65, 0x74, 0x74, 0x6f, 0x2f, 0x6d, 0x65, 0x74, 0x72,
- 0x69, 0x63, 0x73, 0x2f, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x2f,
- 0x68, 0x65, 0x61, 0x70, 0x5f, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65,
- 0x5f, 0x63, 0x61, 0x6c, 0x6c, 0x73, 0x69, 0x74, 0x65, 0x73, 0x2e, 0x70,
- 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x32, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73,
+ 0x03, 0x0a, 0xa4, 0x03, 0x0a, 0x35, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73,
0x2f, 0x70, 0x65, 0x72, 0x66, 0x65, 0x74, 0x74, 0x6f, 0x2f, 0x6d, 0x65,
0x74, 0x72, 0x69, 0x63, 0x73, 0x2f, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69,
- 0x64, 0x2f, 0x70, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x5f, 0x6c, 0x69,
- 0x73, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x39, 0x70, 0x72,
+ 0x64, 0x2f, 0x6a, 0x61, 0x76, 0x61, 0x5f, 0x68, 0x65, 0x61, 0x70, 0x5f,
+ 0x73, 0x74, 0x61, 0x74, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12,
+ 0x0f, 0x70, 0x65, 0x72, 0x66, 0x65, 0x74, 0x74, 0x6f, 0x2e, 0x70, 0x72,
+ 0x6f, 0x74, 0x6f, 0x73, 0x22, 0xd5, 0x02, 0x0a, 0x0d, 0x4a, 0x61, 0x76,
+ 0x61, 0x48, 0x65, 0x61, 0x70, 0x53, 0x74, 0x61, 0x74, 0x73, 0x12, 0x53,
+ 0x0a, 0x0e, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x5f, 0x73,
+ 0x74, 0x61, 0x74, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2c,
+ 0x2e, 0x70, 0x65, 0x72, 0x66, 0x65, 0x74, 0x74, 0x6f, 0x2e, 0x70, 0x72,
+ 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x4a, 0x61, 0x76, 0x61, 0x48, 0x65, 0x61,
+ 0x70, 0x53, 0x74, 0x61, 0x74, 0x73, 0x2e, 0x49, 0x6e, 0x73, 0x74, 0x61,
+ 0x6e, 0x63, 0x65, 0x53, 0x74, 0x61, 0x74, 0x73, 0x52, 0x0d, 0x69, 0x6e,
+ 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x53, 0x74, 0x61, 0x74, 0x73, 0x1a,
+ 0x65, 0x0a, 0x06, 0x53, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x12, 0x0e, 0x0a,
+ 0x02, 0x74, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x02, 0x74,
+ 0x73, 0x12, 0x1b, 0x0a, 0x09, 0x68, 0x65, 0x61, 0x70, 0x5f, 0x73, 0x69,
+ 0x7a, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x08, 0x68, 0x65,
+ 0x61, 0x70, 0x53, 0x69, 0x7a, 0x65, 0x12, 0x2e, 0x0a, 0x13, 0x72, 0x65,
+ 0x61, 0x63, 0x68, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x68, 0x65, 0x61, 0x70,
+ 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52,
+ 0x11, 0x72, 0x65, 0x61, 0x63, 0x68, 0x61, 0x62, 0x6c, 0x65, 0x48, 0x65,
+ 0x61, 0x70, 0x53, 0x69, 0x7a, 0x65, 0x1a, 0x87, 0x01, 0x0a, 0x0d, 0x49,
+ 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x53, 0x74, 0x61, 0x74, 0x73,
+ 0x12, 0x12, 0x0a, 0x04, 0x75, 0x70, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01,
+ 0x28, 0x0d, 0x52, 0x04, 0x75, 0x70, 0x69, 0x64, 0x12, 0x21, 0x0a, 0x0c,
+ 0x70, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x5f, 0x6e, 0x61, 0x6d, 0x65,
+ 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x70, 0x72, 0x6f, 0x63,
+ 0x65, 0x73, 0x73, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x3f, 0x0a, 0x07, 0x73,
+ 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b,
+ 0x32, 0x25, 0x2e, 0x70, 0x65, 0x72, 0x66, 0x65, 0x74, 0x74, 0x6f, 0x2e,
+ 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x4a, 0x61, 0x76, 0x61, 0x48,
+ 0x65, 0x61, 0x70, 0x53, 0x74, 0x61, 0x74, 0x73, 0x2e, 0x53, 0x61, 0x6d,
+ 0x70, 0x6c, 0x65, 0x52, 0x07, 0x73, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73,
+ 0x42, 0x02, 0x48, 0x03, 0x0a, 0xed, 0x10, 0x0a, 0x25, 0x70, 0x72, 0x6f,
+ 0x74, 0x6f, 0x73, 0x2f, 0x70, 0x65, 0x72, 0x66, 0x65, 0x74, 0x74, 0x6f,
+ 0x2f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2f, 0x6d, 0x65, 0x74,
+ 0x72, 0x69, 0x63, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0f,
+ 0x70, 0x65, 0x72, 0x66, 0x65, 0x74, 0x74, 0x6f, 0x2e, 0x70, 0x72, 0x6f,
+ 0x74, 0x6f, 0x73, 0x1a, 0x31, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2f,
+ 0x70, 0x65, 0x72, 0x66, 0x65, 0x74, 0x74, 0x6f, 0x2f, 0x6d, 0x65, 0x74,
+ 0x72, 0x69, 0x63, 0x73, 0x2f, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64,
+ 0x2f, 0x62, 0x61, 0x74, 0x74, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63,
+ 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x30, 0x70, 0x72, 0x6f, 0x74,
+ 0x6f, 0x73, 0x2f, 0x70, 0x65, 0x72, 0x66, 0x65, 0x74, 0x74, 0x6f, 0x2f,
+ 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2f, 0x61, 0x6e, 0x64, 0x72,
+ 0x6f, 0x69, 0x64, 0x2f, 0x63, 0x70, 0x75, 0x5f, 0x6d, 0x65, 0x74, 0x72,
+ 0x69, 0x63, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x30, 0x70, 0x72,
0x6f, 0x74, 0x6f, 0x73, 0x2f, 0x70, 0x65, 0x72, 0x66, 0x65, 0x74, 0x74,
0x6f, 0x2f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2f, 0x61, 0x6e,
- 0x64, 0x72, 0x6f, 0x69, 0x64, 0x2f, 0x75, 0x6e, 0x73, 0x79, 0x6d, 0x62,
- 0x6f, 0x6c, 0x69, 0x7a, 0x65, 0x64, 0x5f, 0x66, 0x72, 0x61, 0x6d, 0x65,
- 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xd2, 0x01, 0x0a, 0x0d,
- 0x54, 0x72, 0x61, 0x63, 0x65, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74,
- 0x61, 0x12, 0x50, 0x0a, 0x11, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x5f, 0x73,
- 0x74, 0x61, 0x74, 0x73, 0x5f, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x18, 0x01,
- 0x20, 0x03, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x70, 0x65, 0x72, 0x66, 0x65,
- 0x74, 0x74, 0x6f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x54,
- 0x72, 0x61, 0x63, 0x65, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61,
- 0x2e, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0f, 0x65, 0x72, 0x72, 0x6f,
- 0x72, 0x53, 0x74, 0x61, 0x74, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12,
- 0x2a, 0x0a, 0x11, 0x74, 0x72, 0x61, 0x63, 0x65, 0x5f, 0x64, 0x75, 0x72,
- 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6e, 0x73, 0x18, 0x02, 0x20, 0x01,
- 0x28, 0x03, 0x52, 0x0f, 0x74, 0x72, 0x61, 0x63, 0x65, 0x44, 0x75, 0x72,
- 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4e, 0x73, 0x1a, 0x43, 0x0a, 0x05, 0x45,
- 0x6e, 0x74, 0x72, 0x79, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65,
- 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65,
- 0x12, 0x10, 0x0a, 0x03, 0x69, 0x64, 0x78, 0x18, 0x02, 0x20, 0x01, 0x28,
- 0x0d, 0x52, 0x03, 0x69, 0x64, 0x78, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61,
- 0x6c, 0x75, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x05, 0x76,
- 0x61, 0x6c, 0x75, 0x65, 0x22, 0xb8, 0x08, 0x0a, 0x0c, 0x54, 0x72, 0x61,
- 0x63, 0x65, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x12, 0x48, 0x0a,
- 0x0c, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x5f, 0x62, 0x61, 0x74,
- 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x70, 0x65,
- 0x72, 0x66, 0x65, 0x74, 0x74, 0x6f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
- 0x73, 0x2e, 0x41, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x42, 0x61, 0x74,
- 0x74, 0x65, 0x72, 0x79, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x52, 0x0b,
- 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x42, 0x61, 0x74, 0x74, 0x12,
- 0x42, 0x0a, 0x0b, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x5f, 0x63,
- 0x70, 0x75, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x70,
- 0x65, 0x72, 0x66, 0x65, 0x74, 0x74, 0x6f, 0x2e, 0x70, 0x72, 0x6f, 0x74,
- 0x6f, 0x73, 0x2e, 0x41, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x43, 0x70,
- 0x75, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x52, 0x0a, 0x61, 0x6e, 0x64,
- 0x72, 0x6f, 0x69, 0x64, 0x43, 0x70, 0x75, 0x12, 0x45, 0x0a, 0x0b, 0x61,
- 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x5f, 0x6d, 0x65, 0x6d, 0x18, 0x01,
- 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x70, 0x65, 0x72, 0x66, 0x65,
- 0x74, 0x74, 0x6f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x41,
- 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x4d, 0x65, 0x6d, 0x6f, 0x72, 0x79,
- 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x52, 0x0a, 0x61, 0x6e, 0x64, 0x72,
- 0x6f, 0x69, 0x64, 0x4d, 0x65, 0x6d, 0x12, 0x5c, 0x0a, 0x11, 0x61, 0x6e,
- 0x64, 0x72, 0x6f, 0x69, 0x64, 0x5f, 0x6d, 0x65, 0x6d, 0x5f, 0x75, 0x6e,
- 0x61, 0x67, 0x67, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x30, 0x2e,
- 0x70, 0x65, 0x72, 0x66, 0x65, 0x74, 0x74, 0x6f, 0x2e, 0x70, 0x72, 0x6f,
- 0x74, 0x6f, 0x73, 0x2e, 0x41, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x4d,
- 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x55, 0x6e, 0x61, 0x67, 0x67, 0x72, 0x65,
- 0x67, 0x61, 0x74, 0x65, 0x64, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x52,
- 0x0f, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x4d, 0x65, 0x6d, 0x55,
- 0x6e, 0x61, 0x67, 0x67, 0x12, 0x55, 0x0a, 0x14, 0x61, 0x6e, 0x64, 0x72,
- 0x6f, 0x69, 0x64, 0x5f, 0x70, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x5f,
- 0x6c, 0x69, 0x73, 0x74, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23,
- 0x2e, 0x70, 0x65, 0x72, 0x66, 0x65, 0x74, 0x74, 0x6f, 0x2e, 0x70, 0x72,
- 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x41, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64,
- 0x50, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x4c, 0x69, 0x73, 0x74, 0x52,
- 0x12, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x50, 0x61, 0x63, 0x6b,
- 0x61, 0x67, 0x65, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x5b, 0x0a, 0x16, 0x61,
- 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x5f, 0x70, 0x72, 0x6f, 0x63, 0x65,
- 0x73, 0x73, 0x5f, 0x67, 0x72, 0x6f, 0x77, 0x74, 0x68, 0x18, 0x0a, 0x20,
- 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x70, 0x65, 0x72, 0x66, 0x65, 0x74,
- 0x74, 0x6f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x41, 0x6e,
- 0x64, 0x72, 0x6f, 0x69, 0x64, 0x50, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73,
- 0x47, 0x72, 0x6f, 0x77, 0x74, 0x68, 0x52, 0x14, 0x61, 0x6e, 0x64, 0x72,
- 0x6f, 0x69, 0x64, 0x50, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x47, 0x72,
- 0x6f, 0x77, 0x74, 0x68, 0x12, 0x42, 0x0a, 0x0b, 0x61, 0x6e, 0x64, 0x72,
- 0x6f, 0x69, 0x64, 0x5f, 0x69, 0x6f, 0x6e, 0x18, 0x09, 0x20, 0x01, 0x28,
+ 0x64, 0x72, 0x6f, 0x69, 0x64, 0x2f, 0x6d, 0x65, 0x6d, 0x5f, 0x6d, 0x65,
+ 0x74, 0x72, 0x69, 0x63, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x36,
+ 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2f, 0x70, 0x65, 0x72, 0x66, 0x65,
+ 0x74, 0x74, 0x6f, 0x2f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2f,
+ 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x2f, 0x6d, 0x65, 0x6d, 0x5f,
+ 0x75, 0x6e, 0x61, 0x67, 0x67, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63,
+ 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x34, 0x70, 0x72, 0x6f, 0x74,
+ 0x6f, 0x73, 0x2f, 0x70, 0x65, 0x72, 0x66, 0x65, 0x74, 0x74, 0x6f, 0x2f,
+ 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2f, 0x61, 0x6e, 0x64, 0x72,
+ 0x6f, 0x69, 0x64, 0x2f, 0x70, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x5f,
+ 0x67, 0x72, 0x6f, 0x77, 0x74, 0x68, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
+ 0x1a, 0x30, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2f, 0x70, 0x65, 0x72,
+ 0x66, 0x65, 0x74, 0x74, 0x6f, 0x2f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63,
+ 0x73, 0x2f, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x2f, 0x69, 0x6f,
+ 0x6e, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x2e, 0x70, 0x72, 0x6f,
+ 0x74, 0x6f, 0x1a, 0x30, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2f, 0x70,
+ 0x65, 0x72, 0x66, 0x65, 0x74, 0x74, 0x6f, 0x2f, 0x6d, 0x65, 0x74, 0x72,
+ 0x69, 0x63, 0x73, 0x2f, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x2f,
+ 0x6c, 0x6d, 0x6b, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x2e, 0x70,
+ 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x35, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73,
+ 0x2f, 0x70, 0x65, 0x72, 0x66, 0x65, 0x74, 0x74, 0x6f, 0x2f, 0x6d, 0x65,
+ 0x74, 0x72, 0x69, 0x63, 0x73, 0x2f, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69,
+ 0x64, 0x2f, 0x70, 0x6f, 0x77, 0x72, 0x61, 0x69, 0x6c, 0x73, 0x5f, 0x6d,
+ 0x65, 0x74, 0x72, 0x69, 0x63, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a,
+ 0x34, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2f, 0x70, 0x65, 0x72, 0x66,
+ 0x65, 0x74, 0x74, 0x6f, 0x2f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73,
+ 0x2f, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x2f, 0x73, 0x74, 0x61,
+ 0x72, 0x74, 0x75, 0x70, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x2e,
+ 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x3c, 0x70, 0x72, 0x6f, 0x74, 0x6f,
+ 0x73, 0x2f, 0x70, 0x65, 0x72, 0x66, 0x65, 0x74, 0x74, 0x6f, 0x2f, 0x6d,
+ 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2f, 0x61, 0x6e, 0x64, 0x72, 0x6f,
+ 0x69, 0x64, 0x2f, 0x68, 0x65, 0x61, 0x70, 0x5f, 0x70, 0x72, 0x6f, 0x66,
+ 0x69, 0x6c, 0x65, 0x5f, 0x63, 0x61, 0x6c, 0x6c, 0x73, 0x69, 0x74, 0x65,
+ 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x32, 0x70, 0x72, 0x6f,
+ 0x74, 0x6f, 0x73, 0x2f, 0x70, 0x65, 0x72, 0x66, 0x65, 0x74, 0x74, 0x6f,
+ 0x2f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2f, 0x61, 0x6e, 0x64,
+ 0x72, 0x6f, 0x69, 0x64, 0x2f, 0x70, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65,
+ 0x5f, 0x6c, 0x69, 0x73, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a,
+ 0x39, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2f, 0x70, 0x65, 0x72, 0x66,
+ 0x65, 0x74, 0x74, 0x6f, 0x2f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73,
+ 0x2f, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x2f, 0x75, 0x6e, 0x73,
+ 0x79, 0x6d, 0x62, 0x6f, 0x6c, 0x69, 0x7a, 0x65, 0x64, 0x5f, 0x66, 0x72,
+ 0x61, 0x6d, 0x65, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x35,
+ 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2f, 0x70, 0x65, 0x72, 0x66, 0x65,
+ 0x74, 0x74, 0x6f, 0x2f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2f,
+ 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x2f, 0x6a, 0x61, 0x76, 0x61,
+ 0x5f, 0x68, 0x65, 0x61, 0x70, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x73, 0x2e,
+ 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xf1, 0x01, 0x0a, 0x0d, 0x54, 0x72,
+ 0x61, 0x63, 0x65, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12,
+ 0x50, 0x0a, 0x11, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x5f, 0x73, 0x74, 0x61,
+ 0x74, 0x73, 0x5f, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x18, 0x01, 0x20, 0x03,
+ 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x70, 0x65, 0x72, 0x66, 0x65, 0x74, 0x74,
+ 0x6f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x54, 0x72, 0x61,
+ 0x63, 0x65, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x45,
+ 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0f, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x53,
+ 0x74, 0x61, 0x74, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x2a, 0x0a,
+ 0x11, 0x74, 0x72, 0x61, 0x63, 0x65, 0x5f, 0x64, 0x75, 0x72, 0x61, 0x74,
+ 0x69, 0x6f, 0x6e, 0x5f, 0x6e, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03,
+ 0x52, 0x0f, 0x74, 0x72, 0x61, 0x63, 0x65, 0x44, 0x75, 0x72, 0x61, 0x74,
+ 0x69, 0x6f, 0x6e, 0x4e, 0x73, 0x12, 0x1d, 0x0a, 0x0a, 0x74, 0x72, 0x61,
+ 0x63, 0x65, 0x5f, 0x75, 0x75, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28,
+ 0x09, 0x52, 0x09, 0x74, 0x72, 0x61, 0x63, 0x65, 0x55, 0x75, 0x69, 0x64,
+ 0x1a, 0x43, 0x0a, 0x05, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x12, 0x0a,
+ 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52,
+ 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x69, 0x64, 0x78,
+ 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x03, 0x69, 0x64, 0x78, 0x12,
+ 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x03, 0x20, 0x01,
+ 0x28, 0x03, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x80, 0x09,
+ 0x0a, 0x0c, 0x54, 0x72, 0x61, 0x63, 0x65, 0x4d, 0x65, 0x74, 0x72, 0x69,
+ 0x63, 0x73, 0x12, 0x48, 0x0a, 0x0c, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69,
+ 0x64, 0x5f, 0x62, 0x61, 0x74, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b,
+ 0x32, 0x25, 0x2e, 0x70, 0x65, 0x72, 0x66, 0x65, 0x74, 0x74, 0x6f, 0x2e,
+ 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x41, 0x6e, 0x64, 0x72, 0x6f,
+ 0x69, 0x64, 0x42, 0x61, 0x74, 0x74, 0x65, 0x72, 0x79, 0x4d, 0x65, 0x74,
+ 0x72, 0x69, 0x63, 0x52, 0x0b, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64,
+ 0x42, 0x61, 0x74, 0x74, 0x12, 0x42, 0x0a, 0x0b, 0x61, 0x6e, 0x64, 0x72,
+ 0x6f, 0x69, 0x64, 0x5f, 0x63, 0x70, 0x75, 0x18, 0x06, 0x20, 0x01, 0x28,
0x0b, 0x32, 0x21, 0x2e, 0x70, 0x65, 0x72, 0x66, 0x65, 0x74, 0x74, 0x6f,
0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x41, 0x6e, 0x64, 0x72,
- 0x6f, 0x69, 0x64, 0x49, 0x6f, 0x6e, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63,
- 0x52, 0x0a, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x49, 0x6f, 0x6e,
- 0x12, 0x42, 0x0a, 0x0b, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x5f,
- 0x6c, 0x6d, 0x6b, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e,
+ 0x6f, 0x69, 0x64, 0x43, 0x70, 0x75, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63,
+ 0x52, 0x0a, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x43, 0x70, 0x75,
+ 0x12, 0x45, 0x0a, 0x0b, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x5f,
+ 0x6d, 0x65, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e,
0x70, 0x65, 0x72, 0x66, 0x65, 0x74, 0x74, 0x6f, 0x2e, 0x70, 0x72, 0x6f,
- 0x74, 0x6f, 0x73, 0x2e, 0x41, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x4c,
- 0x6d, 0x6b, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x52, 0x0a, 0x61, 0x6e,
- 0x64, 0x72, 0x6f, 0x69, 0x64, 0x4c, 0x6d, 0x6b, 0x12, 0x4d, 0x0a, 0x10,
- 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x5f, 0x70, 0x6f, 0x77, 0x72,
- 0x61, 0x69, 0x6c, 0x73, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22,
- 0x2e, 0x70, 0x65, 0x72, 0x66, 0x65, 0x74, 0x74, 0x6f, 0x2e, 0x70, 0x72,
- 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x41, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64,
- 0x50, 0x6f, 0x77, 0x65, 0x72, 0x52, 0x61, 0x69, 0x6c, 0x73, 0x52, 0x0f,
- 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x50, 0x6f, 0x77, 0x72, 0x61,
- 0x69, 0x6c, 0x73, 0x12, 0x4e, 0x0a, 0x0f, 0x61, 0x6e, 0x64, 0x72, 0x6f,
- 0x69, 0x64, 0x5f, 0x73, 0x74, 0x61, 0x72, 0x74, 0x75, 0x70, 0x18, 0x02,
- 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x70, 0x65, 0x72, 0x66, 0x65,
- 0x74, 0x74, 0x6f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x41,
- 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x53, 0x74, 0x61, 0x72, 0x74, 0x75,
- 0x70, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x52, 0x0e, 0x61, 0x6e, 0x64,
- 0x72, 0x6f, 0x69, 0x64, 0x53, 0x74, 0x61, 0x72, 0x74, 0x75, 0x70, 0x12,
- 0x5b, 0x0a, 0x16, 0x68, 0x65, 0x61, 0x70, 0x5f, 0x70, 0x72, 0x6f, 0x66,
- 0x69, 0x6c, 0x65, 0x5f, 0x63, 0x61, 0x6c, 0x6c, 0x73, 0x69, 0x74, 0x65,
- 0x73, 0x18, 0x10, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x70, 0x65,
- 0x72, 0x66, 0x65, 0x74, 0x74, 0x6f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
- 0x73, 0x2e, 0x48, 0x65, 0x61, 0x70, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c,
- 0x65, 0x43, 0x61, 0x6c, 0x6c, 0x73, 0x69, 0x74, 0x65, 0x73, 0x52, 0x14,
- 0x68, 0x65, 0x61, 0x70, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x43,
- 0x61, 0x6c, 0x6c, 0x73, 0x69, 0x74, 0x65, 0x73, 0x12, 0x45, 0x0a, 0x0e,
- 0x74, 0x72, 0x61, 0x63, 0x65, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61,
- 0x74, 0x61, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x70,
+ 0x74, 0x6f, 0x73, 0x2e, 0x41, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x4d,
+ 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x52,
+ 0x0a, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x4d, 0x65, 0x6d, 0x12,
+ 0x5c, 0x0a, 0x11, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x5f, 0x6d,
+ 0x65, 0x6d, 0x5f, 0x75, 0x6e, 0x61, 0x67, 0x67, 0x18, 0x0b, 0x20, 0x01,
+ 0x28, 0x0b, 0x32, 0x30, 0x2e, 0x70, 0x65, 0x72, 0x66, 0x65, 0x74, 0x74,
+ 0x6f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x41, 0x6e, 0x64,
+ 0x72, 0x6f, 0x69, 0x64, 0x4d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x55, 0x6e,
+ 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x64, 0x4d, 0x65,
+ 0x74, 0x72, 0x69, 0x63, 0x52, 0x0f, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69,
+ 0x64, 0x4d, 0x65, 0x6d, 0x55, 0x6e, 0x61, 0x67, 0x67, 0x12, 0x55, 0x0a,
+ 0x14, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x5f, 0x70, 0x61, 0x63,
+ 0x6b, 0x61, 0x67, 0x65, 0x5f, 0x6c, 0x69, 0x73, 0x74, 0x18, 0x0c, 0x20,
+ 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x70, 0x65, 0x72, 0x66, 0x65, 0x74,
+ 0x74, 0x6f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x41, 0x6e,
+ 0x64, 0x72, 0x6f, 0x69, 0x64, 0x50, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65,
+ 0x4c, 0x69, 0x73, 0x74, 0x52, 0x12, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69,
+ 0x64, 0x50, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x4c, 0x69, 0x73, 0x74,
+ 0x12, 0x5b, 0x0a, 0x16, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x5f,
+ 0x70, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x5f, 0x67, 0x72, 0x6f, 0x77,
+ 0x74, 0x68, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x70,
0x65, 0x72, 0x66, 0x65, 0x74, 0x74, 0x6f, 0x2e, 0x70, 0x72, 0x6f, 0x74,
- 0x6f, 0x73, 0x2e, 0x54, 0x72, 0x61, 0x63, 0x65, 0x4d, 0x65, 0x74, 0x61,
- 0x64, 0x61, 0x74, 0x61, 0x52, 0x0d, 0x74, 0x72, 0x61, 0x63, 0x65, 0x4d,
- 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x54, 0x0a, 0x13, 0x75,
- 0x6e, 0x73, 0x79, 0x6d, 0x62, 0x6f, 0x6c, 0x69, 0x7a, 0x65, 0x64, 0x5f,
- 0x66, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x0b,
- 0x32, 0x23, 0x2e, 0x70, 0x65, 0x72, 0x66, 0x65, 0x74, 0x74, 0x6f, 0x2e,
- 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x55, 0x6e, 0x73, 0x79, 0x6d,
- 0x62, 0x6f, 0x6c, 0x69, 0x7a, 0x65, 0x64, 0x46, 0x72, 0x61, 0x6d, 0x65,
- 0x73, 0x52, 0x12, 0x75, 0x6e, 0x73, 0x79, 0x6d, 0x62, 0x6f, 0x6c, 0x69,
- 0x7a, 0x65, 0x64, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x2a, 0x06, 0x08,
- 0xc2, 0x03, 0x10, 0xf4, 0x03, 0x2a, 0x06, 0x08, 0xf4, 0x03, 0x10, 0xe9,
- 0x07, 0x4a, 0x04, 0x08, 0x04, 0x10, 0x05, 0x4a, 0x04, 0x08, 0x0d, 0x10,
- 0x0e, 0x4a, 0x04, 0x08, 0x0e, 0x10, 0x0f, 0x42, 0x02, 0x48, 0x03}};
+ 0x6f, 0x73, 0x2e, 0x41, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x50, 0x72,
+ 0x6f, 0x63, 0x65, 0x73, 0x73, 0x47, 0x72, 0x6f, 0x77, 0x74, 0x68, 0x52,
+ 0x14, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x50, 0x72, 0x6f, 0x63,
+ 0x65, 0x73, 0x73, 0x47, 0x72, 0x6f, 0x77, 0x74, 0x68, 0x12, 0x42, 0x0a,
+ 0x0b, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x5f, 0x69, 0x6f, 0x6e,
+ 0x18, 0x09, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x70, 0x65, 0x72,
+ 0x66, 0x65, 0x74, 0x74, 0x6f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73,
+ 0x2e, 0x41, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x49, 0x6f, 0x6e, 0x4d,
+ 0x65, 0x74, 0x72, 0x69, 0x63, 0x52, 0x0a, 0x61, 0x6e, 0x64, 0x72, 0x6f,
+ 0x69, 0x64, 0x49, 0x6f, 0x6e, 0x12, 0x42, 0x0a, 0x0b, 0x61, 0x6e, 0x64,
+ 0x72, 0x6f, 0x69, 0x64, 0x5f, 0x6c, 0x6d, 0x6b, 0x18, 0x08, 0x20, 0x01,
+ 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x70, 0x65, 0x72, 0x66, 0x65, 0x74, 0x74,
+ 0x6f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x41, 0x6e, 0x64,
+ 0x72, 0x6f, 0x69, 0x64, 0x4c, 0x6d, 0x6b, 0x4d, 0x65, 0x74, 0x72, 0x69,
+ 0x63, 0x52, 0x0a, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x4c, 0x6d,
+ 0x6b, 0x12, 0x4d, 0x0a, 0x10, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64,
+ 0x5f, 0x70, 0x6f, 0x77, 0x72, 0x61, 0x69, 0x6c, 0x73, 0x18, 0x07, 0x20,
+ 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x70, 0x65, 0x72, 0x66, 0x65, 0x74,
+ 0x74, 0x6f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x41, 0x6e,
+ 0x64, 0x72, 0x6f, 0x69, 0x64, 0x50, 0x6f, 0x77, 0x65, 0x72, 0x52, 0x61,
+ 0x69, 0x6c, 0x73, 0x52, 0x0f, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64,
+ 0x50, 0x6f, 0x77, 0x72, 0x61, 0x69, 0x6c, 0x73, 0x12, 0x4e, 0x0a, 0x0f,
+ 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x5f, 0x73, 0x74, 0x61, 0x72,
+ 0x74, 0x75, 0x70, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e,
+ 0x70, 0x65, 0x72, 0x66, 0x65, 0x74, 0x74, 0x6f, 0x2e, 0x70, 0x72, 0x6f,
+ 0x74, 0x6f, 0x73, 0x2e, 0x41, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x53,
+ 0x74, 0x61, 0x72, 0x74, 0x75, 0x70, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63,
+ 0x52, 0x0e, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x53, 0x74, 0x61,
+ 0x72, 0x74, 0x75, 0x70, 0x12, 0x5b, 0x0a, 0x16, 0x68, 0x65, 0x61, 0x70,
+ 0x5f, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x5f, 0x63, 0x61, 0x6c,
+ 0x6c, 0x73, 0x69, 0x74, 0x65, 0x73, 0x18, 0x10, 0x20, 0x01, 0x28, 0x0b,
+ 0x32, 0x25, 0x2e, 0x70, 0x65, 0x72, 0x66, 0x65, 0x74, 0x74, 0x6f, 0x2e,
+ 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x48, 0x65, 0x61, 0x70, 0x50,
+ 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x43, 0x61, 0x6c, 0x6c, 0x73, 0x69,
+ 0x74, 0x65, 0x73, 0x52, 0x14, 0x68, 0x65, 0x61, 0x70, 0x50, 0x72, 0x6f,
+ 0x66, 0x69, 0x6c, 0x65, 0x43, 0x61, 0x6c, 0x6c, 0x73, 0x69, 0x74, 0x65,
+ 0x73, 0x12, 0x45, 0x0a, 0x0e, 0x74, 0x72, 0x61, 0x63, 0x65, 0x5f, 0x6d,
+ 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x03, 0x20, 0x01, 0x28,
+ 0x0b, 0x32, 0x1e, 0x2e, 0x70, 0x65, 0x72, 0x66, 0x65, 0x74, 0x74, 0x6f,
+ 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x54, 0x72, 0x61, 0x63,
+ 0x65, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x52, 0x0d, 0x74,
+ 0x72, 0x61, 0x63, 0x65, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61,
+ 0x12, 0x54, 0x0a, 0x13, 0x75, 0x6e, 0x73, 0x79, 0x6d, 0x62, 0x6f, 0x6c,
+ 0x69, 0x7a, 0x65, 0x64, 0x5f, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x18,
+ 0x0f, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x70, 0x65, 0x72, 0x66,
+ 0x65, 0x74, 0x74, 0x6f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e,
+ 0x55, 0x6e, 0x73, 0x79, 0x6d, 0x62, 0x6f, 0x6c, 0x69, 0x7a, 0x65, 0x64,
+ 0x46, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x52, 0x12, 0x75, 0x6e, 0x73, 0x79,
+ 0x6d, 0x62, 0x6f, 0x6c, 0x69, 0x7a, 0x65, 0x64, 0x46, 0x72, 0x61, 0x6d,
+ 0x65, 0x73, 0x12, 0x46, 0x0a, 0x0f, 0x6a, 0x61, 0x76, 0x61, 0x5f, 0x68,
+ 0x65, 0x61, 0x70, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x73, 0x18, 0x11, 0x20,
+ 0x01, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x70, 0x65, 0x72, 0x66, 0x65, 0x74,
+ 0x74, 0x6f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x4a, 0x61,
+ 0x76, 0x61, 0x48, 0x65, 0x61, 0x70, 0x53, 0x74, 0x61, 0x74, 0x73, 0x52,
+ 0x0d, 0x6a, 0x61, 0x76, 0x61, 0x48, 0x65, 0x61, 0x70, 0x53, 0x74, 0x61,
+ 0x74, 0x73, 0x2a, 0x06, 0x08, 0xc2, 0x03, 0x10, 0xf4, 0x03, 0x2a, 0x06,
+ 0x08, 0xf4, 0x03, 0x10, 0xe9, 0x07, 0x4a, 0x04, 0x08, 0x04, 0x10, 0x05,
+ 0x4a, 0x04, 0x08, 0x0d, 0x10, 0x0e, 0x4a, 0x04, 0x08, 0x0e, 0x10, 0x0f,
+ 0x42, 0x02, 0x48, 0x03}};
} // namespace perfetto
diff --git a/src/trace_processor/metrics/trace_metadata.sql b/src/trace_processor/metrics/trace_metadata.sql
index 2bee6b3..11524ac 100644
--- a/src/trace_processor/metrics/trace_metadata.sql
+++ b/src/trace_processor/metrics/trace_metadata.sql
@@ -26,5 +26,6 @@
CREATE VIEW trace_metadata_output AS
SELECT TraceMetadata(
'error_stats_entry', (SELECT RepeatedField(entry) FROM error_stats_view),
- 'trace_duration_ns', (SELECT end_ts - start_ts FROM trace_bounds)
+ 'trace_duration_ns', (SELECT end_ts - start_ts FROM trace_bounds),
+ 'trace_uuid', (SELECT str_value FROM metadata WHERE name = 'trace_uuid')
);
diff --git a/src/trace_processor/process_table.cc b/src/trace_processor/process_table.cc
index 9d0129a..c85177a 100644
--- a/src/trace_processor/process_table.cc
+++ b/src/trace_processor/process_table.cc
@@ -74,57 +74,56 @@
int ProcessTable::Cursor::Filter(const QueryConstraints& qc,
sqlite3_value** argv) {
- min = 0;
- max = static_cast<uint32_t>(storage_->process_count()) - 1;
- desc = false;
+ min_ = 0;
+ max_ = static_cast<uint32_t>(storage_->process_count());
+ desc_ = false;
for (size_t j = 0; j < qc.constraints().size(); j++) {
const auto& cs = qc.constraints()[j];
if (cs.iColumn == Column::kUpid) {
auto constraint_upid = static_cast<UniquePid>(sqlite3_value_int(argv[j]));
// Set the range of upids that we are interested in, based on the
- // constraints in the query. Everything between min and max (inclusive)
+ // constraints in the query. Everything between min and max (exclusive)
// will be returned.
if (IsOpEq(cs.op)) {
- min = constraint_upid;
- max = constraint_upid;
+ min_ = constraint_upid;
+ max_ = constraint_upid + 1;
} else if (IsOpGe(cs.op) || IsOpGt(cs.op)) {
- min = IsOpGt(cs.op) ? constraint_upid + 1 : constraint_upid;
+ min_ = IsOpGt(cs.op) ? constraint_upid + 1 : constraint_upid;
} else if (IsOpLe(cs.op) || IsOpLt(cs.op)) {
- max = IsOpLt(cs.op) ? constraint_upid - 1 : constraint_upid;
+ max_ = IsOpLt(cs.op) ? constraint_upid : constraint_upid + 1;
}
}
}
for (const auto& ob : qc.order_by()) {
if (ob.iColumn == Column::kUpid) {
- desc = ob.desc;
+ desc_ = ob.desc;
}
}
- current = desc ? max : min;
+ index_ = 0;
return SQLITE_OK;
}
int ProcessTable::Cursor::Column(sqlite3_context* context, int N) {
+ uint32_t current = desc_ ? max_ - index_ - 1 : min_ + index_;
+ const auto& process = storage_->GetProcess(current);
switch (N) {
case Column::kUpid: {
sqlite3_result_int64(context, current);
break;
}
case Column::kName: {
- const auto& process = storage_->GetProcess(current);
const auto& name = storage_->GetString(process.name_id);
sqlite3_result_text(context, name.c_str(), -1, kSqliteStatic);
break;
}
case Column::kPid: {
- const auto& process = storage_->GetProcess(current);
sqlite3_result_int64(context, process.pid);
break;
}
case Column::kStartTs: {
- const auto& process = storage_->GetProcess(current);
if (process.start_ns != 0) {
sqlite3_result_int64(context, process.start_ns);
} else {
@@ -133,7 +132,6 @@
break;
}
case Column::kEndTs: {
- const auto& process = storage_->GetProcess(current);
if (process.end_ns != 0) {
sqlite3_result_int64(context, process.end_ns);
} else {
@@ -142,7 +140,6 @@
break;
}
case Column::kParentUpid: {
- const auto& process = storage_->GetProcess(current);
if (process.parent_upid.has_value()) {
sqlite3_result_int64(context, process.parent_upid.value());
} else {
@@ -158,16 +155,12 @@
}
int ProcessTable::Cursor::Next() {
- if (desc) {
- --current;
- } else {
- ++current;
- }
+ ++index_;
return SQLITE_OK;
}
int ProcessTable::Cursor::Eof() {
- return desc ? current < min : current > max;
+ return index_ >= (max_ - min_);
}
} // namespace trace_processor
diff --git a/src/trace_processor/process_table.h b/src/trace_processor/process_table.h
index 4c8b208..c4c1ed5 100644
--- a/src/trace_processor/process_table.h
+++ b/src/trace_processor/process_table.h
@@ -50,10 +50,10 @@
private:
const TraceStorage* const storage_;
- UniquePid min;
- UniquePid max;
- UniquePid current;
- bool desc;
+ UniquePid min_ = 0;
+ UniquePid max_ = 0;
+ uint32_t index_ = 0;
+ bool desc_ = false;
};
static void RegisterTable(sqlite3* db, const TraceStorage* storage);
diff --git a/src/trace_processor/raw_table.cc b/src/trace_processor/raw_table.cc
index bf4f111..29d86ef 100644
--- a/src/trace_processor/raw_table.cc
+++ b/src/trace_processor/raw_table.cc
@@ -70,12 +70,13 @@
int RawTable::BestIndex(const QueryConstraints& qc, BestIndexInfo* info) {
info->estimated_cost = RowCount();
+ info->sqlite_omit_order_by = true;
// Only the string columns are handled by SQLite
- info->order_by_consumed = true;
size_t name_index = schema().ColumnIndexFromName("name");
for (size_t i = 0; i < qc.constraints().size(); i++) {
- info->omit[i] = qc.constraints()[i].iColumn != static_cast<int>(name_index);
+ info->constraint_info[i].sqlite_omit =
+ qc.constraints()[i].iColumn != static_cast<int>(name_index);
}
return SQLITE_OK;
diff --git a/src/trace_processor/sched_slice_table.cc b/src/trace_processor/sched_slice_table.cc
index 05657c4..0385fab 100644
--- a/src/trace_processor/sched_slice_table.cc
+++ b/src/trace_processor/sched_slice_table.cc
@@ -51,8 +51,9 @@
// We should be able to handle any constraint and any order by clause given
// to us.
- info->order_by_consumed = true;
- std::fill(info->omit.begin(), info->omit.end(), true);
+ info->sqlite_omit_order_by = true;
+ for (auto& c_info : info->constraint_info)
+ c_info.sqlite_omit = true;
return SQLITE_OK;
}
diff --git a/src/trace_processor/slice_table.cc b/src/trace_processor/slice_table.cc
index d2dca83..5eef8c0 100644
--- a/src/trace_processor/slice_table.cc
+++ b/src/trace_processor/slice_table.cc
@@ -53,15 +53,15 @@
int SliceTable::BestIndex(const QueryConstraints& qc, BestIndexInfo* info) {
info->estimated_cost = EstimateCost(qc);
+ info->sqlite_omit_order_by = true;
// Only the string columns are handled by SQLite
- info->order_by_consumed = true;
size_t name_index = schema().ColumnIndexFromName("name");
size_t cat_index = schema().ColumnIndexFromName("category");
size_t ref_type_index = schema().ColumnIndexFromName("ref_type");
for (size_t i = 0; i < qc.constraints().size(); i++) {
auto col = static_cast<size_t>(qc.constraints()[i].iColumn);
- info->omit[i] =
+ info->constraint_info[i].sqlite_omit =
col != name_index && col != cat_index && col != ref_type_index;
}
return SQLITE_OK;
diff --git a/src/trace_processor/sql_stats_table.cc b/src/trace_processor/sql_stats_table.cc
index 3356f8e..0d434a0 100644
--- a/src/trace_processor/sql_stats_table.cc
+++ b/src/trace_processor/sql_stats_table.cc
@@ -57,7 +57,7 @@
}
int SqlStatsTable::BestIndex(const QueryConstraints&, BestIndexInfo* info) {
- info->order_by_consumed = false; // Delegate sorting to SQLite.
+ info->sqlite_omit_order_by = true;
return SQLITE_OK;
}
diff --git a/src/trace_processor/sqlite/sqlite_table.cc b/src/trace_processor/sqlite/sqlite_table.cc
index 211ff7e..9a41763 100644
--- a/src/trace_processor/sqlite/sqlite_table.cc
+++ b/src/trace_processor/sqlite/sqlite_table.cc
@@ -58,54 +58,84 @@
}
int SqliteTable::BestIndexInternal(sqlite3_index_info* idx) {
- QueryConstraints query_constraints;
+ using ConstraintInfo = BestIndexInfo::ConstraintInfo;
- for (int i = 0; i < idx->nOrderBy; i++) {
- int column = idx->aOrderBy[i].iColumn;
- bool desc = idx->aOrderBy[i].desc;
- query_constraints.AddOrderBy(column, desc);
- }
-
+ QueryConstraints in_qc;
+ BestIndexInfo info;
for (int i = 0; i < idx->nConstraint; i++) {
const auto& cs = idx->aConstraint[i];
if (!cs.usable)
continue;
- query_constraints.AddConstraint(cs.iColumn, cs.op);
+ in_qc.AddConstraint(cs.iColumn, cs.op);
- // argvIndex is 1-based so use the current size of the vector.
- int argv_index = static_cast<int>(query_constraints.constraints().size());
- idx->aConstraintUsage[i].argvIndex = argv_index;
+ ConstraintInfo c_info;
+ c_info.qc_idx = static_cast<uint32_t>(in_qc.constraints().size() - 1);
+ info.constraint_info.emplace_back(c_info);
}
- BestIndexInfo info;
- info.omit.resize(query_constraints.constraints().size());
-
- int ret = BestIndex(query_constraints, &info);
-
- if (SqliteTable::debug) {
- PERFETTO_LOG(
- "[%s::BestIndex] constraints=%s orderByConsumed=%d estimatedCost=%d",
- name_.c_str(), query_constraints.ToNewSqlite3String().get(),
- info.order_by_consumed, info.estimated_cost);
+ for (int i = 0; i < idx->nOrderBy; i++) {
+ int column = idx->aOrderBy[i].iColumn;
+ bool desc = idx->aOrderBy[i].desc;
+ in_qc.AddOrderBy(column, desc);
}
+ int ret = BestIndex(in_qc, &info);
if (ret != SQLITE_OK)
return ret;
- idx->orderByConsumed = info.order_by_consumed;
- idx->estimatedCost = info.estimated_cost;
+ auto& cs_info = info.constraint_info;
- size_t j = 0;
- for (int i = 0; i < idx->nConstraint; i++) {
- const auto& cs = idx->aConstraint[i];
- if (cs.usable)
- idx->aConstraintUsage[i].omit = info.omit[j++];
+ // Remove all the pruned terms from the constraints.
+ {
+ auto prune_fn = [](const ConstraintInfo& t) { return t.prune; };
+ auto prune_cs_it = std::remove_if(cs_info.begin(), cs_info.end(), prune_fn);
+ cs_info.erase(prune_cs_it, cs_info.end());
}
- if (!info.order_by_consumed)
- query_constraints.ClearOrderBy();
+ idx->orderByConsumed = info.prune_order_by || info.sqlite_omit_order_by;
+ idx->estimatedCost = info.estimated_cost;
- idx->idxStr = query_constraints.ToNewSqlite3String().release();
+ uint32_t in_qc_idx = 0;
+ for (int i = 0; i < idx->nConstraint; i++) {
+ const auto& c = idx->aConstraint[i];
+ if (c.usable) {
+ auto cs_fn = [in_qc_idx](const ConstraintInfo& t) {
+ return t.qc_idx == in_qc_idx;
+ };
+ auto it = std::find_if(cs_info.begin(), cs_info.end(), cs_fn);
+
+ // If the iterator no longer exists, we must have pruned it.
+ if (it == cs_info.end()) {
+ idx->aConstraintUsage[i].omit = true;
+ } else {
+ idx->aConstraintUsage[i].argvIndex =
+ static_cast<int>(std::distance(cs_info.begin(), it)) + 1;
+ idx->aConstraintUsage[i].omit = it->sqlite_omit;
+ }
+ in_qc_idx++;
+ }
+ }
+
+ QueryConstraints out_qc;
+ for (const auto& c_info : cs_info) {
+ const auto& c = in_qc.constraints()[c_info.qc_idx];
+ out_qc.AddConstraint(c.iColumn, c.op);
+ }
+ if (!info.prune_order_by) {
+ for (const auto& o : in_qc.order_by()) {
+ out_qc.AddOrderBy(o.iColumn, o.desc);
+ }
+ }
+
+ auto out_qc_str = out_qc.ToNewSqlite3String();
+ if (SqliteTable::debug) {
+ PERFETTO_LOG(
+ "[%s::BestIndex] constraints=%s orderByConsumed=%d estimatedCost=%d",
+ name_.c_str(), out_qc_str.get(), idx->orderByConsumed,
+ info.estimated_cost);
+ }
+
+ idx->idxStr = out_qc_str.release();
idx->needToFreeIdxStr = true;
idx->idxNum = ++best_index_num_;
diff --git a/src/trace_processor/sqlite/sqlite_table.h b/src/trace_processor/sqlite/sqlite_table.h
index 51557bf..3b9f83c 100644
--- a/src/trace_processor/sqlite/sqlite_table.h
+++ b/src/trace_processor/sqlite/sqlite_table.h
@@ -136,9 +136,41 @@
// Populated by a BestIndex call to allow subclasses to tweak SQLite's
// handling of sets of constraints.
struct BestIndexInfo {
- bool order_by_consumed = false;
+ // Contains info about a single constraint.
+ struct ConstraintInfo {
+ // Gives the index of this constraint in the QueryConstraints class.
+ uint32_t qc_idx = 0;
+
+ // Indicates whether this constraint should be removed from the
+ // QueryConstraint class when passed to SqliteTable::Filter.
+ bool prune = false;
+
+ // Indiciates whether SQLite should omit double checking this constraint.
+ //
+ // If |prune| is set to true, this value will be ignored and SQLite will
+ // be told that it can omit double checking (i.e. this value will
+ // implicitly be taken to be true).
+ bool sqlite_omit = false;
+ };
+
+ // Stores the estimated cost of this query.
uint32_t estimated_cost = 0;
- std::vector<bool> omit;
+
+ // Stores the information about each constraint.
+ std::vector<ConstraintInfo> constraint_info;
+
+ // Indicates that all the order by constraints should be pruned. This should
+ // be set to true if the table is exactly ordered by the order by terms in
+ // QueryConstraints.
+ bool prune_order_by = false;
+
+ // Indicates that SQLite should not double check the result of the order by
+ // clause.
+ //
+ // If |prune_order_by| is set to true, this value will be ignored and SQLite
+ // will be told that it can omit double checking (i.e. this value will
+ // implicitly be taken to be true).
+ bool sqlite_omit_order_by = false;
};
template <typename Context>
diff --git a/src/trace_processor/stack_profile_frame_table.cc b/src/trace_processor/stack_profile_frame_table.cc
index eb750e3..6939873 100644
--- a/src/trace_processor/stack_profile_frame_table.cc
+++ b/src/trace_processor/stack_profile_frame_table.cc
@@ -46,7 +46,7 @@
int StackProfileFrameTable::BestIndex(const QueryConstraints& qc,
BestIndexInfo* info) {
- info->order_by_consumed = true;
+ info->sqlite_omit_order_by = true;
info->estimated_cost = HasEqConstraint(qc, "id") ? 1 : RowCount();
return SQLITE_OK;
}
diff --git a/src/trace_processor/stack_profile_mapping_table.cc b/src/trace_processor/stack_profile_mapping_table.cc
index a7644db..52a9038 100644
--- a/src/trace_processor/stack_profile_mapping_table.cc
+++ b/src/trace_processor/stack_profile_mapping_table.cc
@@ -50,7 +50,7 @@
int StackProfileMappingTable::BestIndex(const QueryConstraints& qc,
BestIndexInfo* info) {
- info->order_by_consumed = true;
+ info->sqlite_omit_order_by = true;
info->estimated_cost = HasEqConstraint(qc, "id") ? 1 : RowCount();
return SQLITE_OK;
}
diff --git a/src/trace_processor/tables/track_tables.h b/src/trace_processor/tables/track_tables.h
index 76a4417..403b520 100644
--- a/src/trace_processor/tables/track_tables.h
+++ b/src/trace_processor/tables/track_tables.h
@@ -54,6 +54,58 @@
PERFETTO_TP_TABLE(PERFETTO_TP_GPU_TRACK_DEF);
+#define PERFETTO_TP_COUNTER_TRACK_DEF(NAME, PARENT, C) \
+ NAME(CounterTrackTable, "counter_track") \
+ PARENT(PERFETTO_TP_TRACK_TABLE_DEF, C) \
+ C(int64_t, ref) \
+ C(StringPool::Id, ref_type) \
+ C(StringPool::Id, unit) \
+ C(StringPool::Id, description)
+
+PERFETTO_TP_TABLE(PERFETTO_TP_COUNTER_TRACK_DEF);
+
+#define PERFETTO_TP_THREAD_COUNTER_TRACK_DEF(NAME, PARENT, C) \
+ NAME(ThreadCounterTrackTable, "thread_counter_track") \
+ PARENT(PERFETTO_TP_COUNTER_TRACK_DEF, C) \
+ C(uint32_t, utid)
+
+PERFETTO_TP_TABLE(PERFETTO_TP_THREAD_COUNTER_TRACK_DEF);
+
+#define PERFETTO_TP_PROCESS_COUNTER_TRACK_DEF(NAME, PARENT, C) \
+ NAME(ProcessCounterTrackTable, "process_counter_track") \
+ PARENT(PERFETTO_TP_COUNTER_TRACK_DEF, C) \
+ C(uint32_t, upid)
+
+PERFETTO_TP_TABLE(PERFETTO_TP_PROCESS_COUNTER_TRACK_DEF);
+
+#define PERFETTO_TP_CPU_COUNTER_TRACK_DEF(NAME, PARENT, C) \
+ NAME(CpuCounterTrackTable, "cpu_counter_track") \
+ PARENT(PERFETTO_TP_COUNTER_TRACK_DEF, C) \
+ C(uint32_t, cpu)
+
+PERFETTO_TP_TABLE(PERFETTO_TP_CPU_COUNTER_TRACK_DEF);
+
+#define PERFETTO_TP_IRQ_COUNTER_TRACK_DEF(NAME, PARENT, C) \
+ NAME(IrqCounterTrackTable, "irq_counter_track") \
+ PARENT(PERFETTO_TP_COUNTER_TRACK_DEF, C) \
+ C(int32_t, irq)
+
+PERFETTO_TP_TABLE(PERFETTO_TP_IRQ_COUNTER_TRACK_DEF);
+
+#define PERFETTO_TP_SOFTIRQ_COUNTER_TRACK_DEF(NAME, PARENT, C) \
+ NAME(SoftirqCounterTrackTable, "softirq_counter_track") \
+ PARENT(PERFETTO_TP_COUNTER_TRACK_DEF, C) \
+ C(int32_t, softirq)
+
+PERFETTO_TP_TABLE(PERFETTO_TP_SOFTIRQ_COUNTER_TRACK_DEF);
+
+#define PERFETTO_TP_GPU_COUNTER_TRACK_DEF(NAME, PARENT, C) \
+ NAME(GpuCounterTrackTable, "gpu_counter_track") \
+ PARENT(PERFETTO_TP_COUNTER_TRACK_DEF, C) \
+ C(uint32_t, gpu_id)
+
+PERFETTO_TP_TABLE(PERFETTO_TP_GPU_COUNTER_TRACK_DEF);
+
} // namespace tables
} // namespace trace_processor
} // namespace perfetto
diff --git a/src/trace_processor/thread_table.cc b/src/trace_processor/thread_table.cc
index a951812..ba339e8 100644
--- a/src/trace_processor/thread_table.cc
+++ b/src/trace_processor/thread_table.cc
@@ -76,9 +76,9 @@
sqlite3_value** argv) {
*this = Cursor(table_);
- min = 0;
- max = static_cast<uint32_t>(storage_->thread_count()) - 1;
- desc = false;
+ min_ = 0;
+ max_ = static_cast<uint32_t>(storage_->thread_count());
+ desc_ = false;
for (size_t j = 0; j < qc.constraints().size(); j++) {
const auto& cs = qc.constraints()[j];
@@ -86,30 +86,31 @@
UniqueTid constraint_utid =
static_cast<UniqueTid>(sqlite3_value_int(argv[j]));
// Filter the range of utids that we are interested in, based on the
- // constraints in the query. Everything between min and max (inclusive)
+ // constraints in the query. Everything between min and max (exclusive)
// will be returned.
if (IsOpEq(cs.op)) {
- min = constraint_utid;
- max = constraint_utid;
+ min_ = constraint_utid;
+ max_ = constraint_utid + 1;
} else if (IsOpGe(cs.op) || IsOpGt(cs.op)) {
- min = IsOpGt(cs.op) ? constraint_utid + 1 : constraint_utid;
+ min_ = IsOpGt(cs.op) ? constraint_utid + 1 : constraint_utid;
} else if (IsOpLe(cs.op) || IsOpLt(cs.op)) {
- max = IsOpLt(cs.op) ? constraint_utid - 1 : constraint_utid;
+ max_ = IsOpLt(cs.op) ? constraint_utid : constraint_utid + 1;
}
}
}
for (const auto& ob : qc.order_by()) {
if (ob.iColumn == Column::kUtid) {
- desc = ob.desc;
+ desc_ = ob.desc;
}
}
- current = desc ? max : min;
+ index_ = 0;
return SQLITE_OK;
}
int ThreadTable::Cursor::Column(sqlite3_context* context, int N) {
+ uint32_t current = desc_ ? max_ - index_ - 1 : min_ + index_;
const auto& thread = storage_->GetThread(current);
switch (N) {
case Column::kUtid: {
@@ -158,16 +159,12 @@
}
int ThreadTable::Cursor::Next() {
- if (desc) {
- --current;
- } else {
- ++current;
- }
+ ++index_;
return SQLITE_OK;
}
int ThreadTable::Cursor::Eof() {
- return desc ? current < min : current > max;
+ return index_ >= (max_ - min_);
}
} // namespace trace_processor
} // namespace perfetto
diff --git a/src/trace_processor/thread_table.h b/src/trace_processor/thread_table.h
index a72ed23..43484d1 100644
--- a/src/trace_processor/thread_table.h
+++ b/src/trace_processor/thread_table.h
@@ -55,10 +55,10 @@
Cursor(Cursor&&) noexcept = default;
Cursor& operator=(Cursor&&) = default;
- UniqueTid min;
- UniqueTid max;
- UniqueTid current;
- bool desc;
+ UniqueTid min_ = 0;
+ UniqueTid max_ = 0;
+ uint32_t index_ = 0;
+ bool desc_ = false;
const TraceStorage* storage_ = nullptr;
ThreadTable* table_ = nullptr;
diff --git a/src/trace_processor/trace_processor_impl.cc b/src/trace_processor/trace_processor_impl.cc
index 64c558a..bbbe087 100644
--- a/src/trace_processor/trace_processor_impl.cc
+++ b/src/trace_processor/trace_processor_impl.cc
@@ -25,7 +25,6 @@
#include "perfetto/ext/base/string_utils.h"
#include "src/trace_processor/android_logs_table.h"
#include "src/trace_processor/args_table.h"
-#include "src/trace_processor/counter_definitions_table.h"
#include "src/trace_processor/counter_values_table.h"
#include "src/trace_processor/cpu_profile_stack_sample_table.h"
#include "src/trace_processor/heap_profile_allocation_table.h"
@@ -136,9 +135,35 @@
void CreateBuiltinViews(sqlite3* db) {
char* error = nullptr;
sqlite3_exec(db,
+ "CREATE VIEW counter_definitions AS "
+ "SELECT "
+ " *, "
+ " id AS counter_id "
+ "FROM counter_track",
+ 0, 0, &error);
+ if (error) {
+ PERFETTO_ELOG("Error initializing: %s", error);
+ sqlite3_free(error);
+ }
+
+ sqlite3_exec(db,
+ "CREATE VIEW counter_values AS "
+ "SELECT "
+ " *, "
+ " track_id as counter_id "
+ "FROM counter",
+ 0, 0, &error);
+ if (error) {
+ PERFETTO_ELOG("Error initializing: %s", error);
+ sqlite3_free(error);
+ }
+
+ sqlite3_exec(db,
"CREATE VIEW counters AS "
- "SELECT * FROM counter_values "
- "INNER JOIN counter_definitions USING(counter_id) "
+ "SELECT * "
+ "FROM counter_values v "
+ "INNER JOIN counter_track t "
+ "ON v.track_id = t.id "
"ORDER BY ts;",
0, 0, &error);
if (error) {
@@ -150,7 +175,7 @@
"CREATE VIEW slice AS "
"SELECT "
" *, "
- " category as cat, "
+ " category AS cat, "
" CASE ref_type "
" WHEN 'utid' THEN ref "
" ELSE NULL "
@@ -316,7 +341,6 @@
SliceTable::RegisterTable(*db_, context_.storage.get());
SqlStatsTable::RegisterTable(*db_, context_.storage.get());
ThreadTable::RegisterTable(*db_, context_.storage.get());
- CounterDefinitionsTable::RegisterTable(*db_, context_.storage.get());
CounterValuesTable::RegisterTable(*db_, context_.storage.get());
SpanJoinOperatorTable::RegisterTable(*db_, context_.storage.get());
WindowOperatorTable::RegisterTable(*db_, context_.storage.get());
@@ -332,6 +356,7 @@
// New style db-backed tables.
const TraceStorage* storage = context_.storage.get();
+
DbSqliteTable::RegisterTable(*db_, &storage->track_table(),
storage->track_table().table_name());
DbSqliteTable::RegisterTable(*db_, &storage->thread_track_table(),
@@ -342,16 +367,37 @@
storage->gpu_slice_table().table_name());
DbSqliteTable::RegisterTable(*db_, &storage->gpu_track_table(),
storage->gpu_track_table().table_name());
- DbSqliteTable::RegisterTable(*db_, &storage->symbol_table(),
- storage->symbol_table().table_name());
+
+ DbSqliteTable::RegisterTable(*db_, &storage->counter_track_table(),
+ storage->counter_track_table().table_name());
+ DbSqliteTable::RegisterTable(
+ *db_, &storage->process_counter_track_table(),
+ storage->process_counter_track_table().table_name());
+ DbSqliteTable::RegisterTable(
+ *db_, &storage->thread_counter_track_table(),
+ storage->thread_counter_track_table().table_name());
+ DbSqliteTable::RegisterTable(*db_, &storage->cpu_counter_track_table(),
+ storage->cpu_counter_track_table().table_name());
+ DbSqliteTable::RegisterTable(*db_, &storage->irq_counter_track_table(),
+ storage->irq_counter_track_table().table_name());
+ DbSqliteTable::RegisterTable(
+ *db_, &storage->softirq_counter_track_table(),
+ storage->softirq_counter_track_table().table_name());
+ DbSqliteTable::RegisterTable(*db_, &storage->gpu_counter_track_table(),
+ storage->gpu_counter_track_table().table_name());
+
DbSqliteTable::RegisterTable(*db_, &storage->heap_graph_object_table(),
storage->heap_graph_object_table().table_name());
DbSqliteTable::RegisterTable(
- *db_, &storage->stack_profile_callsite_table(),
- storage->stack_profile_callsite_table().table_name());
- DbSqliteTable::RegisterTable(
*db_, &storage->heap_graph_reference_table(),
storage->heap_graph_reference_table().table_name());
+
+ DbSqliteTable::RegisterTable(*db_, &storage->symbol_table(),
+ storage->symbol_table().table_name());
+ DbSqliteTable::RegisterTable(
+ *db_, &storage->stack_profile_callsite_table(),
+ storage->stack_profile_callsite_table().table_name());
+
DbSqliteTable::RegisterTable(
*db_, &storage->vulkan_memory_allocations_table(),
storage->vulkan_memory_allocations_table().table_name());
diff --git a/src/trace_processor/trace_storage.h b/src/trace_processor/trace_storage.h
index db91884..a832e9f 100644
--- a/src/trace_processor/trace_storage.h
+++ b/src/trace_processor/trace_storage.h
@@ -80,6 +80,10 @@
using TrackId = uint32_t;
+// TODO(lalitm): this is a temporary hack while migrating the counters table and
+// will be removed when the migration is complete.
+static const TrackId kInvalidTrackId = std::numeric_limits<TrackId>::max();
+
enum class RefType {
kRefNoRef = 0,
kRefUtid = 1,
@@ -509,98 +513,43 @@
std::deque<int64_t> thread_instruction_deltas_;
};
- class CounterDefinitions {
- public:
- using Id = uint32_t;
- static constexpr Id kInvalidId = std::numeric_limits<Id>::max();
-
- inline Id AddCounterDefinition(StringId name_id,
- int64_t ref,
- RefType type,
- StringId desc_id = 0,
- StringId unit_id = 0) {
- base::Hash hash;
- hash.Update(name_id);
- hash.Update(ref);
- hash.Update(type);
-
- // TODO(lalitm): this is a perf bottleneck and likely we can do something
- // quite a bit better here.
- uint64_t digest = hash.digest();
- auto it = hash_to_row_idx_.find(digest);
- if (it != hash_to_row_idx_.end())
- return it->second;
-
- name_ids_.emplace_back(name_id);
- refs_.emplace_back(ref);
- types_.emplace_back(type);
- desc_ids_.emplace_back(desc_id);
- unit_ids_.emplace_back(unit_id);
- hash_to_row_idx_.emplace(digest, size() - 1);
- return size() - 1;
- }
-
- uint32_t size() const { return static_cast<uint32_t>(name_ids_.size()); }
-
- const std::deque<StringId>& name_ids() const { return name_ids_; }
-
- const std::deque<StringId>& desc_ids() const { return desc_ids_; }
-
- const std::deque<StringId>& unit_ids() const { return unit_ids_; }
-
- const std::deque<int64_t>& refs() const { return refs_; }
-
- const std::deque<RefType>& types() const { return types_; }
-
- private:
- std::deque<StringId> name_ids_;
- std::deque<int64_t> refs_;
- std::deque<RefType> types_;
- std::deque<StringId> desc_ids_;
- std::deque<StringId> unit_ids_;
-
- std::unordered_map<uint64_t, uint32_t> hash_to_row_idx_;
- };
-
class CounterValues {
public:
- inline uint32_t AddCounterValue(CounterDefinitions::Id counter_id,
+ inline uint32_t AddCounterValue(TrackId track_id,
int64_t timestamp,
double value) {
- counter_ids_.emplace_back(counter_id);
+ track_id_.emplace_back(track_id);
timestamps_.emplace_back(timestamp);
values_.emplace_back(value);
arg_set_ids_.emplace_back(kInvalidArgSetId);
- if (counter_id != CounterDefinitions::kInvalidId) {
- if (counter_id >= rows_for_counter_id_.size()) {
- rows_for_counter_id_.resize(counter_id + 1);
+ if (track_id != kInvalidTrackId) {
+ if (track_id >= rows_for_track_id_.size()) {
+ rows_for_track_id_.resize(track_id + 1);
}
- rows_for_counter_id_[counter_id].emplace_back(size() - 1);
+ rows_for_track_id_[track_id].emplace_back(size() - 1);
}
return size() - 1;
}
- void set_counter_id(uint32_t index, CounterDefinitions::Id counter_id) {
- PERFETTO_DCHECK(counter_ids_[index] == CounterDefinitions::kInvalidId);
+ void set_track_id(uint32_t index, TrackId track_id) {
+ PERFETTO_DCHECK(track_id_[index] == kInvalidTrackId);
- counter_ids_[index] = counter_id;
- if (counter_id >= rows_for_counter_id_.size()) {
- rows_for_counter_id_.resize(counter_id + 1);
+ track_id_[index] = track_id;
+ if (track_id >= rows_for_track_id_.size()) {
+ rows_for_track_id_.resize(track_id + 1);
}
- auto* new_rows = &rows_for_counter_id_[counter_id];
+ auto* new_rows = &rows_for_track_id_[track_id];
new_rows->insert(
std::upper_bound(new_rows->begin(), new_rows->end(), index), index);
}
void set_arg_set_id(uint32_t row, ArgSetId id) { arg_set_ids_[row] = id; }
- uint32_t size() const { return static_cast<uint32_t>(counter_ids_.size()); }
+ uint32_t size() const { return static_cast<uint32_t>(track_id_.size()); }
- const std::deque<CounterDefinitions::Id>& counter_ids() const {
- return counter_ids_;
- }
+ const std::deque<TrackId>& track_ids() const { return track_id_; }
const std::deque<int64_t>& timestamps() const { return timestamps_; }
@@ -608,19 +557,18 @@
const std::deque<ArgSetId>& arg_set_ids() const { return arg_set_ids_; }
- const std::deque<std::vector<uint32_t>>& rows_for_counter_id() const {
- return rows_for_counter_id_;
+ const std::deque<std::vector<uint32_t>>& rows_for_track_id() const {
+ return rows_for_track_id_;
}
private:
- std::deque<CounterDefinitions::Id> counter_ids_;
+ std::deque<TrackId> track_id_;
std::deque<int64_t> timestamps_;
std::deque<double> values_;
std::deque<ArgSetId> arg_set_ids_;
- // Indexed by counter_id value and contains the row numbers corresponding to
- // it.
- std::deque<std::vector<uint32_t>> rows_for_counter_id_;
+ // Indexed by track_id and contains the row numbers corresponding to it.
+ std::deque<std::vector<uint32_t>> rows_for_track_id_;
};
class SqlStats {
@@ -1156,6 +1104,55 @@
return &thread_track_table_;
}
+ const tables::CounterTrackTable& counter_track_table() const {
+ return counter_track_table_;
+ }
+ tables::CounterTrackTable* mutable_counter_track_table() {
+ return &counter_track_table_;
+ }
+
+ const tables::ThreadCounterTrackTable& thread_counter_track_table() const {
+ return thread_counter_track_table_;
+ }
+ tables::ThreadCounterTrackTable* mutable_thread_counter_track_table() {
+ return &thread_counter_track_table_;
+ }
+
+ const tables::ProcessCounterTrackTable& process_counter_track_table() const {
+ return process_counter_track_table_;
+ }
+ tables::ProcessCounterTrackTable* mutable_process_counter_track_table() {
+ return &process_counter_track_table_;
+ }
+
+ const tables::CpuCounterTrackTable& cpu_counter_track_table() const {
+ return cpu_counter_track_table_;
+ }
+ tables::CpuCounterTrackTable* mutable_cpu_counter_track_table() {
+ return &cpu_counter_track_table_;
+ }
+
+ const tables::IrqCounterTrackTable& irq_counter_track_table() const {
+ return irq_counter_track_table_;
+ }
+ tables::IrqCounterTrackTable* mutable_irq_counter_track_table() {
+ return &irq_counter_track_table_;
+ }
+
+ const tables::SoftirqCounterTrackTable& softirq_counter_track_table() const {
+ return softirq_counter_track_table_;
+ }
+ tables::SoftirqCounterTrackTable* mutable_softirq_counter_track_table() {
+ return &softirq_counter_track_table_;
+ }
+
+ const tables::GpuCounterTrackTable& gpu_counter_track_table() const {
+ return gpu_counter_track_table_;
+ }
+ tables::GpuCounterTrackTable* mutable_gpu_counter_track_table() {
+ return &gpu_counter_track_table_;
+ }
+
const Slices& slices() const { return slices_; }
Slices* mutable_slices() { return &slices_; }
@@ -1177,13 +1174,6 @@
}
tables::GpuSliceTable* mutable_gpu_slice_table() { return &gpu_slice_table_; }
- const CounterDefinitions& counter_definitions() const {
- return counter_definitions_;
- }
- CounterDefinitions* mutable_counter_definitions() {
- return &counter_definitions_;
- }
-
const CounterValues& counter_values() const { return counter_values_; }
CounterValues* mutable_counter_values() { return &counter_values_; }
@@ -1322,6 +1312,21 @@
tables::ProcessTrackTable process_track_table_{&string_pool_, &track_table_};
tables::ThreadTrackTable thread_track_table_{&string_pool_, &track_table_};
+ // Track tables for counter events.
+ tables::CounterTrackTable counter_track_table_{&string_pool_, &track_table_};
+ tables::ThreadCounterTrackTable thread_counter_track_table_{
+ &string_pool_, &counter_track_table_};
+ tables::ProcessCounterTrackTable process_counter_track_table_{
+ &string_pool_, &counter_track_table_};
+ tables::CpuCounterTrackTable cpu_counter_track_table_{&string_pool_,
+ &counter_track_table_};
+ tables::IrqCounterTrackTable irq_counter_track_table_{&string_pool_,
+ &counter_track_table_};
+ tables::SoftirqCounterTrackTable softirq_counter_track_table_{
+ &string_pool_, &counter_track_table_};
+ tables::GpuCounterTrackTable gpu_counter_track_table_{&string_pool_,
+ &counter_track_table_};
+
// Metadata for gpu tracks.
GpuContexts gpu_contexts_;
@@ -1353,9 +1358,6 @@
// NestableSlices).
tables::GpuSliceTable gpu_slice_table_{&string_pool_, nullptr};
- // The type of counters in the trace. Can be thought of as the "metadata".
- CounterDefinitions counter_definitions_;
-
// The values from the Counter events from the trace. This includes CPU
// frequency events as well systrace trace_marker counter events.
CounterValues counter_values_;
diff --git a/src/trace_processor/track_tracker.cc b/src/trace_processor/track_tracker.cc
index dd57e8b..5cc9746 100644
--- a/src/trace_processor/track_tracker.cc
+++ b/src/trace_processor/track_tracker.cc
@@ -319,5 +319,133 @@
default_descriptor_track_name_);
}
+TrackId TrackTracker::InternGlobalCounterTrack(StringId name) {
+ auto it = global_counter_tracks_by_name_.find(name);
+ if (it != global_counter_tracks_by_name_.end()) {
+ return it->second;
+ }
+
+ tables::CounterTrackTable::Row row(name);
+ TrackId track = context_->storage->mutable_counter_track_table()->Insert(row);
+ global_counter_tracks_by_name_[name] = track;
+ return track;
+}
+
+TrackId TrackTracker::InternCpuCounterTrack(StringId name, uint32_t cpu) {
+ auto it = cpu_counter_tracks_.find(std::make_pair(name, cpu));
+ if (it != cpu_counter_tracks_.end()) {
+ return it->second;
+ }
+
+ tables::CpuCounterTrackTable::Row row(name);
+ row.cpu = cpu;
+ row.ref = cpu;
+ row.ref_type = context_->storage->InternString(
+ GetRefTypeStringMap()[static_cast<size_t>(RefType::kRefCpuId)]);
+
+ TrackId track =
+ context_->storage->mutable_cpu_counter_track_table()->Insert(row);
+ cpu_counter_tracks_[std::make_pair(name, cpu)] = track;
+ return track;
+}
+
+TrackId TrackTracker::InternThreadCounterTrack(StringId name, UniqueTid utid) {
+ auto it = utid_counter_tracks_.find(std::make_pair(name, utid));
+ if (it != utid_counter_tracks_.end()) {
+ return it->second;
+ }
+
+ tables::ThreadCounterTrackTable::Row row(name);
+ row.utid = utid;
+ row.ref = utid;
+ row.ref_type = context_->storage->InternString(
+ GetRefTypeStringMap()[static_cast<size_t>(RefType::kRefUtid)]);
+
+ TrackId track =
+ context_->storage->mutable_thread_counter_track_table()->Insert(row);
+ utid_counter_tracks_[std::make_pair(name, utid)] = track;
+ return track;
+}
+
+TrackId TrackTracker::InternProcessCounterTrack(StringId name, UniquePid upid) {
+ auto it = upid_counter_tracks_.find(std::make_pair(name, upid));
+ if (it != upid_counter_tracks_.end()) {
+ return it->second;
+ }
+
+ tables::ProcessCounterTrackTable::Row row(name);
+ row.upid = upid;
+ row.ref = upid;
+ row.ref_type = context_->storage->InternString(
+ GetRefTypeStringMap()[static_cast<size_t>(RefType::kRefUpid)]);
+
+ TrackId track =
+ context_->storage->mutable_process_counter_track_table()->Insert(row);
+ upid_counter_tracks_[std::make_pair(name, upid)] = track;
+ return track;
+}
+
+TrackId TrackTracker::InternIrqCounterTrack(StringId name, int32_t irq) {
+ auto it = irq_counter_tracks_.find(std::make_pair(name, irq));
+ if (it != irq_counter_tracks_.end()) {
+ return it->second;
+ }
+
+ tables::IrqCounterTrackTable::Row row(name);
+ row.irq = irq;
+ row.ref = irq;
+ row.ref_type = context_->storage->InternString(
+ GetRefTypeStringMap()[static_cast<size_t>(RefType::kRefIrq)]);
+
+ TrackId track =
+ context_->storage->mutable_irq_counter_track_table()->Insert(row);
+ irq_counter_tracks_[std::make_pair(name, irq)] = track;
+ return track;
+}
+
+TrackId TrackTracker::InternSoftirqCounterTrack(StringId name,
+ int32_t softirq) {
+ auto it = softirq_counter_tracks_.find(std::make_pair(name, softirq));
+ if (it != softirq_counter_tracks_.end()) {
+ return it->second;
+ }
+
+ tables::SoftirqCounterTrackTable::Row row(name);
+ row.softirq = softirq;
+ row.ref = softirq;
+ row.ref_type = context_->storage->InternString(
+ GetRefTypeStringMap()[static_cast<size_t>(RefType::kRefSoftIrq)]);
+
+ TrackId track =
+ context_->storage->mutable_softirq_counter_track_table()->Insert(row);
+ softirq_counter_tracks_[std::make_pair(name, softirq)] = track;
+ return track;
+}
+
+TrackId TrackTracker::InternGpuCounterTrack(StringId name, uint32_t gpu_id) {
+ auto it = gpu_counter_tracks_.find(std::make_pair(name, gpu_id));
+ if (it != gpu_counter_tracks_.end()) {
+ return it->second;
+ }
+ TrackId track = CreateGpuCounterTrack(name, gpu_id);
+ gpu_counter_tracks_[std::make_pair(name, gpu_id)] = track;
+ return track;
+}
+
+TrackId TrackTracker::CreateGpuCounterTrack(StringId name,
+ uint32_t gpu_id,
+ StringId description,
+ StringId unit) {
+ tables::GpuCounterTrackTable::Row row(name);
+ row.gpu_id = gpu_id;
+ row.description = description;
+ row.unit = unit;
+ row.ref = gpu_id;
+ row.ref_type = context_->storage->InternString(
+ GetRefTypeStringMap()[static_cast<size_t>(RefType::kRefGpuId)]);
+
+ return context_->storage->mutable_gpu_counter_track_table()->Insert(row);
+}
+
} // namespace trace_processor
} // namespace perfetto
diff --git a/src/trace_processor/track_tracker.h b/src/trace_processor/track_tracker.h
index 8d064b4..8ef379a 100644
--- a/src/trace_processor/track_tracker.h
+++ b/src/trace_processor/track_tracker.h
@@ -75,6 +75,33 @@
// Returns the ID of the implicit trace-global default TrackDescriptor track.
TrackId GetOrCreateDefaultDescriptorTrack();
+ // Interns a global counter track into the storage.
+ TrackId InternGlobalCounterTrack(StringId name);
+
+ // Interns a counter track associated with a cpu into the storage.
+ TrackId InternCpuCounterTrack(StringId name, uint32_t cpu);
+
+ // Interns a counter track associated with a thread into the storage.
+ TrackId InternThreadCounterTrack(StringId name, UniqueTid utid);
+
+ // Interns a counter track associated with a process into the storage.
+ TrackId InternProcessCounterTrack(StringId name, UniquePid upid);
+
+ // Interns a counter track associated with an irq into the storage.
+ TrackId InternIrqCounterTrack(StringId name, int32_t irq);
+
+ // Interns a counter track associated with an softirq into the storage.
+ TrackId InternSoftirqCounterTrack(StringId name, int32_t softirq);
+
+ // Interns a counter track associated with a GPU into the storage.
+ TrackId InternGpuCounterTrack(StringId name, uint32_t gpu_id);
+
+ // Creates a counter track associated with a GPU into the storage.
+ TrackId CreateGpuCounterTrack(StringId name,
+ uint32_t gpu_id,
+ StringId description = 0,
+ StringId unit = 0);
+
private:
struct GpuTrackTuple {
StringId track_name;
@@ -121,6 +148,14 @@
std::map<uint64_t /* uuid */, TrackId> descriptor_tracks_;
std::map<UniqueTid, TrackId> descriptor_tracks_by_utid_;
+ std::map<StringId, TrackId> global_counter_tracks_by_name_;
+ std::map<std::pair<StringId, uint32_t>, TrackId> cpu_counter_tracks_;
+ std::map<std::pair<StringId, UniqueTid>, TrackId> utid_counter_tracks_;
+ std::map<std::pair<StringId, UniquePid>, TrackId> upid_counter_tracks_;
+ std::map<std::pair<StringId, int32_t>, TrackId> irq_counter_tracks_;
+ std::map<std::pair<StringId, int32_t>, TrackId> softirq_counter_tracks_;
+ std::map<std::pair<StringId, uint32_t>, TrackId> gpu_counter_tracks_;
+
const StringId source_key_ = 0;
const StringId source_id_key_ = 0;
const StringId source_id_is_process_scoped_key_ = 0;
diff --git a/src/trace_processor/window_operator_table.cc b/src/trace_processor/window_operator_table.cc
index cbc8d78..727b32a 100644
--- a/src/trace_processor/window_operator_table.cc
+++ b/src/trace_processor/window_operator_table.cc
@@ -65,10 +65,9 @@
BestIndexInfo* info) {
// Remove ordering on timestamp if it is the only ordering as we are already
// sorted on TS. This makes span joining significantly faster.
- if (qc.order_by().size() == 1 && qc.order_by()[0].iColumn == Column::kTs &&
- !qc.order_by()[0].desc) {
- info->order_by_consumed = true;
- }
+ const auto& ob = qc.order_by();
+ info->prune_order_by =
+ ob.size() == 1 && ob[0].iColumn == Column::kTs && !ob[0].desc;
return SQLITE_OK;
}
diff --git a/src/traced/probes/ftrace/compact_sched.cc b/src/traced/probes/ftrace/compact_sched.cc
index 6bc7619..63b87ff 100644
--- a/src/traced/probes/ftrace/compact_sched.cc
+++ b/src/traced/probes/ftrace/compact_sched.cc
@@ -169,8 +169,8 @@
compact_out->set_switch_next_prio(switch_next_prio_);
for (size_t i = 0; i < interned_switch_comms_size_; i++) {
- compact_out->add_switch_next_comm_table(interned_switch_comms_[i].data(),
- interned_switch_comms_[i].size());
+ compact_out->add_intern_table(interned_switch_comms_[i].data(),
+ interned_switch_comms_[i].size());
}
compact_out->set_switch_next_comm_index(switch_next_comm_index_);
}
diff --git a/src/traced/probes/ftrace/cpu_reader_unittest.cc b/src/traced/probes/ftrace/cpu_reader_unittest.cc
index d008744..7f17c07 100644
--- a/src/traced/probes/ftrace/cpu_reader_unittest.cc
+++ b/src/traced/probes/ftrace/cpu_reader_unittest.cc
@@ -861,7 +861,7 @@
EXPECT_EQ(6, compact_sched.switch_next_pid().size());
EXPECT_EQ(6, compact_sched.switch_next_prio().size());
// 4 unique interned next_comm strings:
- EXPECT_EQ(4, compact_sched.switch_next_comm_table().size());
+ EXPECT_EQ(4, compact_sched.intern_table().size());
EXPECT_EQ(6, compact_sched.switch_next_comm_index().size());
// First event exactly as expected (absolute timestamp):
@@ -870,7 +870,7 @@
EXPECT_EQ(1, compact_sched.switch_prev_state(0));
EXPECT_EQ(3733, compact_sched.switch_next_pid(0));
EXPECT_EQ(120, compact_sched.switch_next_prio(0));
- std::string next_comm = compact_sched.switch_next_comm_table(
+ std::string next_comm = compact_sched.intern_table(
static_cast<int>(compact_sched.switch_next_comm_index(0)));
EXPECT_EQ("sleep", next_comm);
}
diff --git a/src/tracing/BUILD.gn b/src/tracing/BUILD.gn
index babb52e..9c58d68 100644
--- a/src/tracing/BUILD.gn
+++ b/src/tracing/BUILD.gn
@@ -275,6 +275,7 @@
"../../include/perfetto/tracing/core",
"../../protos/perfetto/trace:lite",
"../../protos/perfetto/trace:zero",
+ "../../protos/perfetto/trace/interned_data:zero",
"../base",
"test:api_test_support",
]
diff --git a/src/tracing/api_integrationtest.cc b/src/tracing/api_integrationtest.cc
index 3151eec..dee34a4 100644
--- a/src/tracing/api_integrationtest.cc
+++ b/src/tracing/api_integrationtest.cc
@@ -24,11 +24,13 @@
#include <vector>
#include "perfetto/tracing.h"
+#include "protos/perfetto/trace/interned_data/interned_data.pbzero.h"
#include "protos/perfetto/trace/test_event.pbzero.h"
#include "protos/perfetto/trace/trace.pb.h"
#include "protos/perfetto/trace/trace_packet.pbzero.h"
#include "protos/perfetto/trace/track_event/debug_annotation.pbzero.h"
#include "protos/perfetto/trace/track_event/log_message.pbzero.h"
+#include "protos/perfetto/trace/track_event/source_location.pbzero.h"
#include "test/gtest_and_gmock.h"
// Deliberately not pulling any non-public perfetto header to spot accidental
@@ -48,9 +50,27 @@
PERFETTO_CATEGORY(bar));
PERFETTO_TRACK_EVENT_STATIC_STORAGE();
+// For testing interning of complex objects.
+using SourceLocation = std::tuple<const char* /* file_name */,
+ const char* /* function_name */,
+ uint32_t /* line_number */>;
+
+namespace std {
+template <>
+struct hash<SourceLocation> {
+ size_t operator()(const SourceLocation& value) const {
+ auto hasher = hash<size_t>();
+ return hasher(reinterpret_cast<size_t>(get<0>(value))) ^
+ hasher(reinterpret_cast<size_t>(get<1>(value))) ^
+ hasher(get<2>(value));
+ }
+};
+} // namespace std
+
namespace {
using ::testing::_;
+using ::testing::ElementsAre;
using ::testing::HasSubstr;
using ::testing::Invoke;
using ::testing::InvokeWithoutArgs;
@@ -238,6 +258,59 @@
return handle;
}
+ std::vector<std::string> ReadLogMessagesFromTrace(
+ perfetto::TracingSession* tracing_session) {
+ std::vector<char> raw_trace = tracing_session->ReadTraceBlocking();
+ EXPECT_GE(raw_trace.size(), 0u);
+
+ // Read back the trace, maintaining interning tables as we go.
+ std::vector<std::string> log_messages;
+ std::map<uint64_t, std::string> log_message_bodies;
+ std::map<uint64_t, perfetto::protos::SourceLocation> source_locations;
+ perfetto::protos::Trace parsed_trace;
+ EXPECT_TRUE(
+ parsed_trace.ParseFromArray(raw_trace.data(), int(raw_trace.size())));
+
+ for (const auto& packet : parsed_trace.packet()) {
+ if (!packet.has_track_event())
+ continue;
+
+ if (packet.has_interned_data()) {
+ const auto& interned_data = packet.interned_data();
+ for (const auto& it : interned_data.log_message_body()) {
+ EXPECT_GE(it.iid(), 1u);
+ EXPECT_EQ(log_message_bodies.find(it.iid()),
+ log_message_bodies.end());
+ log_message_bodies[it.iid()] = it.body();
+ }
+ for (const auto& it : interned_data.source_locations()) {
+ EXPECT_GE(it.iid(), 1u);
+ EXPECT_EQ(source_locations.find(it.iid()), source_locations.end());
+ source_locations[it.iid()] = it;
+ }
+ }
+ const auto& track_event = packet.track_event();
+ if (track_event.type() != perfetto::protos::TrackEvent::TYPE_SLICE_BEGIN)
+ continue;
+
+ EXPECT_TRUE(track_event.has_log_message());
+ const auto& log = track_event.log_message();
+ if (log.source_location_iid()) {
+ std::stringstream msg;
+ const auto& source_location =
+ source_locations[log.source_location_iid()];
+ msg << source_location.function_name() << "("
+ << source_location.file_name() << ":"
+ << source_location.line_number()
+ << "): " << log_message_bodies[log.body_iid()];
+ log_messages.emplace_back(msg.str());
+ } else {
+ log_messages.emplace_back(log_message_bodies[log.body_iid()]);
+ }
+ }
+ return log_messages;
+ }
+
std::map<std::string, TestDataSourceHandle> data_sources_;
std::list<TestTracingSessionHandle> sessions_; // Needs stable pointers.
};
@@ -398,10 +471,14 @@
// Update incremental state.
if (packet.has_interned_data()) {
const auto& interned_data = packet.interned_data();
- for (const auto& it : interned_data.event_categories())
+ for (const auto& it : interned_data.event_categories()) {
+ EXPECT_EQ(categories.find(it.iid()), categories.end());
categories[it.iid()] = it.name();
- for (const auto& it : interned_data.event_names())
+ }
+ for (const auto& it : interned_data.event_names()) {
+ EXPECT_EQ(event_names.find(it.iid()), event_names.end());
event_names[it.iid()] = it.name();
+ }
}
EXPECT_GT(packet.timestamp(), 0u);
@@ -672,6 +749,251 @@
EXPECT_TRUE(found_args);
}
+struct InternedLogMessageBody
+ : public perfetto::TrackEventInternedDataIndex<
+ InternedLogMessageBody,
+ perfetto::protos::pbzero::InternedData::kLogMessageBodyFieldNumber,
+ std::string> {
+ static void Add(perfetto::protos::pbzero::InternedData* interned_data,
+ size_t iid,
+ const std::string& value) {
+ auto l = interned_data->add_log_message_body();
+ l->set_iid(iid);
+ l->set_body(value.data(), value.size());
+ commit_count++;
+ }
+
+ static int commit_count;
+};
+
+int InternedLogMessageBody::commit_count = 0;
+
+TEST_F(PerfettoApiTest, TrackEventTypedArgsWithInterning) {
+ // Setup the trace config.
+ perfetto::TraceConfig cfg;
+ cfg.set_duration_ms(500);
+ cfg.add_buffers()->set_size_kb(1024);
+ auto* ds_cfg = cfg.add_data_sources()->mutable_config();
+ ds_cfg->set_name("track_event");
+ ds_cfg->set_legacy_config("foo");
+
+ // Create a new trace session.
+ auto* tracing_session = NewTrace(cfg);
+ tracing_session->get()->StartBlocking();
+
+ std::stringstream large_message;
+ for (size_t i = 0; i < 512; i++)
+ large_message << i << ". Something wicked this way comes. ";
+
+ size_t body_iid;
+ InternedLogMessageBody::commit_count = 0;
+ TRACE_EVENT_BEGIN(
+ "foo", "EventWithState", [&](perfetto::TrackEventContext ctx) {
+ EXPECT_EQ(0, InternedLogMessageBody::commit_count);
+ body_iid = InternedLogMessageBody::Get(&ctx, "Alas, poor Yorick!");
+ auto log = ctx.track_event()->set_log_message();
+ log->set_body_iid(body_iid);
+ EXPECT_EQ(1, InternedLogMessageBody::commit_count);
+
+ auto body_iid2 =
+ InternedLogMessageBody::Get(&ctx, "Alas, poor Yorick!");
+ EXPECT_EQ(body_iid, body_iid2);
+ EXPECT_EQ(1, InternedLogMessageBody::commit_count);
+ });
+ TRACE_EVENT_END("foo");
+
+ TRACE_EVENT_BEGIN(
+ "foo", "EventWithState", [&](perfetto::TrackEventContext ctx) {
+ // Check that very large amounts of interned data works.
+ auto log = ctx.track_event()->set_log_message();
+ log->set_body_iid(
+ InternedLogMessageBody::Get(&ctx, large_message.str()));
+ EXPECT_EQ(2, InternedLogMessageBody::commit_count);
+ });
+ TRACE_EVENT_END("foo");
+
+ // Make sure interned data persists across trace points.
+ TRACE_EVENT_BEGIN(
+ "foo", "EventWithState", [&](perfetto::TrackEventContext ctx) {
+ auto body_iid2 =
+ InternedLogMessageBody::Get(&ctx, "Alas, poor Yorick!");
+ EXPECT_EQ(body_iid, body_iid2);
+
+ auto body_iid3 =
+ InternedLogMessageBody::Get(&ctx, "I knew him, Horatio");
+ EXPECT_NE(body_iid, body_iid3);
+ auto log = ctx.track_event()->set_log_message();
+ log->set_body_iid(body_iid3);
+ EXPECT_EQ(3, InternedLogMessageBody::commit_count);
+ });
+ TRACE_EVENT_END("foo");
+
+ tracing_session->get()->StopBlocking();
+ auto log_messages = ReadLogMessagesFromTrace(tracing_session->get());
+ EXPECT_THAT(log_messages,
+ ElementsAre("Alas, poor Yorick!", large_message.str(),
+ "I knew him, Horatio"));
+}
+
+struct InternedLogMessageBodySmall
+ : public perfetto::TrackEventInternedDataIndex<
+ InternedLogMessageBodySmall,
+ perfetto::protos::pbzero::InternedData::kLogMessageBodyFieldNumber,
+ const char*,
+ perfetto::SmallInternedDataTraits> {
+ static void Add(perfetto::protos::pbzero::InternedData* interned_data,
+ size_t iid,
+ const char* value) {
+ auto l = interned_data->add_log_message_body();
+ l->set_iid(iid);
+ l->set_body(value);
+ }
+};
+
+TEST_F(PerfettoApiTest, TrackEventTypedArgsWithInterningByValue) {
+ // Setup the trace config.
+ perfetto::TraceConfig cfg;
+ cfg.set_duration_ms(500);
+ cfg.add_buffers()->set_size_kb(1024);
+ auto* ds_cfg = cfg.add_data_sources()->mutable_config();
+ ds_cfg->set_name("track_event");
+ ds_cfg->set_legacy_config("foo");
+
+ // Create a new trace session.
+ auto* tracing_session = NewTrace(cfg);
+ tracing_session->get()->StartBlocking();
+
+ size_t body_iid;
+ TRACE_EVENT_BEGIN(
+ "foo", "EventWithState", [&](perfetto::TrackEventContext ctx) {
+ body_iid = InternedLogMessageBodySmall::Get(&ctx, "This above all:");
+ auto log = ctx.track_event()->set_log_message();
+ log->set_body_iid(body_iid);
+
+ auto body_iid2 =
+ InternedLogMessageBodySmall::Get(&ctx, "This above all:");
+ EXPECT_EQ(body_iid, body_iid2);
+
+ auto body_iid3 =
+ InternedLogMessageBodySmall::Get(&ctx, "to thine own self be true");
+ EXPECT_NE(body_iid, body_iid3);
+ });
+ TRACE_EVENT_END("foo");
+
+ tracing_session->get()->StopBlocking();
+ auto log_messages = ReadLogMessagesFromTrace(tracing_session->get());
+ EXPECT_THAT(log_messages, ElementsAre("This above all:"));
+}
+
+struct InternedLogMessageBodyHashed
+ : public perfetto::TrackEventInternedDataIndex<
+ InternedLogMessageBodyHashed,
+ perfetto::protos::pbzero::InternedData::kLogMessageBodyFieldNumber,
+ std::string,
+ perfetto::HashedInternedDataTraits> {
+ static void Add(perfetto::protos::pbzero::InternedData* interned_data,
+ size_t iid,
+ const std::string& value) {
+ auto l = interned_data->add_log_message_body();
+ l->set_iid(iid);
+ l->set_body(value.data(), value.size());
+ }
+};
+
+TEST_F(PerfettoApiTest, TrackEventTypedArgsWithInterningByHashing) {
+ // Setup the trace config.
+ perfetto::TraceConfig cfg;
+ cfg.set_duration_ms(500);
+ cfg.add_buffers()->set_size_kb(1024);
+ auto* ds_cfg = cfg.add_data_sources()->mutable_config();
+ ds_cfg->set_name("track_event");
+ ds_cfg->set_legacy_config("foo");
+
+ // Create a new trace session.
+ auto* tracing_session = NewTrace(cfg);
+ tracing_session->get()->StartBlocking();
+
+ size_t body_iid;
+ TRACE_EVENT_BEGIN(
+ "foo", "EventWithState", [&](perfetto::TrackEventContext ctx) {
+ // Test using a dynamically created interned value.
+ body_iid = InternedLogMessageBodyHashed::Get(
+ &ctx, std::string("Though this ") + "be madness,");
+ auto log = ctx.track_event()->set_log_message();
+ log->set_body_iid(body_iid);
+
+ auto body_iid2 =
+ InternedLogMessageBodyHashed::Get(&ctx, "Though this be madness,");
+ EXPECT_EQ(body_iid, body_iid2);
+
+ auto body_iid3 =
+ InternedLogMessageBodyHashed::Get(&ctx, "yet there is method in’t");
+ EXPECT_NE(body_iid, body_iid3);
+ });
+ TRACE_EVENT_END("foo");
+
+ tracing_session->get()->StopBlocking();
+ auto log_messages = ReadLogMessagesFromTrace(tracing_session->get());
+ EXPECT_THAT(log_messages, ElementsAre("Though this be madness,"));
+}
+
+struct InternedSourceLocation
+ : public perfetto::TrackEventInternedDataIndex<
+ InternedSourceLocation,
+ perfetto::protos::pbzero::InternedData::kSourceLocationsFieldNumber,
+ SourceLocation> {
+ static void Add(perfetto::protos::pbzero::InternedData* interned_data,
+ size_t iid,
+ const SourceLocation& value) {
+ auto l = interned_data->add_source_locations();
+ auto file_name = std::get<0>(value);
+ auto function_name = std::get<1>(value);
+ auto line_number = std::get<2>(value);
+ l->set_iid(iid);
+ l->set_file_name(file_name);
+ l->set_function_name(function_name);
+ l->set_line_number(line_number);
+ }
+};
+
+TEST_F(PerfettoApiTest, TrackEventTypedArgsWithInterningComplexValue) {
+ // Setup the trace config.
+ perfetto::TraceConfig cfg;
+ cfg.set_duration_ms(500);
+ cfg.add_buffers()->set_size_kb(1024);
+ auto* ds_cfg = cfg.add_data_sources()->mutable_config();
+ ds_cfg->set_name("track_event");
+ ds_cfg->set_legacy_config("foo");
+
+ // Create a new trace session.
+ auto* tracing_session = NewTrace(cfg);
+ tracing_session->get()->StartBlocking();
+
+ TRACE_EVENT_BEGIN(
+ "foo", "EventWithState", [&](perfetto::TrackEventContext ctx) {
+ const SourceLocation location{"file.cc", "SomeFunction", 123};
+ auto location_iid = InternedSourceLocation::Get(&ctx, location);
+ auto body_iid =
+ InternedLogMessageBody::Get(&ctx, "To be, or not to be");
+ auto log = ctx.track_event()->set_log_message();
+ log->set_source_location_iid(location_iid);
+ log->set_body_iid(body_iid);
+
+ auto location_iid2 = InternedSourceLocation::Get(&ctx, location);
+ EXPECT_EQ(location_iid, location_iid2);
+
+ const SourceLocation location2{"file.cc", "SomeFunction", 456};
+ auto location_iid3 = InternedSourceLocation::Get(&ctx, location2);
+ EXPECT_NE(location_iid, location_iid3);
+ });
+ TRACE_EVENT_END("foo");
+
+ tracing_session->get()->StopBlocking();
+ auto log_messages = ReadLogMessagesFromTrace(tracing_session->get());
+ EXPECT_THAT(log_messages,
+ ElementsAre("SomeFunction(file.cc:123): To be, or not to be"));
+}
+
TEST_F(PerfettoApiTest, OneDataSourceOneEvent) {
auto* data_source = &data_sources_["my_data_source"];
diff --git a/src/tracing/internal/track_event_internal.cc b/src/tracing/internal/track_event_internal.cc
index 5e3353d..2e65517 100644
--- a/src/tracing/internal/track_event_internal.cc
+++ b/src/tracing/internal/track_event_internal.cc
@@ -22,6 +22,7 @@
#include "perfetto/tracing/core/data_source_config.h"
#include "perfetto/tracing/track_event.h"
#include "perfetto/tracing/track_event_category_registry.h"
+#include "perfetto/tracing/track_event_interned_data_index.h"
#include "protos/perfetto/common/data_source_descriptor.gen.h"
#include "protos/perfetto/trace/interned_data/interned_data.pbzero.h"
#include "protos/perfetto/trace/track_event/process_descriptor.pbzero.h"
@@ -29,23 +30,48 @@
namespace perfetto {
namespace internal {
+
+BaseTrackEventInternedDataIndex::~BaseTrackEventInternedDataIndex() = default;
+
namespace {
std::atomic<perfetto::base::PlatformThreadID> g_main_thread;
+struct InternedEventCategory
+ : public TrackEventInternedDataIndex<
+ InternedEventCategory,
+ perfetto::protos::pbzero::InternedData::kEventCategoriesFieldNumber,
+ const char*,
+ SmallInternedDataTraits> {
+ static void Add(protos::pbzero::InternedData* interned_data,
+ size_t iid,
+ const char* value) {
+ auto category = interned_data->add_event_categories();
+ category->set_iid(iid);
+ category->set_name(value);
+ }
+};
+
+struct InternedEventName
+ : public TrackEventInternedDataIndex<
+ InternedEventName,
+ perfetto::protos::pbzero::InternedData::kEventNamesFieldNumber,
+ const char*,
+ SmallInternedDataTraits> {
+ static void 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);
+ }
+};
+
uint64_t GetTimeNs() {
// TODO(skyostil): Consider using boot time where available.
return static_cast<uint64_t>(perfetto::base::GetWallTimeNs().count());
}
-uint64_t GetNameIidOrZero(std::unordered_map<const char*, uint64_t>& name_map,
- const char* name) {
- auto it = name_map.find(name);
- if (it == name_map.end())
- return 0;
- return it->second;
-}
-
// static
void WriteSequenceDescriptors(TraceWriterBase* trace_writer,
uint64_t timestamp) {
@@ -124,32 +150,15 @@
// We assume that |category| and |name| point to strings with static lifetime.
// This means we can use their addresses as interning keys.
- uint64_t name_iid = GetNameIidOrZero(incr_state->event_names, name);
- uint64_t category_iid = GetNameIidOrZero(incr_state->categories, category);
- if (PERFETTO_UNLIKELY((name && !name_iid) || !category_iid)) {
- auto id = packet->set_interned_data();
- if (name && !name_iid) {
- auto event_name = id->add_event_names();
- name_iid = incr_state->event_names.size() + 1;
- event_name->set_name(name, strlen(name));
- event_name->set_iid(name_iid);
- incr_state->event_names[name] = name_iid;
- }
- if (!category_iid) {
- auto category_name = id->add_event_categories();
- category_iid = incr_state->categories.size() + 1;
- category_name->set_name(category, strlen(category));
- category_name->set_iid(category_iid);
- incr_state->categories[category] = category_iid;
- }
- }
- TrackEventContext ctx(std::move(packet));
+ TrackEventContext ctx(std::move(packet), incr_state);
+ size_t category_iid = InternedEventCategory::Get(&ctx, category);
auto track_event = ctx.track_event();
track_event->set_type(type);
// TODO(skyostil): Handle multiple categories.
track_event->add_category_iids(category_iid);
if (name) {
+ size_t name_iid = InternedEventName::Get(&ctx, name);
track_event->set_name_iid(name_iid);
}
return ctx;
diff --git a/src/tracing/track_event_context.cc b/src/tracing/track_event_context.cc
index 2c3e808..93f45cb 100644
--- a/src/tracing/track_event_context.cc
+++ b/src/tracing/track_event_context.cc
@@ -16,15 +16,35 @@
#include "perfetto/tracing/track_event_context.h"
+#include "protos/perfetto/trace/interned_data/interned_data.pbzero.h"
#include "protos/perfetto/trace/track_event/track_event.pbzero.h"
namespace perfetto {
TrackEventContext::TrackEventContext(
- TrackEventContext::TracePacketHandle trace_packet)
+ TrackEventContext::TracePacketHandle trace_packet,
+ internal::TrackEventIncrementalState* incremental_state)
: trace_packet_(std::move(trace_packet)),
- track_event_(trace_packet_->set_track_event()) {}
+ track_event_(trace_packet_->set_track_event()),
+ incremental_state_(incremental_state) {}
-TrackEventContext::~TrackEventContext() = default;
+TrackEventContext::~TrackEventContext() {
+ // 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_LIKELY(serialized_interned_data.empty()))
+ return;
+
+ 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();
+}
} // namespace perfetto
diff --git a/test/metrics/heap_profile_callsites.out b/test/metrics/heap_profile_callsites.out
index 6a975bb..5f8c14c 100644
--- a/test/metrics/heap_profile_callsites.out
+++ b/test/metrics/heap_profile_callsites.out
@@ -58,5 +58,7 @@
delta_bytes: 1090
}
}
+ profile_delta_bytes: 1090
+ profile_total_bytes: 2100
}
}
diff --git a/test/metrics/index b/test/metrics/index
index a159f21..8f29693 100644
--- a/test/metrics/index
+++ b/test/metrics/index
@@ -21,5 +21,7 @@
heap_profile.textproto heap_profile_callsites heap_profile_callsites.out
heap_profile_no_symbols.textproto unsymbolized_frames unsymbolized_frames.out
+../trace_processor/heap_graph.textproto java_heap_stats java_heap_stats.out
+
# Json output
../data/memory_counters.pb trace_metadata trace_metadata.json.out
diff --git a/test/metrics/java_heap_stats.out b/test/metrics/java_heap_stats.out
new file mode 100644
index 0000000..64db708
--- /dev/null
+++ b/test/metrics/java_heap_stats.out
@@ -0,0 +1,11 @@
+java_heap_stats {
+ instance_stats {
+ upid: 2
+ process_name: "system_server"
+ samples {
+ ts: 10
+ heap_size: 224
+ reachable_heap_size: 96
+ }
+ }
+}
diff --git a/test/trace_processor/filter_row_vector.sql b/test/trace_processor/filter_row_vector.sql
index d793cde..81a2a36 100644
--- a/test/trace_processor/filter_row_vector.sql
+++ b/test/trace_processor/filter_row_vector.sql
@@ -1,6 +1,14 @@
SELECT ts FROM counter_values
WHERE
ts > 72563651549 AND
- counter_id = 7 AND
+ counter_id = (
+ SELECT d.counter_id
+ FROM counter_definitions d
+ INNER JOIN process p on d.ref = p.upid
+ WHERE
+ d.name = 'Heap size (KB)'
+ AND d.ref_type = 'upid'
+ AND p.pid = 1204
+ ) AND
value != 17952.000000
LIMIT 20
diff --git a/test/trace_processor/heap_graph.textproto b/test/trace_processor/heap_graph.textproto
index eb32c54..b785578 100644
--- a/test/trace_processor/heap_graph.textproto
+++ b/test/trace_processor/heap_graph.textproto
@@ -16,6 +16,7 @@
trusted_packet_sequence_id: 999
timestamp: 10
heap_graph {
+ pid: 2
roots {
root_type: ROOT_JAVA_FRAME
object_ids: 0x01
@@ -32,12 +33,18 @@
type_id: 2
self_size: 32
}
+ objects {
+ id: 0x03
+ type_id: 2
+ self_size: 128
+ }
continued: true
index: 1
}
}
packet {
heap_graph {
+ pid: 2
type_names {
iid: 1
str: "FactoryProducerDelegateImplActor"
diff --git a/test/trace_processor/heap_graph_object.out b/test/trace_processor/heap_graph_object.out
index 48bc6b9..b0f9e43 100644
--- a/test/trace_processor/heap_graph_object.out
+++ b/test/trace_processor/heap_graph_object.out
@@ -1,3 +1,4 @@
"id","type","upid","graph_sample_ts","object_id","self_size","retained_size","unique_retained_size","reference_set_id","reachable","type_name","root_type"
-0,"heap_graph_object",0,10,1,64,96,96,0,1,"FactoryProducerDelegateImplActor","ROOT_JAVA_FRAME"
-1,"heap_graph_object",0,10,2,32,32,32,1,1,"Foo","[NULL]"
+0,"heap_graph_object",2,10,1,64,96,96,0,1,"FactoryProducerDelegateImplActor","ROOT_JAVA_FRAME"
+1,"heap_graph_object",2,10,2,32,32,32,1,1,"Foo","[NULL]"
+2,"heap_graph_object",2,10,3,128,-1,0,1,0,"Foo","[NULL]"
diff --git a/tools/compact_reencode/main.cc b/tools/compact_reencode/main.cc
index d54db1c..982be0e 100644
--- a/tools/compact_reencode/main.cc
+++ b/tools/compact_reencode/main.cc
@@ -113,7 +113,7 @@
auto* compact_sched = bundle_out->set_compact_sched();
for (const auto& s : string_table)
- compact_sched->add_switch_next_comm_table(s.data(), s.size());
+ compact_sched->add_intern_table(s.data(), s.size());
compact_sched->set_switch_timestamp(switch_timestamp);
compact_sched->set_switch_next_comm_index(switch_next_comm_index);
diff --git a/ui/src/controller/trace_controller.ts b/ui/src/controller/trace_controller.ts
index 8c93273..7edcbba 100644
--- a/ui/src/controller/trace_controller.ts
+++ b/ui/src/controller/trace_controller.ts
@@ -494,7 +494,9 @@
left join (select upid, sum(dur) as total_dur
from sched join thread using(utid)
group by upid
- ) using(upid) group by utid, upid
+ ) using(upid)
+ where utid != 0
+ group by utid, upid
order by total_dur desc, upid, utid`);
const upidToUuid = new Map<number, string>();