Merge changes I2c6ef9a4,I196e54e8
* changes:
Do not display total percentage next to self size.
Improve display of sizes in flamegraph.
diff --git a/include/perfetto/tracing/debug_annotation.h b/include/perfetto/tracing/debug_annotation.h
index 996861c..f13fbd9 100644
--- a/include/perfetto/tracing/debug_annotation.h
+++ b/include/perfetto/tracing/debug_annotation.h
@@ -21,6 +21,7 @@
#include <stdint.h>
+#include <memory>
#include <string>
namespace perfetto {
@@ -56,6 +57,12 @@
void WriteDebugAnnotation(protos::pbzero::DebugAnnotation*,
const DebugAnnotation&);
+template <typename T>
+void WriteDebugAnnotation(protos::pbzero::DebugAnnotation* annotation,
+ const std::unique_ptr<T>& value) {
+ WriteDebugAnnotation(annotation, *value);
+}
+
} // namespace internal
} // namespace perfetto
diff --git a/include/perfetto/tracing/track_event_legacy.h b/include/perfetto/tracing/track_event_legacy.h
index 8513024..bf83ca4 100644
--- a/include/perfetto/tracing/track_event_legacy.h
+++ b/include/perfetto/tracing/track_event_legacy.h
@@ -23,6 +23,7 @@
// to 1 activate the compatibility layer.
#include "perfetto/base/compiler.h"
+#include "perfetto/tracing/track_event.h"
#include <stdint.h>
@@ -118,6 +119,81 @@
// Internal legacy trace point implementation.
// ----------------------------------------------------------------------------
+namespace perfetto {
+namespace internal {
+
+class TrackEventLegacy {
+ public:
+ static constexpr protos::pbzero::TrackEvent::Type PhaseToType(char phase) {
+ // clang-format off
+ return (phase == TRACE_EVENT_PHASE_BEGIN) ?
+ protos::pbzero::TrackEvent::TYPE_SLICE_BEGIN :
+ (phase == TRACE_EVENT_PHASE_END) ?
+ protos::pbzero::TrackEvent::TYPE_SLICE_END :
+ (phase == TRACE_EVENT_PHASE_INSTANT) ?
+ protos::pbzero::TrackEvent::TYPE_INSTANT :
+ protos::pbzero::TrackEvent::TYPE_UNSPECIFIED;
+ // clang-format on
+ }
+
+ // Reduce binary size overhead by outlining most of the code for writing a
+ // legacy trace event.
+ template <typename... Args>
+ static void WriteLegacyEvent(EventContext ctx,
+ char phase,
+ uint32_t flags,
+ Args&&... args) PERFETTO_NO_INLINE {
+ AddDebugAnnotations(&ctx, std::forward<Args>(args)...);
+ SetTrackIfNeeded(&ctx, flags);
+ if (PhaseToType(phase) == protos::pbzero::TrackEvent::TYPE_UNSPECIFIED) {
+ auto legacy_event = ctx.event()->set_legacy_event();
+ legacy_event->set_phase(phase);
+ }
+ }
+
+ // No arguments.
+ static void AddDebugAnnotations(EventContext*) {}
+
+ // One argument.
+ template <typename ArgType>
+ static void AddDebugAnnotations(EventContext* ctx,
+ const char* arg_name,
+ ArgType&& arg_value) {
+ TrackEventInternal::AddDebugAnnotation(ctx, arg_name, arg_value);
+ }
+
+ // Two arguments.
+ template <typename ArgType, typename ArgType2>
+ static void AddDebugAnnotations(EventContext* ctx,
+ const char* arg_name,
+ ArgType&& arg_value,
+ const char* arg_name2,
+ ArgType2&& arg_value2) {
+ TrackEventInternal::AddDebugAnnotation(ctx, arg_name, arg_value);
+ TrackEventInternal::AddDebugAnnotation(ctx, arg_name2, arg_value2);
+ }
+
+ private:
+ static void SetTrackIfNeeded(EventContext* ctx, uint32_t flags) {
+ auto scope = flags & TRACE_EVENT_FLAG_SCOPE_MASK;
+ switch (scope) {
+ case TRACE_EVENT_SCOPE_GLOBAL:
+ ctx->event()->set_track_uuid(0);
+ break;
+ case TRACE_EVENT_SCOPE_PROCESS:
+ ctx->event()->set_track_uuid(ProcessTrack::Current().uuid);
+ break;
+ default:
+ case TRACE_EVENT_SCOPE_THREAD:
+ // Thread scope is already the default.
+ break;
+ }
+ }
+};
+
+} // namespace internal
+} // namespace perfetto
+
// A black hole trace point where unsupported trace events are routed.
#define PERFETTO_INTERNAL_EVENT_NOOP(cat, name, ...) \
do { \
@@ -129,9 +205,23 @@
// Implementations for the INTERNAL_* adapter macros used by the trace points
// below.
-#define INTERNAL_TRACE_EVENT_ADD(...) PERFETTO_INTERNAL_EVENT_NOOP(__VA_ARGS__)
-#define INTERNAL_TRACE_EVENT_ADD_SCOPED(...) \
- PERFETTO_INTERNAL_EVENT_NOOP(__VA_ARGS__)
+#define INTERNAL_TRACE_EVENT_ADD(phase, category, name, flags, ...) \
+ PERFETTO_INTERNAL_TRACK_EVENT( \
+ category, name, \
+ ::perfetto::internal::TrackEventLegacy::PhaseToType(phase), \
+ [&](perfetto::EventContext ctx) { \
+ using ::perfetto::internal::TrackEventLegacy; \
+ TrackEventLegacy::WriteLegacyEvent(std::move(ctx), phase, flags, \
+ ##__VA_ARGS__); \
+ })
+
+#define INTERNAL_TRACE_EVENT_ADD_SCOPED(category, name, ...) \
+ PERFETTO_INTERNAL_SCOPED_TRACK_EVENT( \
+ category, name, [&](perfetto::EventContext ctx) { \
+ using ::perfetto::internal::TrackEventLegacy; \
+ TrackEventLegacy::AddDebugAnnotations(&ctx, ##__VA_ARGS__); \
+ })
+
#define INTERNAL_TRACE_EVENT_ADD_SCOPED_WITH_FLOW(...) \
PERFETTO_INTERNAL_EVENT_NOOP(__VA_ARGS__)
#define INTERNAL_TRACE_EVENT_ADD_WITH_TIMESTAMP(...) \
diff --git a/src/trace_processor/containers/bit_vector_benchmark.cc b/src/trace_processor/containers/bit_vector_benchmark.cc
index 206bc5d..2deb904 100644
--- a/src/trace_processor/containers/bit_vector_benchmark.cc
+++ b/src/trace_processor/containers/bit_vector_benchmark.cc
@@ -143,6 +143,9 @@
static constexpr uint32_t kPoolSize = 1024 * 1024;
std::vector<uint32_t> row_pool(kPoolSize);
uint32_t set_bit_count = bv.GetNumBitsSet();
+ if (set_bit_count == 0)
+ return;
+
for (uint32_t i = 0; i < kPoolSize; ++i) {
row_pool[i] = rnd_engine() % set_bit_count;
}
diff --git a/src/trace_processor/importers/proto/heap_graph_tracker.cc b/src/trace_processor/importers/proto/heap_graph_tracker.cc
index f96cf6e..9eb166b 100644
--- a/src/trace_processor/importers/proto/heap_graph_tracker.cc
+++ b/src/trace_processor/importers/proto/heap_graph_tracker.cc
@@ -230,8 +230,7 @@
base::Optional<uint32_t> parent_id;
if (node.parent_id != 0)
parent_id = node_to_row_idx[node.parent_id];
- const uint32_t depth = node.depth - 1; // -1 because we do not have the
- // artificial root in the database.
+ const uint32_t depth = node.depth;
tables::ExperimentalFlamegraphNodesTable::Row alloc_row{
current_ts, current_upid, profile_type, depth,
diff --git a/src/trace_processor/tables/macros_benchmark.cc b/src/trace_processor/tables/macros_benchmark.cc
index 2e7bfbb..fec67ed 100644
--- a/src/trace_processor/tables/macros_benchmark.cc
+++ b/src/trace_processor/tables/macros_benchmark.cc
@@ -27,6 +27,7 @@
PERFETTO_TP_ROOT_TABLE(PARENT, C) \
C(uint32_t, root_sorted, Column::Flag::kSorted) \
C(uint32_t, root_non_null) \
+ C(uint32_t, root_non_null_2) \
C(base::Optional<uint32_t>, root_nullable)
PERFETTO_TP_TABLE(PERFETTO_TP_ROOT_TEST_TABLE);
@@ -200,6 +201,28 @@
}
BENCHMARK(BM_TableFilterRootNonNullEqMatchMany)->Apply(TableFilterArgs);
+static void BM_TableFilterRootMultipleNonNull(benchmark::State& state) {
+ StringPool pool;
+ RootTestTable root(&pool, nullptr);
+
+ uint32_t size = static_cast<uint32_t>(state.range(0));
+ uint32_t partitions = size / 512;
+
+ std::minstd_rand0 rnd_engine;
+ for (uint32_t i = 0; i < size; ++i) {
+ RootTestTable::Row row;
+ row.root_non_null = rnd_engine() % partitions;
+ row.root_non_null_2 = rnd_engine() % partitions;
+ root.Insert(row);
+ }
+
+ for (auto _ : state) {
+ benchmark::DoNotOptimize(root.Filter(
+ {root.root_non_null().lt(4), root.root_non_null_2().lt(10)}));
+ }
+}
+BENCHMARK(BM_TableFilterRootMultipleNonNull)->Apply(TableFilterArgs);
+
static void BM_TableFilterRootNullableEqMatchMany(benchmark::State& state) {
StringPool pool;
RootTestTable root(&pool, nullptr);
diff --git a/src/trace_processor/trace_storage.cc b/src/trace_processor/trace_storage.cc
index cbd01b5..74d22bf 100644
--- a/src/trace_processor/trace_storage.cc
+++ b/src/trace_processor/trace_storage.cc
@@ -147,6 +147,14 @@
&end_ns);
DbTableMaybeUpdateMinMax(instant_table_.ts(), &start_ns, &end_ns);
DbTableMaybeUpdateMinMax(android_log_table_.ts(), &start_ns, &end_ns);
+ DbTableMaybeUpdateMinMax(heap_graph_object_table_.graph_sample_ts(),
+ &start_ns, &end_ns);
+
+ if (heap_graph_object_table_.row_count() != 0) {
+ // TODO(fmayer): Remove this.
+ // Work around UI bug that the heap marker is not displayed.
+ end_ns += 50000000; // 50 ms
+ }
if (start_ns == std::numeric_limits<int64_t>::max()) {
return std::make_pair(0, 0);
diff --git a/src/tracing/api_integrationtest.cc b/src/tracing/api_integrationtest.cc
index c4edec1..63a682e 100644
--- a/src/tracing/api_integrationtest.cc
+++ b/src/tracing/api_integrationtest.cc
@@ -72,7 +72,8 @@
// Trace categories used in the tests.
PERFETTO_DEFINE_CATEGORIES(PERFETTO_CATEGORY(test),
PERFETTO_CATEGORY(foo),
- PERFETTO_CATEGORY(bar));
+ PERFETTO_CATEGORY(bar),
+ PERFETTO_CATEGORY(cat));
PERFETTO_TRACK_EVENT_STATIC_STORAGE();
// For testing interning of complex objects.
@@ -237,6 +238,16 @@
WaitableTestEvent on_stop;
};
+class MyDebugAnnotation : public perfetto::DebugAnnotation {
+ public:
+ ~MyDebugAnnotation() override = default;
+
+ void Add(
+ perfetto::protos::pbzero::DebugAnnotation* annotation) const override {
+ annotation->set_legacy_json_value(R"({"key": 123})");
+ }
+};
+
// -------------------------
// Declaration of test class
// -------------------------
@@ -398,9 +409,16 @@
case perfetto::protos::gen::TrackEvent::TYPE_INSTANT:
slice += "I";
break;
- default:
- case perfetto::protos::gen::TrackEvent::TYPE_UNSPECIFIED:
+ case perfetto::protos::gen::TrackEvent::TYPE_UNSPECIFIED: {
+ EXPECT_TRUE(track_event.has_legacy_event());
EXPECT_FALSE(track_event.type());
+ auto legacy_event = track_event.legacy_event();
+ slice += "Legacy_" +
+ std::string(1, static_cast<char>(legacy_event.phase()));
+ break;
+ }
+ default:
+ ADD_FAILURE();
}
if (!track_event.category_iids().empty())
slice += ":" + categories[track_event.category_iids()[0]];
@@ -1455,23 +1473,15 @@
ds_cfg->set_name("track_event");
ds_cfg->set_legacy_config("test");
- class MyDebugAnnotation : public perfetto::DebugAnnotation {
- public:
- ~MyDebugAnnotation() override = default;
-
- void Add(
- perfetto::protos::pbzero::DebugAnnotation* annotation) const override {
- annotation->set_legacy_json_value(R"({"key": 123})");
- }
- };
-
// Create a new trace session.
auto* tracing_session = NewTrace(cfg);
tracing_session->get()->StartBlocking();
+ std::unique_ptr<MyDebugAnnotation> owned_annotation(new MyDebugAnnotation());
+
TRACE_EVENT_BEGIN("test", "E", "custom_arg", MyDebugAnnotation());
TRACE_EVENT_BEGIN("test", "E", "normal_arg", "x", "custom_arg",
- MyDebugAnnotation());
+ std::move(owned_annotation));
perfetto::TrackEvent::Flush();
tracing_session->get()->StopBlocking();
@@ -1952,7 +1962,19 @@
// TODO(skyostil): For now we just test that all variants of legacy trace
// points compile. Test actual functionality when implemented.
+ // 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");
+
+ // Create a new trace session.
+ auto* tracing_session = NewTrace(cfg);
+ tracing_session->get()->StartBlocking();
+
// Basic events.
+ TRACE_EVENT_INSTANT0("cat", "LegacyEvent", TRACE_EVENT_SCOPE_GLOBAL);
TRACE_EVENT_BEGIN1("cat", "LegacyEvent", "arg", 123);
TRACE_EVENT_END2("cat", "LegacyEvent", "arg", "string", "arg2", 0.123f);
@@ -1972,10 +1994,79 @@
"cat", std::string("LegacyWithIdTidAndTimestamp").c_str(), 1, 2, 3);
// Event with id.
- TRACE_COUNTER_ID1("cat", "LegacyCounter", 1234, 9000);
+ TRACE_COUNTER1("cat", "LegacyCounter", 1234);
+ TRACE_COUNTER_ID1("cat", "LegacyCounterWithId", 1234, 9000);
// Metadata event.
TRACE_EVENT_METADATA1("cat", "LegacyMetadata", "obsolete", true);
+
+ perfetto::TrackEvent::Flush();
+ tracing_session->get()->StopBlocking();
+ auto slices = ReadSlicesFromTrace(tracing_session->get());
+ EXPECT_THAT(
+ slices,
+ ElementsAre("I:cat.LegacyEvent", "B:cat.LegacyEvent(arg=(int)123)",
+ "E.LegacyEvent(arg=(string)string,arg2=(double)0.123)",
+ "B:cat.ScopedLegacyEvent", "E",
+ "Legacy_C:cat.LegacyCounter(value=(int)1234)"));
+}
+
+TEST_F(PerfettoApiTest, LegacyTraceEventsWithCustomAnnotation) {
+ // 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");
+
+ // Create a new trace session.
+ auto* tracing_session = NewTrace(cfg);
+ tracing_session->get()->StartBlocking();
+
+ MyDebugAnnotation annotation;
+ TRACE_EVENT_BEGIN1("cat", "LegacyEvent", "arg", annotation);
+
+ std::unique_ptr<MyDebugAnnotation> owned_annotation(new MyDebugAnnotation());
+ TRACE_EVENT_BEGIN1("cat", "LegacyEvent", "arg", std::move(owned_annotation));
+
+ perfetto::TrackEvent::Flush();
+ tracing_session->get()->StopBlocking();
+ auto slices = ReadSlicesFromTrace(tracing_session->get());
+ EXPECT_THAT(slices,
+ ElementsAre("B:cat.LegacyEvent(arg=(json){\"key\": 123})",
+ "B:cat.LegacyEvent(arg=(json){\"key\": 123})"));
+}
+
+TEST_F(PerfettoApiTest, LegacyTraceEventsWithConcurrentSessions) {
+ // Make sure that a uniquely owned debug annotation can be written into
+ // multiple concurrent tracing sessions.
+
+ // 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");
+
+ auto* tracing_session = NewTrace(cfg);
+ tracing_session->get()->StartBlocking();
+
+ auto* tracing_session2 = NewTrace(cfg);
+ tracing_session2->get()->StartBlocking();
+
+ std::unique_ptr<MyDebugAnnotation> owned_annotation(new MyDebugAnnotation());
+ TRACE_EVENT_BEGIN1("cat", "LegacyEvent", "arg", std::move(owned_annotation));
+
+ perfetto::TrackEvent::Flush();
+ tracing_session->get()->StopBlocking();
+ auto slices = ReadSlicesFromTrace(tracing_session->get());
+ EXPECT_THAT(slices,
+ ElementsAre("B:cat.LegacyEvent(arg=(json){\"key\": 123})"));
+
+ tracing_session2->get()->StopBlocking();
+ slices = ReadSlicesFromTrace(tracing_session2->get());
+ EXPECT_THAT(slices,
+ ElementsAre("B:cat.LegacyEvent(arg=(json){\"key\": 123})"));
}
} // namespace
diff --git a/src/tracing/internal/track_event_internal.cc b/src/tracing/internal/track_event_internal.cc
index 9a84aeb..4c0c86b 100644
--- a/src/tracing/internal/track_event_internal.cc
+++ b/src/tracing/internal/track_event_internal.cc
@@ -202,7 +202,8 @@
EventContext ctx(std::move(packet), incr_state);
auto track_event = ctx.event();
- track_event->set_type(type);
+ if (type != protos::pbzero::TrackEvent::TYPE_UNSPECIFIED)
+ track_event->set_type(type);
// We assume that |category| and |name| point to strings with static lifetime.
// This means we can use their addresses as interning keys.
diff --git a/src/tracing/test/tracing_module.cc b/src/tracing/test/tracing_module.cc
index 7c10d4e..d4fef2e 100644
--- a/src/tracing/test/tracing_module.cc
+++ b/src/tracing/test/tracing_module.cc
@@ -89,4 +89,18 @@
puts("Hello");
}
+void FunctionWithOneLegacyEvent() {
+ TRACE_EVENT_BEGIN("cat1", "LegacyEventWithArgs", "arg1", 42, "arg2", .5f);
+ // Simulates the non-tracing work of this function, which should take priority
+ // over the above trace event in terms of instruction scheduling.
+ puts("Hello");
+}
+
+void FunctionWithOneScopedLegacyEvent() {
+ TRACE_EVENT("cat1", "ScopedLegacyEventWithArgs", "arg1", 42, "arg2", .5f);
+ // Simulates the non-tracing work of this function, which should take priority
+ // over the above trace event in terms of instruction scheduling.
+ puts("Hello");
+}
+
} // namespace tracing_module
diff --git a/src/tracing/test/tracing_module.h b/src/tracing/test/tracing_module.h
index c005a6f..7ed9364 100644
--- a/src/tracing/test/tracing_module.h
+++ b/src/tracing/test/tracing_module.h
@@ -39,6 +39,10 @@
void FunctionWithOneTrackEventWithDebugAnnotations();
void FunctionWithOneTrackEventWithCustomTrack();
+// Legacy events.
+void FunctionWithOneLegacyEvent();
+void FunctionWithOneScopedLegacyEvent();
+
} // namespace tracing_module
#endif // SRC_TRACING_TEST_TRACING_MODULE_H_
diff --git a/src/tracing/test/tracing_module_categories.h b/src/tracing/test/tracing_module_categories.h
index f776894..b492db8 100644
--- a/src/tracing/test/tracing_module_categories.h
+++ b/src/tracing/test/tracing_module_categories.h
@@ -23,6 +23,7 @@
// categories can be written to the same trace writer.
#define PERFETTO_TRACK_EVENT_NAMESPACE tracing_module
+#define PERFETTO_ENABLE_LEGACY_TRACE_EVENTS 1
#include "perfetto/tracing.h"
diff --git a/test/trace_processor/heap_graph_flamegraph_system-server-heap-graph.out b/test/trace_processor/heap_graph_flamegraph_system-server-heap-graph.out
index 102c246..8f822d1 100644
--- a/test/trace_processor/heap_graph_flamegraph_system-server-heap-graph.out
+++ b/test/trace_processor/heap_graph_flamegraph_system-server-heap-graph.out
@@ -1,11 +1,11 @@
"id","depth","name","map_name","count","cumulative_count","size","cumulative_size","parent_id"
-0,4294967295,"java.lang.Class<boolean>","JAVA",2,4,240,276,"[NULL]"
-1,0,"java.lang.Object[]","JAVA",1,1,12,12,0
-2,0,"java.lang.String","JAVA",1,1,24,24,0
-3,4294967295,"java.lang.Class<byte>","JAVA",3,4,360,384,"[NULL]"
-4,0,"java.lang.String","JAVA",1,1,24,24,3
-5,4294967295,"java.lang.Class<short>","JAVA",2,3,240,264,"[NULL]"
-6,0,"java.lang.String","JAVA",1,1,24,24,5
-7,4294967295,"java.lang.Class<char>","JAVA",2,3,240,264,"[NULL]"
-8,0,"java.lang.String","JAVA",1,1,24,24,7
-9,4294967295,"java.lang.Class<int>","JAVA",2,3,240,264,"[NULL]"
+0,0,"java.lang.Class<boolean>","JAVA",2,4,240,276,"[NULL]"
+1,1,"java.lang.Object[]","JAVA",1,1,12,12,0
+2,1,"java.lang.String","JAVA",1,1,24,24,0
+3,0,"java.lang.Class<byte>","JAVA",3,4,360,384,"[NULL]"
+4,1,"java.lang.String","JAVA",1,1,24,24,3
+5,0,"java.lang.Class<short>","JAVA",2,3,240,264,"[NULL]"
+6,1,"java.lang.String","JAVA",1,1,24,24,5
+7,0,"java.lang.Class<char>","JAVA",2,3,240,264,"[NULL]"
+8,1,"java.lang.String","JAVA",1,1,24,24,7
+9,0,"java.lang.Class<int>","JAVA",2,3,240,264,"[NULL]"
diff --git a/ui/src/common/actions.ts b/ui/src/common/actions.ts
index c5f7f63..8e43ca5 100644
--- a/ui/src/common/actions.ts
+++ b/ui/src/common/actions.ts
@@ -426,18 +426,26 @@
},
selectHeapProfile(
- state: StateDraft, args: {id: number, upid: number, ts: number}): void {
- state.currentSelection =
- {kind: 'HEAP_PROFILE', id: args.id, upid: args.upid, ts: args.ts};
+ state: StateDraft,
+ args: {id: number, upid: number, ts: number, type: string}): void {
+ state.currentSelection = {
+ kind: 'HEAP_PROFILE',
+ id: args.id,
+ upid: args.upid,
+ ts: args.ts,
+ type: args.type
+ };
},
showHeapProfileFlamegraph(
- state: StateDraft, args: {id: number, upid: number, ts: number}): void {
+ state: StateDraft,
+ args: {id: number, upid: number, ts: number, type: string}): void {
state.currentHeapProfileFlamegraph = {
kind: 'HEAP_PROFILE_FLAMEGRAPH',
id: args.id,
upid: args.upid,
ts: args.ts,
+ type: args.type,
};
},
diff --git a/ui/src/common/state.ts b/ui/src/common/state.ts
index 2b6d2b2..b7f2f40 100644
--- a/ui/src/common/state.ts
+++ b/ui/src/common/state.ts
@@ -163,6 +163,7 @@
id: number;
upid: number;
ts: number;
+ type: string;
}
export interface HeapProfileFlamegraph {
@@ -170,6 +171,7 @@
id: number;
upid: number;
ts: number;
+ type: string;
expandedCallsite?: CallsiteInfo;
viewingOption?: string;
}
diff --git a/ui/src/controller/heap_profile_controller.ts b/ui/src/controller/heap_profile_controller.ts
index eadb704..2f5d5f7 100644
--- a/ui/src/controller/heap_profile_controller.ts
+++ b/ui/src/controller/heap_profile_controller.ts
@@ -85,7 +85,8 @@
selectedHeapProfile.viewingOption :
DEFAULT_VIEWING_OPTION,
selection.ts,
- selectedHeapProfile.upid)
+ selectedHeapProfile.upid,
+ selectedHeapProfile.type)
.then(flamegraphData => {
if (flamegraphData !== undefined && selection &&
selection.kind === selectedHeapProfile.kind &&
@@ -119,6 +120,7 @@
id: heapProfile.id,
upid: heapProfile.upid,
ts: heapProfile.ts,
+ type: heapProfile.type,
expandedCallsite: heapProfile.expandedCallsite,
viewingOption: heapProfile.viewingOption
};
@@ -130,6 +132,7 @@
(this.lastSelectedHeapProfile !== undefined &&
(this.lastSelectedHeapProfile.id !== selection.id ||
this.lastSelectedHeapProfile.ts !== selection.ts ||
+ this.lastSelectedHeapProfile.type !== selection.type ||
this.lastSelectedHeapProfile.upid !== selection.upid ||
this.lastSelectedHeapProfile.viewingOption !==
selection.viewingOption ||
@@ -151,8 +154,8 @@
async getFlamegraphData(
- baseKey: string, viewingOption: string, ts: number,
- upid: number): Promise<CallsiteInfo[]> {
+ baseKey: string, viewingOption: string, ts: number, upid: number,
+ type: string): Promise<CallsiteInfo[]> {
let currentData: CallsiteInfo[];
const key = `${baseKey}-${viewingOption}`;
if (this.flamegraphDatasets.has(key)) {
@@ -163,7 +166,7 @@
// Collecting data for drawing flamegraph for selected heap profile.
// Data needs to be in following format:
// id, name, parent_id, depth, total_size
- const tableName = await this.prepareViewsAndTables(ts, upid);
+ const tableName = await this.prepareViewsAndTables(ts, upid, type);
currentData =
await this.getFlamegraphDataFromTables(tableName, viewingOption);
this.flamegraphDatasets.set(key, currentData);
@@ -201,7 +204,7 @@
}
const callsites = await this.args.engine.query(
- `SELECT id, name, parent_id, depth, cumulative_size,
+ `SELECT id, name, IFNULL(parent_id, -1), depth, cumulative_size,
cumulative_alloc_size, cumulative_count,
cumulative_alloc_count, map_name, size from ${tableName} ${orderBy}`);
@@ -227,7 +230,7 @@
return flamegraphData;
}
- private async prepareViewsAndTables(ts: number, upid: number):
+ private async prepareViewsAndTables(ts: number, upid: number, type: string):
Promise<string> {
// Creating unique names for views so we can reuse and not delete them
// for each marker.
@@ -239,7 +242,7 @@
select id, name, map_name, parent_id, depth, cumulative_size,
cumulative_alloc_size, cumulative_count, cumulative_alloc_count,
size, alloc_size, count, alloc_count
- from experimental_flamegraph(${ts}, ${upid}, 'native')`);
+ from experimental_flamegraph(${ts}, ${upid}, '${type}')`);
return tableNameGroupedCallsitesForFlamegraph;
}
diff --git a/ui/src/controller/trace_controller.ts b/ui/src/controller/trace_controller.ts
index c5b6130..76acaa9 100644
--- a/ui/src/controller/trace_controller.ts
+++ b/ui/src/controller/trace_controller.ts
@@ -407,7 +407,9 @@
}
const heapProfiles = await engine.query(`
- select distinct(upid) from heap_profile_allocation`);
+ select distinct(upid) from heap_profile_allocation
+ union
+ select distinct(upid) from heap_graph_object`);
const heapUpids: Set<number> = new Set();
for (let i = 0; i < heapProfiles.numRecords; i++) {
diff --git a/ui/src/tracks/heap_profile/common.ts b/ui/src/tracks/heap_profile/common.ts
index fc9da62..0a8a16d 100644
--- a/ui/src/tracks/heap_profile/common.ts
+++ b/ui/src/tracks/heap_profile/common.ts
@@ -17,6 +17,7 @@
export interface Data extends TrackData {
tsStarts: Float64Array;
+ types: string[];
}
export interface Config {
diff --git a/ui/src/tracks/heap_profile/controller.ts b/ui/src/tracks/heap_profile/controller.ts
index 61ad335..bab0b15 100644
--- a/ui/src/tracks/heap_profile/controller.ts
+++ b/ui/src/tracks/heap_profile/controller.ts
@@ -28,11 +28,23 @@
async onBoundsChange(start: number, end: number, resolution: number):
Promise<Data> {
if (this.config.upid === undefined) {
- return {start, end, resolution, length: 0, tsStarts: new Float64Array()};
+ return {
+ start,
+ end,
+ resolution,
+ length: 0,
+ tsStarts: new Float64Array(),
+ types: new Array<string>()
+ };
}
const result = await this.query(`
- select distinct(ts) from heap_profile_allocation where upid = ${
- this.config.upid}`);
+ select * from
+ (select distinct(ts) as ts, 'native' as type from heap_profile_allocation
+ where upid = ${this.config.upid}
+ union
+ select distinct(graph_sample_ts) as ts, 'graph' as type from
+ heap_graph_object
+ where upid = ${this.config.upid}) order by ts`);
const numRows = +result.numRecords;
const data: Data = {
start,
@@ -40,10 +52,12 @@
resolution,
length: numRows,
tsStarts: new Float64Array(numRows),
+ types: new Array<string>(numRows),
};
for (let row = 0; row < numRows; row++) {
data.tsStarts[row] = +result.columns[0].longValues![row];
+ data.types[row] = result.columns[1].stringValues![row];
}
return data;
diff --git a/ui/src/tracks/heap_profile/frontend.ts b/ui/src/tracks/heap_profile/frontend.ts
index 8eaba5e..86d177e 100644
--- a/ui/src/tracks/heap_profile/frontend.ts
+++ b/ui/src/tracks/heap_profile/frontend.ts
@@ -118,10 +118,11 @@
if (index !== -1) {
const ts = data.tsStarts[index];
+ const type = data.types[index];
globals.dispatch(Actions.showHeapProfileFlamegraph(
- {id: index, upid: this.config.upid, ts}));
- globals.makeSelection(
- Actions.selectHeapProfile({id: index, upid: this.config.upid, ts}));
+ {id: index, upid: this.config.upid, ts, type}));
+ globals.makeSelection(Actions.selectHeapProfile(
+ {id: index, upid: this.config.upid, ts, type}));
return true;
}
return false;