• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2023 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 <condition_variable>
18 #include <mutex>
19 #include <thread>
20 
21 #include "perfetto/public/abi/data_source_abi.h"
22 #include "perfetto/public/abi/pb_decoder_abi.h"
23 #include "perfetto/public/data_source.h"
24 #include "perfetto/public/producer.h"
25 #include "perfetto/public/protos/trace/test_event.pzc.h"
26 #include "perfetto/public/protos/trace/trace.pzc.h"
27 #include "perfetto/public/protos/trace/trace_packet.pzc.h"
28 
29 #include "test/gtest_and_gmock.h"
30 
31 #include "src/shared_lib/reset_for_testing.h"
32 #include "src/shared_lib/test/utils.h"
33 
34 // Tests for the perfetto shared library.
35 
36 namespace {
37 
38 using ::perfetto::shlib::test_utils::FieldView;
39 using ::perfetto::shlib::test_utils::IdFieldView;
40 using ::perfetto::shlib::test_utils::MsgField;
41 using ::perfetto::shlib::test_utils::PbField;
42 using ::perfetto::shlib::test_utils::StringField;
43 using ::perfetto::shlib::test_utils::TracingSession;
44 using ::testing::_;
45 using ::testing::DoAll;
46 using ::testing::ElementsAre;
47 using ::testing::InSequence;
48 using ::testing::NiceMock;
49 using ::testing::Return;
50 using ::testing::SaveArg;
51 
52 constexpr char kDataSourceName1[] = "dev.perfetto.example_data_source";
53 struct PerfettoDs data_source_1 = PERFETTO_DS_INIT();
54 
55 constexpr char kDataSourceName2[] = "dev.perfetto.example_data_source2";
56 struct PerfettoDs data_source_2 = PERFETTO_DS_INIT();
57 void* const kDataSource2UserArg = reinterpret_cast<void*>(0x555);
58 
59 class MockDs2Callbacks : testing::Mock {
60  public:
61   MOCK_METHOD(void*,
62               OnSetup,
63               (PerfettoDsInstanceIndex inst_id,
64                void* ds_config,
65                size_t ds_config_size,
66                void* user_arg));
67   MOCK_METHOD(void,
68               OnStart,
69               (PerfettoDsInstanceIndex inst_id,
70                void* user_arg,
71                void* inst_ctx));
72   MOCK_METHOD(void,
73               OnStop,
74               (PerfettoDsInstanceIndex inst_id,
75                void* user_arg,
76                void* inst_ctx,
77                struct PerfettoDsOnStopArgs* args));
78   MOCK_METHOD(void*,
79               OnCreateTls,
80               (PerfettoDsInstanceIndex inst_id,
81                struct PerfettoDsTracerImpl* tracer,
82                void* user_arg));
83   MOCK_METHOD(void, OnDeleteTls, (void*));
84   MOCK_METHOD(void*,
85               OnCreateIncr,
86               (PerfettoDsInstanceIndex inst_id,
87                struct PerfettoDsTracerImpl* tracer,
88                void* user_arg));
89   MOCK_METHOD(void, OnDeleteIncr, (void*));
90 };
91 
92 class Notification {
93  public:
94   Notification() = default;
Notify()95   void Notify() {
96     std::unique_lock<std::mutex> lock(m_);
97     notified_ = true;
98     cv_.notify_one();
99   }
WaitForNotification()100   bool WaitForNotification() {
101     std::unique_lock<std::mutex> lock(m_);
102     cv_.wait(lock, [this] { return notified_; });
103     return notified_;
104   }
Notified()105   bool Notified() {
106     std::unique_lock<std::mutex> lock(m_);
107     return notified_;
108   }
109 
110  private:
111   std::mutex m_;
112   std::condition_variable cv_;
113   bool notified_ = false;
114 };
115 
116 class SharedLibDataSourceTest : public testing::Test {
117  protected:
SetUp()118   void SetUp() override {
119     struct PerfettoProducerInitArgs args = {0};
120     args.backends = PERFETTO_BACKEND_IN_PROCESS;
121     PerfettoProducerInit(args);
122     PerfettoDsRegister(&data_source_1, kDataSourceName1,
123                        PerfettoDsNoCallbacks());
124     RegisterDataSource2();
125   }
126 
TearDown()127   void TearDown() override {
128     perfetto::shlib::ResetForTesting();
129     data_source_1.enabled = &perfetto_atomic_false;
130     perfetto::shlib::DsImplDestroy(data_source_1.impl);
131     data_source_1.impl = nullptr;
132     data_source_2.enabled = &perfetto_atomic_false;
133     perfetto::shlib::DsImplDestroy(data_source_2.impl);
134     data_source_2.impl = nullptr;
135   }
136 
137   struct Ds2CustomState {
138     void* actual;
139     SharedLibDataSourceTest* thiz;
140   };
141 
RegisterDataSource2()142   void RegisterDataSource2() {
143     static struct PerfettoDsCallbacks callbacks = {};
144     callbacks.on_setup_cb = [](PerfettoDsInstanceIndex inst_id, void* ds_config,
145                                size_t ds_config_size, void* user_arg) -> void* {
146       auto* thiz = static_cast<SharedLibDataSourceTest*>(user_arg);
147       return thiz->ds2_callbacks_.OnSetup(inst_id, ds_config, ds_config_size,
148                                           thiz->ds2_user_arg_);
149     };
150     callbacks.on_start_cb = [](PerfettoDsInstanceIndex inst_id, void* user_arg,
151                                void* inst_ctx) -> void {
152       auto* thiz = static_cast<SharedLibDataSourceTest*>(user_arg);
153       return thiz->ds2_callbacks_.OnStart(inst_id, thiz->ds2_user_arg_,
154                                           inst_ctx);
155     };
156     callbacks.on_stop_cb = [](PerfettoDsInstanceIndex inst_id, void* user_arg,
157                               void* inst_ctx,
158                               struct PerfettoDsOnStopArgs* args) {
159       auto* thiz = static_cast<SharedLibDataSourceTest*>(user_arg);
160       return thiz->ds2_callbacks_.OnStop(inst_id, thiz->ds2_user_arg_, inst_ctx,
161                                          args);
162     };
163     callbacks.on_create_tls_cb = [](PerfettoDsInstanceIndex inst_id,
164                                     struct PerfettoDsTracerImpl* tracer,
165                                     void* user_arg) -> void* {
166       auto* thiz = static_cast<SharedLibDataSourceTest*>(user_arg);
167       auto* state = new Ds2CustomState();
168       state->thiz = thiz;
169       state->actual = thiz->ds2_callbacks_.OnCreateTls(inst_id, tracer,
170                                                        thiz->ds2_user_arg_);
171       return state;
172     };
173     callbacks.on_delete_tls_cb = [](void* ptr) {
174       auto* state = static_cast<Ds2CustomState*>(ptr);
175       state->thiz->ds2_callbacks_.OnDeleteTls(state->actual);
176       delete state;
177     };
178     callbacks.on_create_incr_cb = [](PerfettoDsInstanceIndex inst_id,
179                                      struct PerfettoDsTracerImpl* tracer,
180                                      void* user_arg) -> void* {
181       auto* thiz = static_cast<SharedLibDataSourceTest*>(user_arg);
182       auto* state = new Ds2CustomState();
183       state->thiz = thiz;
184       state->actual = thiz->ds2_callbacks_.OnCreateIncr(inst_id, tracer,
185                                                         thiz->ds2_user_arg_);
186       return state;
187     };
188     callbacks.on_delete_incr_cb = [](void* ptr) {
189       auto* state = static_cast<Ds2CustomState*>(ptr);
190       state->thiz->ds2_callbacks_.OnDeleteIncr(state->actual);
191       delete state;
192     };
193     callbacks.user_arg = this;
194     PerfettoDsRegister(&data_source_2, kDataSourceName2, callbacks);
195   }
196 
Ds2ActualCustomState(void * ptr)197   void* Ds2ActualCustomState(void* ptr) {
198     auto* state = static_cast<Ds2CustomState*>(ptr);
199     return state->actual;
200   }
201 
202   NiceMock<MockDs2Callbacks> ds2_callbacks_;
203   void* ds2_user_arg_ = kDataSource2UserArg;
204 };
205 
TEST_F(SharedLibDataSourceTest,DisabledNotExecuted)206 TEST_F(SharedLibDataSourceTest, DisabledNotExecuted) {
207   bool executed = false;
208 
209   PERFETTO_DS_TRACE(data_source_1, ctx) {
210     executed = true;
211   }
212 
213   EXPECT_FALSE(executed);
214 }
215 
TEST_F(SharedLibDataSourceTest,EnabledOnce)216 TEST_F(SharedLibDataSourceTest, EnabledOnce) {
217   size_t executed = 0;
218   TracingSession tracing_session =
219       TracingSession::Builder().set_data_source_name(kDataSourceName1).Build();
220 
221   PERFETTO_DS_TRACE(data_source_1, ctx) {
222     executed++;
223   }
224 
225   EXPECT_EQ(executed, 1u);
226 }
227 
TEST_F(SharedLibDataSourceTest,EnabledTwice)228 TEST_F(SharedLibDataSourceTest, EnabledTwice) {
229   size_t executed = 0;
230   TracingSession tracing_session1 =
231       TracingSession::Builder().set_data_source_name(kDataSourceName1).Build();
232   TracingSession tracing_session2 =
233       TracingSession::Builder().set_data_source_name(kDataSourceName1).Build();
234 
235   PERFETTO_DS_TRACE(data_source_1, ctx) {
236     executed++;
237   }
238 
239   EXPECT_EQ(executed, 2u);
240 }
241 
TEST_F(SharedLibDataSourceTest,Serialization)242 TEST_F(SharedLibDataSourceTest, Serialization) {
243   TracingSession tracing_session =
244       TracingSession::Builder().set_data_source_name(kDataSourceName1).Build();
245 
246   PERFETTO_DS_TRACE(data_source_1, ctx) {
247     struct PerfettoDsRootTracePacket trace_packet;
248     PerfettoDsTracerPacketBegin(&ctx, &trace_packet);
249 
250     {
251       struct perfetto_protos_TestEvent for_testing;
252       perfetto_protos_TracePacket_begin_for_testing(&trace_packet.msg,
253                                                     &for_testing);
254       {
255         struct perfetto_protos_TestEvent_TestPayload payload;
256         perfetto_protos_TestEvent_begin_payload(&for_testing, &payload);
257         perfetto_protos_TestEvent_TestPayload_set_cstr_str(&payload,
258                                                            "ABCDEFGH");
259         perfetto_protos_TestEvent_end_payload(&for_testing, &payload);
260       }
261       perfetto_protos_TracePacket_end_for_testing(&trace_packet.msg,
262                                                   &for_testing);
263     }
264     PerfettoDsTracerPacketEnd(&ctx, &trace_packet);
265   }
266   PERFETTO_DS_TRACE(data_source_1, ctx) {
267     struct PerfettoDsRootTracePacket trace_packet;
268     PerfettoDsTracerPacketBegin(&ctx, &trace_packet);
269     PerfettoDsTracerPacketEnd(&ctx, &trace_packet);
270   }
271 
272   tracing_session.StopBlocking();
273   std::vector<uint8_t> data = tracing_session.ReadBlocking();
274   bool found_for_testing = false;
275   for (struct PerfettoPbDecoderField trace_field : FieldView(data)) {
276     ASSERT_THAT(trace_field, PbField(perfetto_protos_Trace_packet_field_number,
277                                      MsgField(_)));
278     IdFieldView for_testing(
279         trace_field, perfetto_protos_TracePacket_for_testing_field_number);
280     ASSERT_TRUE(for_testing.ok());
281     if (for_testing.size() == 0) {
282       continue;
283     }
284     found_for_testing = true;
285     ASSERT_EQ(for_testing.size(), 1u);
286     ASSERT_THAT(FieldView(for_testing.front()),
287                 ElementsAre(PbField(
288                     perfetto_protos_TestEvent_payload_field_number,
289                     MsgField(ElementsAre(PbField(
290                         perfetto_protos_TestEvent_TestPayload_str_field_number,
291                         StringField("ABCDEFGH")))))));
292   }
293   EXPECT_TRUE(found_for_testing);
294 }
295 
TEST_F(SharedLibDataSourceTest,Break)296 TEST_F(SharedLibDataSourceTest, Break) {
297   TracingSession tracing_session1 =
298       TracingSession::Builder().set_data_source_name(kDataSourceName1).Build();
299   TracingSession tracing_session2 =
300       TracingSession::Builder().set_data_source_name(kDataSourceName1).Build();
301 
302   PERFETTO_DS_TRACE(data_source_1, ctx) {
303     struct PerfettoDsRootTracePacket trace_packet;
304     PerfettoDsTracerPacketBegin(&ctx, &trace_packet);
305 
306     {
307       struct perfetto_protos_TestEvent for_testing;
308       perfetto_protos_TracePacket_begin_for_testing(&trace_packet.msg,
309                                                     &for_testing);
310       perfetto_protos_TracePacket_end_for_testing(&trace_packet.msg,
311                                                   &for_testing);
312     }
313     PerfettoDsTracerPacketEnd(&ctx, &trace_packet);
314     // Break: the packet will be emitted only on the first data source instance
315     // and therefore will not show up on `tracing_session2`.
316     PERFETTO_DS_TRACE_BREAK(data_source_1, ctx);
317   }
318   PERFETTO_DS_TRACE(data_source_1, ctx) {
319     struct PerfettoDsRootTracePacket trace_packet;
320     PerfettoDsTracerPacketBegin(&ctx, &trace_packet);
321     PerfettoDsTracerPacketEnd(&ctx, &trace_packet);
322   }
323 
324   tracing_session1.StopBlocking();
325   std::vector<uint8_t> data1 = tracing_session1.ReadBlocking();
326   EXPECT_THAT(
327       FieldView(data1),
328       Contains(PbField(perfetto_protos_Trace_packet_field_number,
329                        MsgField(Contains(PbField(
330                            perfetto_protos_TracePacket_for_testing_field_number,
331                            MsgField(_)))))));
332   tracing_session2.StopBlocking();
333   std::vector<uint8_t> data2 = tracing_session2.ReadBlocking();
334   EXPECT_THAT(
335       FieldView(data2),
336       Each(PbField(
337           perfetto_protos_Trace_packet_field_number,
338           MsgField(Not(Contains(PbField(
339               perfetto_protos_TracePacket_for_testing_field_number, _)))))));
340 }
341 
TEST_F(SharedLibDataSourceTest,FlushCb)342 TEST_F(SharedLibDataSourceTest, FlushCb) {
343   TracingSession tracing_session =
344       TracingSession::Builder().set_data_source_name(kDataSourceName1).Build();
345   Notification notification;
346 
347   PERFETTO_DS_TRACE(data_source_1, ctx) {
348     PerfettoDsTracerFlush(
349         &ctx,
350         [](void* p_notification) {
351           static_cast<Notification*>(p_notification)->Notify();
352         },
353         &notification);
354   }
355 
356   notification.WaitForNotification();
357   EXPECT_TRUE(notification.Notified());
358 }
359 
TEST_F(SharedLibDataSourceTest,LifetimeCallbacks)360 TEST_F(SharedLibDataSourceTest, LifetimeCallbacks) {
361   void* const kInstancePtr = reinterpret_cast<void*>(0x44);
362   testing::InSequence seq;
363   PerfettoDsInstanceIndex setup_inst, start_inst, stop_inst;
364   EXPECT_CALL(ds2_callbacks_, OnSetup(_, _, _, kDataSource2UserArg))
365       .WillOnce(DoAll(SaveArg<0>(&setup_inst), Return(kInstancePtr)));
366   EXPECT_CALL(ds2_callbacks_, OnStart(_, kDataSource2UserArg, kInstancePtr))
367       .WillOnce(SaveArg<0>(&start_inst));
368 
369   TracingSession tracing_session =
370       TracingSession::Builder().set_data_source_name(kDataSourceName2).Build();
371 
372   EXPECT_CALL(ds2_callbacks_, OnStop(_, kDataSource2UserArg, kInstancePtr, _))
373       .WillOnce(SaveArg<0>(&stop_inst));
374 
375   tracing_session.StopBlocking();
376 
377   EXPECT_EQ(setup_inst, start_inst);
378   EXPECT_EQ(setup_inst, stop_inst);
379 }
380 
TEST_F(SharedLibDataSourceTest,StopDone)381 TEST_F(SharedLibDataSourceTest, StopDone) {
382   TracingSession tracing_session =
383       TracingSession::Builder().set_data_source_name(kDataSourceName2).Build();
384 
385   Notification stop_called;
386   struct PerfettoDsAsyncStopper* stopper;
387 
388   EXPECT_CALL(ds2_callbacks_, OnStop(_, kDataSource2UserArg, _, _))
389       .WillOnce([&](PerfettoDsInstanceIndex, void*, void*,
390                     struct PerfettoDsOnStopArgs* args) {
391         stopper = PerfettoDsOnStopArgsPostpone(args);
392         stop_called.Notify();
393       });
394 
395   std::thread t([&]() { tracing_session.StopBlocking(); });
396 
397   stop_called.WaitForNotification();
398   PerfettoDsStopDone(stopper);
399 
400   t.join();
401 }
402 
TEST_F(SharedLibDataSourceTest,ThreadLocalState)403 TEST_F(SharedLibDataSourceTest, ThreadLocalState) {
404   bool ignored = false;
405   void* const kTlsPtr = &ignored;
406   TracingSession tracing_session =
407       TracingSession::Builder().set_data_source_name(kDataSourceName2).Build();
408 
409   EXPECT_CALL(ds2_callbacks_, OnCreateTls).WillOnce(Return(kTlsPtr));
410 
411   void* tls_state = nullptr;
412   PERFETTO_DS_TRACE(data_source_2, ctx) {
413     tls_state = PerfettoDsGetCustomTls(&data_source_2, &ctx);
414   }
415   EXPECT_EQ(Ds2ActualCustomState(tls_state), kTlsPtr);
416 
417   tracing_session.StopBlocking();
418 
419   EXPECT_CALL(ds2_callbacks_, OnDeleteTls(kTlsPtr));
420 
421   // The OnDelete callback will be called by
422   // DestroyStoppedTraceWritersForCurrentThread(). One way to trigger that is to
423   // trace with another data source.
424   TracingSession tracing_session_1 =
425       TracingSession::Builder().set_data_source_name(kDataSourceName1).Build();
426   PERFETTO_DS_TRACE(data_source_1, ctx) {}
427 }
428 
TEST_F(SharedLibDataSourceTest,IncrementalState)429 TEST_F(SharedLibDataSourceTest, IncrementalState) {
430   bool ignored = false;
431   void* const kIncrPtr = &ignored;
432   TracingSession tracing_session =
433       TracingSession::Builder().set_data_source_name(kDataSourceName2).Build();
434 
435   EXPECT_CALL(ds2_callbacks_, OnCreateIncr).WillOnce(Return(kIncrPtr));
436 
437   void* tls_state = nullptr;
438   PERFETTO_DS_TRACE(data_source_2, ctx) {
439     tls_state = PerfettoDsGetIncrementalState(&data_source_2, &ctx);
440   }
441   EXPECT_EQ(Ds2ActualCustomState(tls_state), kIncrPtr);
442 
443   tracing_session.StopBlocking();
444 
445   EXPECT_CALL(ds2_callbacks_, OnDeleteIncr(kIncrPtr));
446 
447   // The OnDelete callback will be called by
448   // DestroyStoppedTraceWritersForCurrentThread(). One way to trigger that is to
449   // trace with another data source.
450   TracingSession tracing_session_1 =
451       TracingSession::Builder().set_data_source_name(kDataSourceName1).Build();
452   PERFETTO_DS_TRACE(data_source_1, ctx) {}
453 }
454 
455 }  // namespace
456