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