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