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