1 /*
2  * Copyright (C) 2018 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 <inttypes.h>
18 
19 #include <array>
20 #include <atomic>
21 
22 #include "perfetto/base/logging.h"
23 #include "perfetto/public/consumer_api.h"
24 
25 #include "perfetto/config/trace_config.pb.h"
26 #include "perfetto/trace/trace.pb.h"
27 
28 using namespace perfetto::consumer;
29 
30 namespace {
31 
32 int g_pointer = 0;
33 
GetConfig(uint32_t duration_ms)34 std::string GetConfig(uint32_t duration_ms) {
35   perfetto::protos::TraceConfig trace_config;
36   trace_config.set_duration_ms(duration_ms);
37   trace_config.add_buffers()->set_size_kb(4096);
38   trace_config.set_deferred_start(true);
39   auto* ds_config = trace_config.add_data_sources()->mutable_config();
40   ds_config->set_name("linux.ftrace");
41   ds_config->mutable_ftrace_config()->add_ftrace_events("sched_switch");
42   ds_config->mutable_ftrace_config()->add_ftrace_events(
43       "mm_filemap_add_to_page_cache");
44   ds_config->mutable_ftrace_config()->add_ftrace_events(
45       "mm_filemap_delete_from_page_cache");
46   ds_config->set_target_buffer(0);
47   return trace_config.SerializeAsString();
48 }
49 
DumpTrace(TraceBuffer buf)50 void DumpTrace(TraceBuffer buf) {
51   perfetto::protos::Trace trace;
52   bool parsed = trace.ParseFromArray(buf.begin, static_cast<int>(buf.size));
53   if (!parsed) {
54     PERFETTO_ELOG("Failed to parse the trace");
55     return;
56   }
57 
58   PERFETTO_LOG("Parsing %d trace packets", trace.packet_size());
59   int num_filemap_events = 0;
60   for (const auto& packet : trace.packet()) {
61     if (packet.has_ftrace_events()) {
62       const auto& bundle = packet.ftrace_events();
63       for (const auto& ftrace : bundle.event()) {
64         if (ftrace.has_mm_filemap_add_to_page_cache()) {
65           num_filemap_events++;
66           // const auto& evt = ftrace.mm_filemap_add_to_page_cache();
67           // PERFETTO_LOG(
68           //     "mm_filemap_add_to_page_cache pfn=%llu, dev=%llu, ino=%llu",
69           //     evt.pfn(), evt.s_dev(), evt.i_ino());
70         }
71         if (ftrace.has_mm_filemap_delete_from_page_cache()) {
72           num_filemap_events++;
73           // const auto& evt = ftrace.mm_filemap_delete_from_page_cache();
74           // PERFETTO_LOG(
75           //     "mm_filemap_delete_from_page_cache pfn=%llu, dev=%llu,
76           //     ino=%llu", evt.pfn(), evt.s_dev(), evt.i_ino());
77         }
78       }
79     }
80   }
81   PERFETTO_LOG("Got %d mm_filemap events", num_filemap_events);
82 }
83 
OnStateChanged(Handle handle,State state,void * ptr)84 void OnStateChanged(Handle handle, State state, void* ptr) {
85   PERFETTO_LOG("Callback: handle=%" PRId64 " state=%d", handle,
86                static_cast<int>(state));
87   PERFETTO_CHECK(ptr == &g_pointer);
88 }
89 
TestSingle()90 void TestSingle() {
91   std::string cfg = GetConfig(1000);
92   auto handle = Create(cfg.data(), cfg.size(), &OnStateChanged, &g_pointer);
93   PERFETTO_ILOG("Starting, handle=%" PRId64 " state=%d", handle,
94                 static_cast<int>(PollState(handle)));
95   usleep(100000);
96   StartTracing(handle);
97   // Wait for either completion or error.
98   while (static_cast<int>(PollState(handle)) > 0 &&
99          PollState(handle) != State::kTraceEnded) {
100     usleep(10000);
101   }
102 
103   if (PollState(handle) == State::kTraceEnded) {
104     auto buf = ReadTrace(handle);
105     DumpTrace(buf);
106   } else {
107     PERFETTO_ELOG("Trace failed");
108   }
109 
110   PERFETTO_ILOG("Destroying");
111   Destroy(handle);
112 }
113 
TestMany()114 void TestMany() {
115   std::string cfg = GetConfig(8000);
116 
117   std::array<Handle, 5> handles{};
118   for (size_t i = 0; i < handles.size(); i++) {
119     auto handle = Create(cfg.data(), cfg.size(), &OnStateChanged, &g_pointer);
120     handles[i] = handle;
121     PERFETTO_ILOG("Creating handle=%" PRId64 " state=%d", handle,
122                   static_cast<int>(PollState(handle)));
123   }
124 
125   // Wait that all sessions are connected.
126   for (bool all_connected = false; !all_connected;) {
127     all_connected = true;
128     for (size_t i = 0; i < handles.size(); i++) {
129       if (PollState(handles[i]) != State::kConfigured) {
130         all_connected = false;
131       }
132     }
133     usleep(10000);
134   }
135 
136   // Start only 3 out of 5 sessions, scattering them with 1 second delay.
137   for (size_t i = 0; i < handles.size(); i++) {
138     if (i % 2 == 0) {
139       StartTracing(handles[i]);
140       sleep(1);
141     }
142   }
143 
144   // Wait until all sessions are complete.
145   for (int num_complete = 0; num_complete != 3;) {
146     num_complete = 0;
147     for (size_t i = 0; i < handles.size(); i++) {
148       if (PollState(handles[i]) == State::kTraceEnded) {
149         num_complete++;
150       }
151     }
152     usleep(10000);
153   }
154 
155   // Read the trace buffers.
156   for (size_t i = 0; i < handles.size(); i++) {
157     auto buf = ReadTrace(handles[i]);
158     PERFETTO_ILOG("ReadTrace[%zu] buf=%p %zu", i, static_cast<void*>(buf.begin),
159                   buf.size);
160     if (i % 2 == 0) {
161       if (!buf.begin) {
162         PERFETTO_ELOG("FAIL: the buffer was supposed to be not empty");
163       } else {
164         DumpTrace(buf);
165       }
166     }
167   }
168 
169   PERFETTO_ILOG("Destroying");
170   for (size_t i = 0; i < handles.size(); i++)
171     Destroy(handles[i]);
172 }
173 }  // namespace
174 
main()175 int main() {
176   PERFETTO_LOG("Testing single trace");
177   PERFETTO_LOG("=============================================================");
178   TestSingle();
179   PERFETTO_LOG("=============================================================");
180 
181   PERFETTO_LOG("\n");
182 
183   PERFETTO_LOG("\n");
184   PERFETTO_LOG("Testing concurrent traces");
185   PERFETTO_LOG("=============================================================");
186   TestMany();
187   PERFETTO_LOG("=============================================================");
188 
189   return 0;
190 }
191