1 /*
2 * Copyright (C) 2021 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include "src/trace_processor/importers/proto/perf_sample_tracker.h"
18
19 #include "perfetto/base/logging.h"
20 #include "src/trace_processor/importers/common/track_tracker.h"
21 #include "test/gtest_and_gmock.h"
22
23 #include "protos/perfetto/common/perf_events.gen.h"
24 #include "protos/perfetto/trace/profiling/profile_packet.gen.h"
25 #include "protos/perfetto/trace/profiling/profile_packet.pbzero.h"
26 #include "protos/perfetto/trace/trace_packet_defaults.gen.h"
27 #include "protos/perfetto/trace/trace_packet_defaults.pbzero.h"
28
29 namespace perfetto {
30 namespace trace_processor {
31 namespace {
32
33 class PerfSampleTrackerTest : public ::testing::Test {
34 public:
PerfSampleTrackerTest()35 PerfSampleTrackerTest() {
36 context.storage.reset(new TraceStorage());
37 context.track_tracker.reset(new TrackTracker(&context));
38 context.perf_sample_tracker.reset(new PerfSampleTracker(&context));
39 }
40
41 protected:
42 TraceProcessorContext context;
43 };
44
TEST_F(PerfSampleTrackerTest,PerCpuCounterTracks)45 TEST_F(PerfSampleTrackerTest, PerCpuCounterTracks) {
46 uint32_t seq_id = 42;
47 uint32_t cpu0 = 0;
48 uint32_t cpu1 = 1;
49
50 auto stream = context.perf_sample_tracker->GetSamplingStreamInfo(
51 seq_id, cpu0, /*nullable_defaults=*/nullptr);
52 auto stream2 = context.perf_sample_tracker->GetSamplingStreamInfo(
53 seq_id, cpu1, /*nullable_defaults=*/nullptr);
54
55 // same session, different counter tracks
56 EXPECT_EQ(stream.perf_session_id, stream2.perf_session_id);
57 EXPECT_NE(stream.timebase_track_id, stream2.timebase_track_id);
58
59 // re-querying one of the existing streams gives the same ids
60 auto stream3 = context.perf_sample_tracker->GetSamplingStreamInfo(
61 seq_id, cpu1, /*nullable_defaults=*/nullptr);
62
63 EXPECT_EQ(stream2.perf_session_id, stream3.perf_session_id);
64 EXPECT_EQ(stream2.timebase_track_id, stream3.timebase_track_id);
65 }
66
TEST_F(PerfSampleTrackerTest,TimebaseTrackName_Counter)67 TEST_F(PerfSampleTrackerTest, TimebaseTrackName_Counter) {
68 uint32_t seq_id = 42;
69 uint32_t cpu0 = 0;
70
71 protos::gen::TracePacketDefaults defaults;
72 auto* perf_defaults = defaults.mutable_perf_sample_defaults();
73 perf_defaults->mutable_timebase()->set_frequency(100);
74 perf_defaults->mutable_timebase()->set_counter(
75 protos::gen::PerfEvents::SW_PAGE_FAULTS);
76 auto defaults_pb = defaults.SerializeAsString();
77 protos::pbzero::TracePacketDefaults::Decoder defaults_decoder(defaults_pb);
78
79 auto stream = context.perf_sample_tracker->GetSamplingStreamInfo(
80 seq_id, cpu0, &defaults_decoder);
81
82 TrackId track_id = stream.timebase_track_id;
83 const auto& track_table = context.storage->perf_counter_track_table();
84 auto row_id = track_table.id().IndexOf(track_id);
85
86 // track exists and looks sensible
87 ASSERT_TRUE(row_id.has_value());
88 EXPECT_EQ(track_table.perf_session_id()[*row_id], stream.perf_session_id);
89 EXPECT_EQ(track_table.cpu()[*row_id], cpu0);
90 EXPECT_TRUE(track_table.is_timebase()[*row_id]);
91
92 // Name derived from the timebase.
93 std::string track_name =
94 context.storage->GetString(track_table.name()[*row_id]).ToStdString();
95 ASSERT_EQ(track_name, "page-faults");
96 }
97
TEST_F(PerfSampleTrackerTest,TimebaseTrackName_Tracepoint)98 TEST_F(PerfSampleTrackerTest, TimebaseTrackName_Tracepoint) {
99 uint32_t seq_id = 42;
100 uint32_t cpu0 = 0;
101
102 protos::gen::TracePacketDefaults defaults;
103 auto* perf_defaults = defaults.mutable_perf_sample_defaults();
104 perf_defaults->mutable_timebase()->set_frequency(100);
105 perf_defaults->mutable_timebase()->mutable_tracepoint()->set_name(
106 "sched:sched_switch");
107 auto defaults_pb = defaults.SerializeAsString();
108 protos::pbzero::TracePacketDefaults::Decoder defaults_decoder(defaults_pb);
109
110 auto stream = context.perf_sample_tracker->GetSamplingStreamInfo(
111 seq_id, cpu0, &defaults_decoder);
112
113 TrackId track_id = stream.timebase_track_id;
114 const auto& track_table = context.storage->perf_counter_track_table();
115 auto row_id = track_table.id().IndexOf(track_id);
116
117 // track exists and looks sensible
118 ASSERT_TRUE(row_id.has_value());
119 EXPECT_EQ(track_table.perf_session_id()[*row_id], stream.perf_session_id);
120 EXPECT_EQ(track_table.cpu()[*row_id], cpu0);
121 EXPECT_TRUE(track_table.is_timebase()[*row_id]);
122
123 // Name derived from the timebase.
124 std::string track_name =
125 context.storage->GetString(track_table.name()[*row_id]).ToStdString();
126 ASSERT_EQ(track_name, "sched:sched_switch");
127 }
128
TEST_F(PerfSampleTrackerTest,UnknownCounterTreatedAsCpuClock)129 TEST_F(PerfSampleTrackerTest, UnknownCounterTreatedAsCpuClock) {
130 uint32_t seq_id = 42;
131 uint32_t cpu0 = 0;
132
133 auto stream = context.perf_sample_tracker->GetSamplingStreamInfo(
134 seq_id, cpu0, /*nullable_defaults=*/nullptr);
135
136 TrackId track_id = stream.timebase_track_id;
137 const auto& track_table = context.storage->perf_counter_track_table();
138 auto row_id = track_table.id().IndexOf(track_id);
139
140 // track exists and looks sensible
141 ASSERT_TRUE(row_id.has_value());
142 EXPECT_EQ(track_table.perf_session_id()[*row_id], stream.perf_session_id);
143 EXPECT_EQ(track_table.cpu()[*row_id], cpu0);
144 EXPECT_TRUE(track_table.is_timebase()[*row_id]);
145
146 // If the trace doesn't have a PerfSampleDefaults describing the timebase
147 // counter, we assume cpu-clock.
148 std::string track_name =
149 context.storage->GetString(track_table.name()[*row_id]).ToStdString();
150 ASSERT_EQ(track_name, "cpu-clock");
151 }
152
153 } // namespace
154 } // namespace trace_processor
155 } // namespace perfetto
156