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