/* * Copyright (C) 2023 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include "perfetto/public/abi/data_source_abi.h" #include "perfetto/public/abi/heap_buffer.h" #include "perfetto/public/abi/pb_decoder_abi.h" #include "perfetto/public/abi/tracing_session_abi.h" #include "perfetto/public/abi/track_event_abi.h" #include "perfetto/public/data_source.h" #include "perfetto/public/pb_decoder.h" #include "perfetto/public/producer.h" #include "perfetto/public/protos/config/trace_config.pzc.h" #include "perfetto/public/protos/trace/interned_data/interned_data.pzc.h" #include "perfetto/public/protos/trace/test_event.pzc.h" #include "perfetto/public/protos/trace/trace.pzc.h" #include "perfetto/public/protos/trace/trace_packet.pzc.h" #include "perfetto/public/protos/trace/track_event/debug_annotation.pzc.h" #include "perfetto/public/protos/trace/track_event/track_descriptor.pzc.h" #include "perfetto/public/protos/trace/track_event/track_event.pzc.h" #include "perfetto/public/protos/trace/trigger.pzc.h" #include "perfetto/public/te_category_macros.h" #include "perfetto/public/te_macros.h" #include "perfetto/public/track_event.h" #include "test/gtest_and_gmock.h" #include "src/shared_lib/reset_for_testing.h" #include "src/shared_lib/test/protos/extensions.pzc.h" #include "src/shared_lib/test/protos/test_messages.pzc.h" #include "src/shared_lib/test/utils.h" // Tests for the perfetto shared library. namespace { using ::perfetto::shlib::test_utils::AllFieldsWithId; using ::perfetto::shlib::test_utils::DoubleField; using ::perfetto::shlib::test_utils::FieldView; using ::perfetto::shlib::test_utils::Fixed32Field; using ::perfetto::shlib::test_utils::Fixed64Field; using ::perfetto::shlib::test_utils::FloatField; using ::perfetto::shlib::test_utils::IdFieldView; using ::perfetto::shlib::test_utils::MsgField; using ::perfetto::shlib::test_utils::PbField; using ::perfetto::shlib::test_utils::StringField; using ::perfetto::shlib::test_utils::TracingSession; using ::perfetto::shlib::test_utils::VarIntField; using ::perfetto::shlib::test_utils::WaitableEvent; using ::testing::_; using ::testing::AllOf; using ::testing::DoAll; using ::testing::ElementsAre; using ::testing::InSequence; using ::testing::IsNull; using ::testing::NiceMock; using ::testing::ResultOf; using ::testing::Return; using ::testing::SaveArg; using ::testing::UnorderedElementsAre; constexpr char kDataSourceName1[] = "dev.perfetto.example_data_source"; struct PerfettoDs data_source_1 = PERFETTO_DS_INIT(); constexpr char kDataSourceName2[] = "dev.perfetto.example_data_source2"; struct PerfettoDs data_source_2 = PERFETTO_DS_INIT(); void* const kDataSource2UserArg = reinterpret_cast(0x555); #define TEST_CATEGORIES(C) \ C(cat1, "cat1", "") C(cat2, "cat2", "") C(cat3, "cat3", "") PERFETTO_TE_CATEGORIES_DEFINE(TEST_CATEGORIES) class MockDs2Callbacks : testing::Mock { public: MOCK_METHOD(void*, OnSetup, (struct PerfettoDsImpl*, PerfettoDsInstanceIndex inst_id, void* ds_config, size_t ds_config_size, void* user_arg, struct PerfettoDsOnSetupArgs* args)); MOCK_METHOD(void, OnStart, (struct PerfettoDsImpl*, PerfettoDsInstanceIndex inst_id, void* user_arg, void* inst_ctx, struct PerfettoDsOnStartArgs* args)); MOCK_METHOD(void, OnStop, (struct PerfettoDsImpl*, PerfettoDsInstanceIndex inst_id, void* user_arg, void* inst_ctx, struct PerfettoDsOnStopArgs* args)); MOCK_METHOD(void, OnDestroy, (struct PerfettoDsImpl*, void* user_arg, void* inst_ctx)); MOCK_METHOD(void, OnFlush, (struct PerfettoDsImpl*, PerfettoDsInstanceIndex inst_id, void* user_arg, void* inst_ctx, struct PerfettoDsOnFlushArgs* args)); MOCK_METHOD(void*, OnCreateTls, (struct PerfettoDsImpl*, PerfettoDsInstanceIndex inst_id, struct PerfettoDsTracerImpl* tracer, void* user_arg)); MOCK_METHOD(void, OnDeleteTls, (void*)); MOCK_METHOD(void*, OnCreateIncr, (struct PerfettoDsImpl*, PerfettoDsInstanceIndex inst_id, struct PerfettoDsTracerImpl* tracer, void* user_arg)); MOCK_METHOD(void, OnDeleteIncr, (void*)); }; TEST(SharedLibProtobufTest, PerfettoPbDecoderIteratorExample) { // # proto-message: perfetto.protos.TestEvent // counter: 5 // payload { // str: "hello" // single_int: -1 // } std::string_view msg = "\x18\x05\x2a\x12\x0a\x05\x68\x65\x6c\x6c\x6f\x28\xff\xff\xff\xff\xff\xff" "\xff\xff\xff\x01"; size_t n_counter = 0; size_t n_payload = 0; size_t n_payload_str = 0; size_t n_payload_single_int = 0; for (struct PerfettoPbDecoderIterator it = PerfettoPbDecoderIterateBegin(msg.data(), msg.size()); it.field.status != PERFETTO_PB_DECODER_DONE; PerfettoPbDecoderIterateNext(&it)) { if (it.field.status != PERFETTO_PB_DECODER_OK) { ADD_FAILURE() << "Failed to parse main message"; break; } switch (it.field.id) { case perfetto_protos_TestEvent_counter_field_number: n_counter++; EXPECT_EQ(it.field.wire_type, PERFETTO_PB_WIRE_TYPE_VARINT); { uint64_t val = 0; EXPECT_TRUE(PerfettoPbDecoderFieldGetUint64(&it.field, &val)); EXPECT_EQ(val, 5u); } break; case perfetto_protos_TestEvent_payload_field_number: n_payload++; EXPECT_EQ(it.field.wire_type, PERFETTO_PB_WIRE_TYPE_DELIMITED); for (struct PerfettoPbDecoderIterator it2 = PerfettoPbDecoderIterateNestedBegin(it.field.value.delimited); it2.field.status != PERFETTO_PB_DECODER_DONE; PerfettoPbDecoderIterateNext(&it2)) { if (it2.field.status != PERFETTO_PB_DECODER_OK) { ADD_FAILURE() << "Failed to parse nested message"; break; } switch (it2.field.id) { case perfetto_protos_TestEvent_TestPayload_str_field_number: n_payload_str++; EXPECT_EQ(it2.field.wire_type, PERFETTO_PB_WIRE_TYPE_DELIMITED); EXPECT_EQ(std::string_view(reinterpret_cast( it2.field.value.delimited.start), it2.field.value.delimited.len), "hello"); break; case perfetto_protos_TestEvent_TestPayload_single_int_field_number: EXPECT_EQ(it2.field.wire_type, PERFETTO_PB_WIRE_TYPE_VARINT); n_payload_single_int++; { int32_t val = 0; EXPECT_TRUE(PerfettoPbDecoderFieldGetInt32(&it2.field, &val)); EXPECT_EQ(val, -1); } break; default: ADD_FAILURE() << "Unexpected nested field.id"; break; } } break; default: ADD_FAILURE() << "Unexpected field.id"; break; } } EXPECT_EQ(n_counter, 1u); EXPECT_EQ(n_payload, 1u); EXPECT_EQ(n_payload_str, 1u); EXPECT_EQ(n_payload_single_int, 1u); } class SharedLibProtozeroSerializationTest : public testing::Test { protected: SharedLibProtozeroSerializationTest() { hb = PerfettoHeapBufferCreate(&writer.writer); } std::vector GetData() { std::vector data; size_t size = PerfettoStreamWriterGetWrittenSize(&writer.writer); data.resize(size); PerfettoHeapBufferCopyInto(hb, &writer.writer, data.data(), data.size()); return data; } ~SharedLibProtozeroSerializationTest() { PerfettoHeapBufferDestroy(hb, &writer.writer); } template static std::vector ParsePackedVarInt(const std::string& data) { std::vector ret; const uint8_t* read_ptr = reinterpret_cast(data.data()); const uint8_t* const end = read_ptr + data.size(); while (read_ptr != end) { uint64_t val; const uint8_t* new_read_ptr = PerfettoPbParseVarInt(read_ptr, end, &val); if (new_read_ptr == read_ptr) { ADD_FAILURE(); return ret; } read_ptr = new_read_ptr; ret.push_back(static_cast(val)); } return ret; } template static std::vector ParsePackedFixed(const std::string& data) { std::vector ret; if (data.size() % sizeof(T)) { ADD_FAILURE(); return ret; } const uint8_t* read_ptr = reinterpret_cast(data.data()); const uint8_t* end = read_ptr + data.size(); while (read_ptr < end) { ret.push_back(*reinterpret_cast(read_ptr)); read_ptr += sizeof(T); } return ret; } struct PerfettoPbMsgWriter writer; struct PerfettoHeapBuffer* hb; }; TEST_F(SharedLibProtozeroSerializationTest, SimpleFieldsNoNesting) { struct protozero_test_protos_EveryField msg; PerfettoPbMsgInit(&msg.msg, &writer); protozero_test_protos_EveryField_set_field_int32(&msg, -1); protozero_test_protos_EveryField_set_field_int64(&msg, -333123456789ll); protozero_test_protos_EveryField_set_field_uint32(&msg, 600); protozero_test_protos_EveryField_set_field_uint64(&msg, 333123456789ll); protozero_test_protos_EveryField_set_field_sint32(&msg, -5); protozero_test_protos_EveryField_set_field_sint64(&msg, -9000); protozero_test_protos_EveryField_set_field_fixed32(&msg, 12345); protozero_test_protos_EveryField_set_field_fixed64(&msg, 444123450000ll); protozero_test_protos_EveryField_set_field_sfixed32(&msg, -69999); protozero_test_protos_EveryField_set_field_sfixed64(&msg, -200); protozero_test_protos_EveryField_set_field_float(&msg, 3.14f); protozero_test_protos_EveryField_set_field_double(&msg, 0.5555); protozero_test_protos_EveryField_set_field_bool(&msg, true); protozero_test_protos_EveryField_set_small_enum(&msg, protozero_test_protos_TO_BE); protozero_test_protos_EveryField_set_signed_enum( &msg, protozero_test_protos_NEGATIVE); protozero_test_protos_EveryField_set_big_enum(&msg, protozero_test_protos_BEGIN); protozero_test_protos_EveryField_set_cstr_field_string(&msg, "FizzBuzz"); protozero_test_protos_EveryField_set_field_bytes(&msg, "\x11\x00\xBE\xEF", 4); protozero_test_protos_EveryField_set_repeated_int32(&msg, 1); protozero_test_protos_EveryField_set_repeated_int32(&msg, -1); protozero_test_protos_EveryField_set_repeated_int32(&msg, 100); protozero_test_protos_EveryField_set_repeated_int32(&msg, 2000000); EXPECT_THAT( FieldView(GetData()), ElementsAre( PbField(protozero_test_protos_EveryField_field_int32_field_number, VarIntField(static_cast(-1))), PbField(protozero_test_protos_EveryField_field_int64_field_number, VarIntField(static_cast(INT64_C(-333123456789)))), PbField(protozero_test_protos_EveryField_field_uint32_field_number, VarIntField(600)), PbField(protozero_test_protos_EveryField_field_uint64_field_number, VarIntField(UINT64_C(333123456789))), PbField(protozero_test_protos_EveryField_field_sint32_field_number, VarIntField(ResultOf( [](uint64_t val) { return PerfettoPbZigZagDecode32( static_cast(val)); }, -5))), PbField(protozero_test_protos_EveryField_field_sint64_field_number, VarIntField(ResultOf(PerfettoPbZigZagDecode64, -9000))), PbField(protozero_test_protos_EveryField_field_fixed32_field_number, Fixed32Field(12345)), PbField(protozero_test_protos_EveryField_field_fixed64_field_number, Fixed64Field(UINT64_C(444123450000))), PbField(protozero_test_protos_EveryField_field_sfixed32_field_number, Fixed32Field(static_cast(-69999))), PbField(protozero_test_protos_EveryField_field_sfixed64_field_number, Fixed64Field(static_cast(-200))), PbField(protozero_test_protos_EveryField_field_float_field_number, FloatField(3.14f)), PbField(protozero_test_protos_EveryField_field_double_field_number, DoubleField(0.5555)), PbField(protozero_test_protos_EveryField_field_bool_field_number, VarIntField(true)), PbField(protozero_test_protos_EveryField_small_enum_field_number, VarIntField(protozero_test_protos_TO_BE)), PbField(protozero_test_protos_EveryField_signed_enum_field_number, VarIntField(protozero_test_protos_NEGATIVE)), PbField(protozero_test_protos_EveryField_big_enum_field_number, VarIntField(protozero_test_protos_BEGIN)), PbField(protozero_test_protos_EveryField_field_string_field_number, StringField("FizzBuzz")), PbField(protozero_test_protos_EveryField_field_bytes_field_number, StringField(std::string_view("\x11\x00\xBE\xEF", 4))), PbField(protozero_test_protos_EveryField_repeated_int32_field_number, VarIntField(1)), PbField(protozero_test_protos_EveryField_repeated_int32_field_number, VarIntField(static_cast(-1))), PbField(protozero_test_protos_EveryField_repeated_int32_field_number, VarIntField(100)), PbField(protozero_test_protos_EveryField_repeated_int32_field_number, VarIntField(2000000)))); } TEST_F(SharedLibProtozeroSerializationTest, NestedMessages) { struct protozero_test_protos_NestedA msg_a; PerfettoPbMsgInit(&msg_a.msg, &writer); { struct protozero_test_protos_NestedA_NestedB msg_b; protozero_test_protos_NestedA_begin_repeated_a(&msg_a, &msg_b); { struct protozero_test_protos_NestedA_NestedB_NestedC msg_c; protozero_test_protos_NestedA_NestedB_begin_value_b(&msg_b, &msg_c); protozero_test_protos_NestedA_NestedB_NestedC_set_value_c(&msg_c, 321); protozero_test_protos_NestedA_NestedB_end_value_b(&msg_b, &msg_c); } protozero_test_protos_NestedA_end_repeated_a(&msg_a, &msg_b); } { struct protozero_test_protos_NestedA_NestedB msg_b; protozero_test_protos_NestedA_begin_repeated_a(&msg_a, &msg_b); protozero_test_protos_NestedA_end_repeated_a(&msg_a, &msg_b); } { struct protozero_test_protos_NestedA_NestedB_NestedC msg_c; protozero_test_protos_NestedA_begin_super_nested(&msg_a, &msg_c); protozero_test_protos_NestedA_NestedB_NestedC_set_value_c(&msg_c, 1000); protozero_test_protos_NestedA_end_super_nested(&msg_a, &msg_c); } EXPECT_THAT( FieldView(GetData()), ElementsAre( PbField( protozero_test_protos_NestedA_repeated_a_field_number, MsgField(ElementsAre(PbField( protozero_test_protos_NestedA_NestedB_value_b_field_number, MsgField(ElementsAre(PbField( protozero_test_protos_NestedA_NestedB_NestedC_value_c_field_number, VarIntField(321)))))))), PbField(protozero_test_protos_NestedA_repeated_a_field_number, MsgField(ElementsAre())), PbField( protozero_test_protos_NestedA_super_nested_field_number, MsgField(ElementsAre(PbField( protozero_test_protos_NestedA_NestedB_NestedC_value_c_field_number, VarIntField(1000))))))); } TEST_F(SharedLibProtozeroSerializationTest, Extensions) { struct protozero_test_protos_RealFakeEvent base; PerfettoPbMsgInit(&base.msg, &writer); { struct protozero_test_protos_SystemA msg_a; protozero_test_protos_BrowserExtension_begin_extension_a(&base, &msg_a); protozero_test_protos_SystemA_set_cstr_string_a(&msg_a, "str_a"); protozero_test_protos_BrowserExtension_end_extension_a(&base, &msg_a); } { struct protozero_test_protos_SystemB msg_b; protozero_test_protos_BrowserExtension_begin_extension_b(&base, &msg_b); protozero_test_protos_SystemB_set_cstr_string_b(&msg_b, "str_b"); protozero_test_protos_BrowserExtension_end_extension_b(&base, &msg_b); } protozero_test_protos_RealFakeEvent_set_cstr_base_string(&base, "str"); EXPECT_THAT( FieldView(GetData()), ElementsAre( PbField( protozero_test_protos_BrowserExtension_extension_a_field_number, MsgField(ElementsAre( PbField(protozero_test_protos_SystemA_string_a_field_number, StringField("str_a"))))), PbField( protozero_test_protos_BrowserExtension_extension_b_field_number, MsgField(ElementsAre( PbField(protozero_test_protos_SystemB_string_b_field_number, StringField("str_b"))))), PbField(protozero_test_protos_RealFakeEvent_base_string_field_number, StringField("str")))); } TEST_F(SharedLibProtozeroSerializationTest, PackedRepeatedMsgVarInt) { struct protozero_test_protos_PackedRepeatedFields msg; PerfettoPbMsgInit(&msg.msg, &writer); { PerfettoPbPackedMsgInt32 f; protozero_test_protos_PackedRepeatedFields_begin_field_int32(&msg, &f); PerfettoPbPackedMsgInt32Append(&f, 42); PerfettoPbPackedMsgInt32Append(&f, 255); PerfettoPbPackedMsgInt32Append(&f, -1); protozero_test_protos_PackedRepeatedFields_end_field_int32(&msg, &f); } { PerfettoPbPackedMsgInt64 f; protozero_test_protos_PackedRepeatedFields_begin_field_int64(&msg, &f); PerfettoPbPackedMsgInt64Append(&f, INT64_C(3000000000)); PerfettoPbPackedMsgInt64Append(&f, INT64_C(-3000000000)); protozero_test_protos_PackedRepeatedFields_end_field_int64(&msg, &f); } { PerfettoPbPackedMsgUint32 f; protozero_test_protos_PackedRepeatedFields_begin_field_uint32(&msg, &f); PerfettoPbPackedMsgUint32Append(&f, 42); PerfettoPbPackedMsgUint32Append(&f, UINT32_C(3000000000)); protozero_test_protos_PackedRepeatedFields_end_field_uint32(&msg, &f); } { PerfettoPbPackedMsgUint64 f; protozero_test_protos_PackedRepeatedFields_begin_field_uint64(&msg, &f); PerfettoPbPackedMsgUint64Append(&f, 42); PerfettoPbPackedMsgUint64Append(&f, UINT64_C(5000000000)); protozero_test_protos_PackedRepeatedFields_end_field_uint64(&msg, &f); } { PerfettoPbPackedMsgInt32 f; protozero_test_protos_PackedRepeatedFields_begin_signed_enum(&msg, &f); PerfettoPbPackedMsgInt32Append(&f, protozero_test_protos_POSITIVE); PerfettoPbPackedMsgInt32Append(&f, protozero_test_protos_NEGATIVE); protozero_test_protos_PackedRepeatedFields_end_signed_enum(&msg, &f); } EXPECT_THAT( FieldView(GetData()), ElementsAre( PbField( protozero_test_protos_PackedRepeatedFields_field_int32_field_number, StringField(ResultOf(ParsePackedVarInt, ElementsAre(42, 255, -1)))), PbField( protozero_test_protos_PackedRepeatedFields_field_int64_field_number, StringField(ResultOf( ParsePackedVarInt, ElementsAre(INT64_C(3000000000), INT64_C(-3000000000))))), PbField( protozero_test_protos_PackedRepeatedFields_field_uint32_field_number, StringField(ResultOf(ParsePackedVarInt, ElementsAre(42, UINT32_C(3000000000))))), PbField( protozero_test_protos_PackedRepeatedFields_field_uint64_field_number, StringField(ResultOf(ParsePackedVarInt, ElementsAre(42, UINT64_C(5000000000))))), PbField( protozero_test_protos_PackedRepeatedFields_signed_enum_field_number, StringField( ResultOf(ParsePackedVarInt, ElementsAre(protozero_test_protos_POSITIVE, protozero_test_protos_NEGATIVE)))))); } TEST_F(SharedLibProtozeroSerializationTest, PackedRepeatedMsgFixed) { struct protozero_test_protos_PackedRepeatedFields msg; PerfettoPbMsgInit(&msg.msg, &writer); { PerfettoPbPackedMsgFixed32 f; protozero_test_protos_PackedRepeatedFields_begin_field_fixed32(&msg, &f); PerfettoPbPackedMsgFixed32Append(&f, 42); PerfettoPbPackedMsgFixed32Append(&f, UINT32_C(3000000000)); protozero_test_protos_PackedRepeatedFields_end_field_fixed32(&msg, &f); } { PerfettoPbPackedMsgFixed64 f; protozero_test_protos_PackedRepeatedFields_begin_field_fixed64(&msg, &f); PerfettoPbPackedMsgFixed64Append(&f, 42); PerfettoPbPackedMsgFixed64Append(&f, UINT64_C(5000000000)); protozero_test_protos_PackedRepeatedFields_end_field_fixed64(&msg, &f); } { PerfettoPbPackedMsgSfixed32 f; protozero_test_protos_PackedRepeatedFields_begin_field_sfixed32(&msg, &f); PerfettoPbPackedMsgSfixed32Append(&f, 42); PerfettoPbPackedMsgSfixed32Append(&f, 255); PerfettoPbPackedMsgSfixed32Append(&f, -1); protozero_test_protos_PackedRepeatedFields_end_field_sfixed32(&msg, &f); } { PerfettoPbPackedMsgSfixed64 f; protozero_test_protos_PackedRepeatedFields_begin_field_sfixed64(&msg, &f); PerfettoPbPackedMsgSfixed64Append(&f, INT64_C(3000000000)); PerfettoPbPackedMsgSfixed64Append(&f, INT64_C(-3000000000)); protozero_test_protos_PackedRepeatedFields_end_field_sfixed64(&msg, &f); } { PerfettoPbPackedMsgFloat f; protozero_test_protos_PackedRepeatedFields_begin_field_float(&msg, &f); PerfettoPbPackedMsgFloatAppend(&f, 3.14f); PerfettoPbPackedMsgFloatAppend(&f, 42.1f); protozero_test_protos_PackedRepeatedFields_end_field_float(&msg, &f); } { PerfettoPbPackedMsgDouble f; protozero_test_protos_PackedRepeatedFields_begin_field_double(&msg, &f); PerfettoPbPackedMsgDoubleAppend(&f, 3.14); PerfettoPbPackedMsgDoubleAppend(&f, 42.1); protozero_test_protos_PackedRepeatedFields_end_field_double(&msg, &f); } EXPECT_THAT( FieldView(GetData()), ElementsAre( PbField( protozero_test_protos_PackedRepeatedFields_field_fixed32_field_number, StringField(ResultOf(ParsePackedFixed, ElementsAre(42, UINT32_C(3000000000))))), PbField( protozero_test_protos_PackedRepeatedFields_field_fixed64_field_number, StringField(ResultOf(ParsePackedFixed, ElementsAre(42, UINT64_C(5000000000))))), PbField( protozero_test_protos_PackedRepeatedFields_field_sfixed32_field_number, StringField(ResultOf(ParsePackedFixed, ElementsAre(42, 255, -1)))), PbField( protozero_test_protos_PackedRepeatedFields_field_sfixed64_field_number, StringField(ResultOf( ParsePackedFixed, ElementsAre(INT64_C(3000000000), INT64_C(-3000000000))))), PbField( protozero_test_protos_PackedRepeatedFields_field_float_field_number, StringField(ResultOf(ParsePackedFixed, ElementsAre(3.14f, 42.1f)))), PbField( protozero_test_protos_PackedRepeatedFields_field_double_field_number, StringField(ResultOf(ParsePackedFixed, ElementsAre(3.14, 42.1)))))); } class SharedLibDataSourceTest : public testing::Test { protected: void SetUp() override { struct PerfettoProducerInitArgs args = PERFETTO_PRODUCER_INIT_ARGS_INIT(); args.backends = PERFETTO_BACKEND_IN_PROCESS; PerfettoProducerInit(args); PerfettoDsRegister(&data_source_1, kDataSourceName1, PerfettoDsParamsDefault()); RegisterDataSource2(); } void TearDown() override { perfetto::shlib::ResetForTesting(); data_source_1.enabled = &perfetto_atomic_false; perfetto::shlib::DsImplDestroy(data_source_1.impl); data_source_1.impl = nullptr; data_source_2.enabled = &perfetto_atomic_false; perfetto::shlib::DsImplDestroy(data_source_2.impl); data_source_2.impl = nullptr; } struct Ds2CustomState { void* actual; SharedLibDataSourceTest* thiz; }; void RegisterDataSource2() { struct PerfettoDsParams params = PerfettoDsParamsDefault(); params.on_setup_cb = [](struct PerfettoDsImpl* ds_impl, PerfettoDsInstanceIndex inst_id, void* ds_config, size_t ds_config_size, void* user_arg, struct PerfettoDsOnSetupArgs* args) -> void* { auto* thiz = static_cast(user_arg); return thiz->ds2_callbacks_.OnSetup(ds_impl, inst_id, ds_config, ds_config_size, thiz->ds2_user_arg_, args); }; params.on_start_cb = [](struct PerfettoDsImpl* ds_impl, PerfettoDsInstanceIndex inst_id, void* user_arg, void* inst_ctx, struct PerfettoDsOnStartArgs* args) -> void { auto* thiz = static_cast(user_arg); return thiz->ds2_callbacks_.OnStart(ds_impl, inst_id, thiz->ds2_user_arg_, inst_ctx, args); }; params.on_stop_cb = [](struct PerfettoDsImpl* ds_impl, PerfettoDsInstanceIndex inst_id, void* user_arg, void* inst_ctx, struct PerfettoDsOnStopArgs* args) { auto* thiz = static_cast(user_arg); return thiz->ds2_callbacks_.OnStop(ds_impl, inst_id, thiz->ds2_user_arg_, inst_ctx, args); }; params.on_destroy_cb = [](struct PerfettoDsImpl* ds_impl, void* user_arg, void* inst_ctx) -> void { auto* thiz = static_cast(user_arg); thiz->ds2_callbacks_.OnDestroy(ds_impl, thiz->ds2_user_arg_, inst_ctx); }; params.on_flush_cb = [](struct PerfettoDsImpl* ds_impl, PerfettoDsInstanceIndex inst_id, void* user_arg, void* inst_ctx, struct PerfettoDsOnFlushArgs* args) { auto* thiz = static_cast(user_arg); return thiz->ds2_callbacks_.OnFlush( ds_impl, inst_id, thiz->ds2_user_arg_, inst_ctx, args); }; params.on_create_tls_cb = [](struct PerfettoDsImpl* ds_impl, PerfettoDsInstanceIndex inst_id, struct PerfettoDsTracerImpl* tracer, void* user_arg) -> void* { auto* thiz = static_cast(user_arg); auto* state = new Ds2CustomState(); state->thiz = thiz; state->actual = thiz->ds2_callbacks_.OnCreateTls(ds_impl, inst_id, tracer, thiz->ds2_user_arg_); return state; }; params.on_delete_tls_cb = [](void* ptr) { auto* state = static_cast(ptr); state->thiz->ds2_callbacks_.OnDeleteTls(state->actual); delete state; }; params.on_create_incr_cb = [](struct PerfettoDsImpl* ds_impl, PerfettoDsInstanceIndex inst_id, struct PerfettoDsTracerImpl* tracer, void* user_arg) -> void* { auto* thiz = static_cast(user_arg); auto* state = new Ds2CustomState(); state->thiz = thiz; state->actual = thiz->ds2_callbacks_.OnCreateIncr( ds_impl, inst_id, tracer, thiz->ds2_user_arg_); return state; }; params.on_delete_incr_cb = [](void* ptr) { auto* state = static_cast(ptr); state->thiz->ds2_callbacks_.OnDeleteIncr(state->actual); delete state; }; params.user_arg = this; PerfettoDsRegister(&data_source_2, kDataSourceName2, params); } void* Ds2ActualCustomState(void* ptr) { auto* state = static_cast(ptr); return state->actual; } NiceMock ds2_callbacks_; void* ds2_user_arg_ = kDataSource2UserArg; }; TEST_F(SharedLibDataSourceTest, DisabledNotExecuted) { bool executed = false; PERFETTO_DS_TRACE(data_source_1, ctx) { executed = true; } EXPECT_FALSE(executed); } TEST_F(SharedLibDataSourceTest, EnabledOnce) { size_t executed = 0; TracingSession tracing_session = TracingSession::Builder().set_data_source_name(kDataSourceName1).Build(); PERFETTO_DS_TRACE(data_source_1, ctx) { executed++; } EXPECT_EQ(executed, 1u); } TEST_F(SharedLibDataSourceTest, EnabledTwice) { size_t executed = 0; TracingSession tracing_session1 = TracingSession::Builder().set_data_source_name(kDataSourceName1).Build(); TracingSession tracing_session2 = TracingSession::Builder().set_data_source_name(kDataSourceName1).Build(); PERFETTO_DS_TRACE(data_source_1, ctx) { executed++; } EXPECT_EQ(executed, 2u); } TEST_F(SharedLibDataSourceTest, Serialization) { TracingSession tracing_session = TracingSession::Builder().set_data_source_name(kDataSourceName1).Build(); PERFETTO_DS_TRACE(data_source_1, ctx) { struct PerfettoDsRootTracePacket trace_packet; PerfettoDsTracerPacketBegin(&ctx, &trace_packet); { struct perfetto_protos_TestEvent for_testing; perfetto_protos_TracePacket_begin_for_testing(&trace_packet.msg, &for_testing); { struct perfetto_protos_TestEvent_TestPayload payload; perfetto_protos_TestEvent_begin_payload(&for_testing, &payload); perfetto_protos_TestEvent_TestPayload_set_cstr_str(&payload, "ABCDEFGH"); perfetto_protos_TestEvent_end_payload(&for_testing, &payload); } perfetto_protos_TracePacket_end_for_testing(&trace_packet.msg, &for_testing); } PerfettoDsTracerPacketEnd(&ctx, &trace_packet); } tracing_session.StopBlocking(); std::vector data = tracing_session.ReadBlocking(); bool found_for_testing = false; for (struct PerfettoPbDecoderField trace_field : FieldView(data)) { ASSERT_THAT(trace_field, PbField(perfetto_protos_Trace_packet_field_number, MsgField(_))); IdFieldView for_testing( trace_field, perfetto_protos_TracePacket_for_testing_field_number); ASSERT_TRUE(for_testing.ok()); if (for_testing.size() == 0) { continue; } found_for_testing = true; ASSERT_EQ(for_testing.size(), 1u); ASSERT_THAT(FieldView(for_testing.front()), ElementsAre(PbField( perfetto_protos_TestEvent_payload_field_number, MsgField(ElementsAre(PbField( perfetto_protos_TestEvent_TestPayload_str_field_number, StringField("ABCDEFGH"))))))); } EXPECT_TRUE(found_for_testing); } TEST_F(SharedLibDataSourceTest, Break) { TracingSession tracing_session1 = TracingSession::Builder().set_data_source_name(kDataSourceName1).Build(); TracingSession tracing_session2 = TracingSession::Builder().set_data_source_name(kDataSourceName1).Build(); PERFETTO_DS_TRACE(data_source_1, ctx) { struct PerfettoDsRootTracePacket trace_packet; PerfettoDsTracerPacketBegin(&ctx, &trace_packet); { struct perfetto_protos_TestEvent for_testing; perfetto_protos_TracePacket_begin_for_testing(&trace_packet.msg, &for_testing); perfetto_protos_TracePacket_end_for_testing(&trace_packet.msg, &for_testing); } PerfettoDsTracerPacketEnd(&ctx, &trace_packet); // Break: the packet will be emitted only on the first data source instance // and therefore will not show up on `tracing_session2`. PERFETTO_DS_TRACE_BREAK(data_source_1, ctx); } tracing_session1.StopBlocking(); std::vector data1 = tracing_session1.ReadBlocking(); EXPECT_THAT( FieldView(data1), Contains(PbField(perfetto_protos_Trace_packet_field_number, MsgField(Contains(PbField( perfetto_protos_TracePacket_for_testing_field_number, MsgField(_))))))); tracing_session2.StopBlocking(); std::vector data2 = tracing_session2.ReadBlocking(); EXPECT_THAT( FieldView(data2), Each(PbField( perfetto_protos_Trace_packet_field_number, MsgField(Not(Contains(PbField( perfetto_protos_TracePacket_for_testing_field_number, _))))))); } TEST_F(SharedLibDataSourceTest, FlushCb) { TracingSession tracing_session = TracingSession::Builder().set_data_source_name(kDataSourceName1).Build(); WaitableEvent notification; PERFETTO_DS_TRACE(data_source_1, ctx) { PerfettoDsTracerFlush( &ctx, [](void* p_notification) { static_cast(p_notification)->Notify(); }, ¬ification); } notification.WaitForNotification(); EXPECT_TRUE(notification.IsNotified()); } TEST_F(SharedLibDataSourceTest, LifetimeCallbacks) { void* const kInstancePtr = reinterpret_cast(0x44); testing::InSequence seq; PerfettoDsInstanceIndex setup_inst, start_inst, stop_inst; EXPECT_CALL(ds2_callbacks_, OnSetup(_, _, _, _, kDataSource2UserArg, _)) .WillOnce(DoAll(SaveArg<1>(&setup_inst), Return(kInstancePtr))); EXPECT_CALL(ds2_callbacks_, OnStart(_, _, kDataSource2UserArg, kInstancePtr, _)) .WillOnce(SaveArg<1>(&start_inst)); TracingSession tracing_session = TracingSession::Builder().set_data_source_name(kDataSourceName2).Build(); EXPECT_CALL(ds2_callbacks_, OnStop(_, _, kDataSource2UserArg, kInstancePtr, _)) .WillOnce(SaveArg<1>(&stop_inst)); EXPECT_CALL(ds2_callbacks_, OnDestroy(_, kDataSource2UserArg, kInstancePtr)); tracing_session.StopBlocking(); EXPECT_EQ(setup_inst, start_inst); EXPECT_EQ(setup_inst, stop_inst); } TEST_F(SharedLibDataSourceTest, StopDone) { TracingSession tracing_session = TracingSession::Builder().set_data_source_name(kDataSourceName2).Build(); WaitableEvent stop_called; struct PerfettoDsAsyncStopper* stopper; EXPECT_CALL(ds2_callbacks_, OnStop(_, _, kDataSource2UserArg, _, _)) .WillOnce([&](struct PerfettoDsImpl*, PerfettoDsInstanceIndex, void*, void*, struct PerfettoDsOnStopArgs* args) { stopper = PerfettoDsOnStopArgsPostpone(args); stop_called.Notify(); }); std::thread t([&]() { tracing_session.StopBlocking(); }); stop_called.WaitForNotification(); PerfettoDsStopDone(stopper); t.join(); } TEST_F(SharedLibDataSourceTest, FlushDone) { TracingSession tracing_session = TracingSession::Builder().set_data_source_name(kDataSourceName2).Build(); WaitableEvent flush_called; WaitableEvent flush_done; struct PerfettoDsAsyncFlusher* flusher; EXPECT_CALL(ds2_callbacks_, OnFlush(_, _, kDataSource2UserArg, _, _)) .WillOnce([&](struct PerfettoDsImpl*, PerfettoDsInstanceIndex, void*, void*, struct PerfettoDsOnFlushArgs* args) { flusher = PerfettoDsOnFlushArgsPostpone(args); flush_called.Notify(); }); std::thread t([&]() { tracing_session.FlushBlocking(/*timeout_ms=*/10000); flush_done.Notify(); }); flush_called.WaitForNotification(); EXPECT_FALSE(flush_done.IsNotified()); PerfettoDsFlushDone(flusher); flush_done.WaitForNotification(); t.join(); } TEST_F(SharedLibDataSourceTest, ThreadLocalState) { bool ignored = false; void* const kTlsPtr = &ignored; TracingSession tracing_session = TracingSession::Builder().set_data_source_name(kDataSourceName2).Build(); EXPECT_CALL(ds2_callbacks_, OnCreateTls).WillOnce(Return(kTlsPtr)); void* tls_state = nullptr; PERFETTO_DS_TRACE(data_source_2, ctx) { tls_state = PerfettoDsGetCustomTls(&data_source_2, &ctx); } EXPECT_EQ(Ds2ActualCustomState(tls_state), kTlsPtr); tracing_session.StopBlocking(); EXPECT_CALL(ds2_callbacks_, OnDeleteTls(kTlsPtr)); // The OnDelete callback will be called by // DestroyStoppedTraceWritersForCurrentThread(). One way to trigger that is to // trace with another data source. TracingSession tracing_session_1 = TracingSession::Builder().set_data_source_name(kDataSourceName1).Build(); PERFETTO_DS_TRACE(data_source_1, ctx) {} } TEST_F(SharedLibDataSourceTest, IncrementalState) { bool ignored = false; void* const kIncrPtr = &ignored; TracingSession tracing_session = TracingSession::Builder().set_data_source_name(kDataSourceName2).Build(); EXPECT_CALL(ds2_callbacks_, OnCreateIncr).WillOnce(Return(kIncrPtr)); void* tls_state = nullptr; PERFETTO_DS_TRACE(data_source_2, ctx) { tls_state = PerfettoDsGetIncrementalState(&data_source_2, &ctx); } EXPECT_EQ(Ds2ActualCustomState(tls_state), kIncrPtr); tracing_session.StopBlocking(); EXPECT_CALL(ds2_callbacks_, OnDeleteIncr(kIncrPtr)); // The OnDelete callback will be called by // DestroyStoppedTraceWritersForCurrentThread(). One way to trigger that is to // trace with another data source. TracingSession tracing_session_1 = TracingSession::Builder().set_data_source_name(kDataSourceName1).Build(); PERFETTO_DS_TRACE(data_source_1, ctx) {} } TEST_F(SharedLibDataSourceTest, GetInstanceLockedSuccess) { bool ignored = false; void* const kInstancePtr = &ignored; EXPECT_CALL(ds2_callbacks_, OnSetup(_, _, _, _, kDataSource2UserArg, _)) .WillOnce(Return(kInstancePtr)); TracingSession tracing_session = TracingSession::Builder().set_data_source_name(kDataSourceName2).Build(); void* arg = nullptr; PERFETTO_DS_TRACE(data_source_2, ctx) { arg = PerfettoDsImplGetInstanceLocked(data_source_2.impl, ctx.impl.inst_id); if (arg) { PerfettoDsImplReleaseInstanceLocked(data_source_2.impl, ctx.impl.inst_id); } } EXPECT_EQ(arg, kInstancePtr); } TEST_F(SharedLibDataSourceTest, GetInstanceLockedFailure) { bool ignored = false; void* const kInstancePtr = &ignored; EXPECT_CALL(ds2_callbacks_, OnSetup(_, _, _, _, kDataSource2UserArg, _)) .WillOnce(Return(kInstancePtr)); TracingSession tracing_session = TracingSession::Builder().set_data_source_name(kDataSourceName2).Build(); WaitableEvent inside_tracing; WaitableEvent stopped; std::thread t([&] { PERFETTO_DS_TRACE(data_source_2, ctx) { inside_tracing.Notify(); stopped.WaitForNotification(); void* arg = PerfettoDsImplGetInstanceLocked(data_source_2.impl, ctx.impl.inst_id); if (arg) { PerfettoDsImplReleaseInstanceLocked(data_source_2.impl, ctx.impl.inst_id); } EXPECT_THAT(arg, IsNull()); } }); inside_tracing.WaitForNotification(); tracing_session.StopBlocking(); stopped.Notify(); t.join(); } // Regression test for a `PerfettoDsImplReleaseInstanceLocked()`. Under very // specific circumstances, that depends on the implementation details of // `TracingMuxerImpl`, the following events can happen: // * `PerfettoDsImplGetInstanceLocked()` is called after // `TracingMuxerImpl::StopDataSource_AsyncBeginImpl`, but before // `TracingMuxerImpl::StopDataSource_AsyncEnd`. // `PerfettoDsImplGetInstanceLocked()` succeeds and returns a valid instance. // * `TracingMuxerImpl::StopDataSource_AsyncEnd()` is called. // `DataSourceStaticState::valid_instances` is reset. // * `PerfettoDsImplReleaseInstanceLocked()` is called. // // In this case `PerfettoDsImplReleaseInstanceLocked()` should work even though // the instance is not there in the valid_instances bitmap anymore. // // In order to reproduce the specific failure, the test makes assumptions about // the internal implementation (that valid_instance is changed outside of the // lock). If that were to change and the test would fail, the test should be // changed/deleted. TEST_F(SharedLibDataSourceTest, GetInstanceLockedStopBeforeRelease) { bool ignored = false; void* const kInstancePtr = &ignored; EXPECT_CALL(ds2_callbacks_, OnSetup(_, _, _, _, kDataSource2UserArg, _)) .WillOnce(Return(kInstancePtr)); TracingSession tracing_session = TracingSession::Builder().set_data_source_name(kDataSourceName2).Build(); WaitableEvent inside_tracing; WaitableEvent stopping; WaitableEvent locked; WaitableEvent fully_stopped; std::thread t([&] { PERFETTO_DS_TRACE(data_source_2, ctx) { inside_tracing.Notify(); stopping.WaitForNotification(); void* arg = PerfettoDsImplGetInstanceLocked(data_source_2.impl, ctx.impl.inst_id); EXPECT_EQ(arg, kInstancePtr); locked.Notify(); fully_stopped.WaitForNotification(); if (arg) { PerfettoDsImplReleaseInstanceLocked(data_source_2.impl, ctx.impl.inst_id); } } }); inside_tracing.WaitForNotification(); struct PerfettoDsAsyncStopper* stopper = nullptr; EXPECT_CALL(ds2_callbacks_, OnStop(_, _, kDataSource2UserArg, _, _)) .WillOnce([&](struct PerfettoDsImpl*, PerfettoDsInstanceIndex, void*, void*, struct PerfettoDsOnStopArgs* args) { stopper = PerfettoDsOnStopArgsPostpone(args); stopping.Notify(); }); tracing_session.StopAsync(); locked.WaitForNotification(); PerfettoDsStopDone(stopper); // Wait for PerfettoDsImplTraceIterateBegin to return a nullptr tracer. This // means that the valid_instances bitmap has been reset. for (;;) { PerfettoDsImplTracerIterator iterator = PerfettoDsImplTraceIterateBegin(data_source_2.impl); if (iterator.tracer == nullptr) { break; } PerfettoDsImplTraceIterateBreak(data_source_2.impl, &iterator); std::this_thread::yield(); } fully_stopped.Notify(); tracing_session.WaitForStopped(); t.join(); } class SharedLibProducerTest : public testing::Test { protected: void SetUp() override { struct PerfettoProducerInitArgs args = PERFETTO_PRODUCER_INIT_ARGS_INIT(); args.backends = PERFETTO_BACKEND_IN_PROCESS; PerfettoProducerInit(args); } void TearDown() override { perfetto::shlib::ResetForTesting(); } }; TEST_F(SharedLibProducerTest, ActivateTriggers) { struct PerfettoPbMsgWriter writer; struct PerfettoHeapBuffer* hb = PerfettoHeapBufferCreate(&writer.writer); struct perfetto_protos_TraceConfig cfg; PerfettoPbMsgInit(&cfg.msg, &writer); { struct perfetto_protos_TraceConfig_BufferConfig buffers; perfetto_protos_TraceConfig_begin_buffers(&cfg, &buffers); perfetto_protos_TraceConfig_BufferConfig_set_size_kb(&buffers, 1024); perfetto_protos_TraceConfig_end_buffers(&cfg, &buffers); } { struct perfetto_protos_TraceConfig_TriggerConfig trigger_config; perfetto_protos_TraceConfig_begin_trigger_config(&cfg, &trigger_config); perfetto_protos_TraceConfig_TriggerConfig_set_trigger_mode( &trigger_config, perfetto_protos_TraceConfig_TriggerConfig_STOP_TRACING); perfetto_protos_TraceConfig_TriggerConfig_set_trigger_timeout_ms( &trigger_config, 5000); { struct perfetto_protos_TraceConfig_TriggerConfig_Trigger trigger; perfetto_protos_TraceConfig_TriggerConfig_begin_triggers(&trigger_config, &trigger); perfetto_protos_TraceConfig_TriggerConfig_Trigger_set_cstr_name( &trigger, "trigger1"); perfetto_protos_TraceConfig_TriggerConfig_end_triggers(&trigger_config, &trigger); } perfetto_protos_TraceConfig_end_trigger_config(&cfg, &trigger_config); } size_t cfg_size = PerfettoStreamWriterGetWrittenSize(&writer.writer); std::unique_ptr ser(new uint8_t[cfg_size]); PerfettoHeapBufferCopyInto(hb, &writer.writer, ser.get(), cfg_size); PerfettoHeapBufferDestroy(hb, &writer.writer); struct PerfettoTracingSessionImpl* ts = PerfettoTracingSessionCreate(PERFETTO_BACKEND_IN_PROCESS); PerfettoTracingSessionSetup(ts, ser.get(), cfg_size); PerfettoTracingSessionStartBlocking(ts); TracingSession tracing_session = TracingSession::Adopt(ts); const char* triggers[3]; triggers[0] = "trigger0"; triggers[1] = "trigger1"; triggers[2] = nullptr; PerfettoProducerActivateTriggers(triggers, 10000); tracing_session.WaitForStopped(); std::vector data = tracing_session.ReadBlocking(); EXPECT_THAT(FieldView(data), Contains(PbField( perfetto_protos_Trace_packet_field_number, MsgField(Contains(PbField( perfetto_protos_TracePacket_trigger_field_number, MsgField(Contains(PbField( perfetto_protos_Trigger_trigger_name_field_number, StringField("trigger1")))))))))); } class SharedLibTrackEventTest : public testing::Test { protected: void SetUp() override { struct PerfettoProducerInitArgs args = PERFETTO_PRODUCER_INIT_ARGS_INIT(); args.backends = PERFETTO_BACKEND_IN_PROCESS; PerfettoProducerInit(args); PerfettoTeInit(); PERFETTO_TE_REGISTER_CATEGORIES(TEST_CATEGORIES); } void TearDown() override { PERFETTO_TE_UNREGISTER_CATEGORIES(TEST_CATEGORIES); perfetto::shlib::ResetForTesting(); } }; TEST_F(SharedLibTrackEventTest, TrackEventFastpathOtherDsCatDisabled) { TracingSession tracing_session = TracingSession::Builder() .set_data_source_name("other_nonexisting_datasource") .Build(); EXPECT_FALSE(std::atomic_load(cat1.enabled)); EXPECT_FALSE(std::atomic_load(cat2.enabled)); EXPECT_FALSE(std::atomic_load(cat3.enabled)); } TEST_F(SharedLibTrackEventTest, TrackEventFastpathEmptyConfigDisablesAllCats) { ASSERT_FALSE(std::atomic_load(cat1.enabled)); ASSERT_FALSE(std::atomic_load(cat2.enabled)); ASSERT_FALSE(std::atomic_load(cat3.enabled)); TracingSession tracing_session = TracingSession::Builder().set_data_source_name("track_event").Build(); EXPECT_FALSE(std::atomic_load(cat1.enabled)); EXPECT_FALSE(std::atomic_load(cat2.enabled)); EXPECT_FALSE(std::atomic_load(cat3.enabled)); } TEST_F(SharedLibTrackEventTest, TrackEventFastpathOneCatEnabled) { ASSERT_FALSE(std::atomic_load(cat1.enabled)); ASSERT_FALSE(std::atomic_load(cat2.enabled)); ASSERT_FALSE(std::atomic_load(cat3.enabled)); TracingSession tracing_session = TracingSession::Builder() .set_data_source_name("track_event") .add_enabled_category("cat1") .add_disabled_category("*") .Build(); EXPECT_TRUE(std::atomic_load(cat1.enabled)); EXPECT_FALSE(std::atomic_load(cat2.enabled)); EXPECT_FALSE(std::atomic_load(cat3.enabled)); } TEST_F(SharedLibTrackEventTest, TrackEventHlCategory) { TracingSession tracing_session = TracingSession::Builder() .set_data_source_name("track_event") .add_enabled_category("*") .Build(); EXPECT_TRUE(std::atomic_load(cat1.enabled)); PERFETTO_TE(cat1, PERFETTO_TE_INSTANT("")); tracing_session.StopBlocking(); std::vector data = tracing_session.ReadBlocking(); bool found = false; for (struct PerfettoPbDecoderField trace_field : FieldView(data)) { ASSERT_THAT(trace_field, PbField(perfetto_protos_Trace_packet_field_number, MsgField(_))); IdFieldView track_event( trace_field, perfetto_protos_TracePacket_track_event_field_number); if (track_event.size() == 0) { continue; } found = true; IdFieldView cat_iid_fields( track_event.front(), perfetto_protos_TrackEvent_category_iids_field_number); ASSERT_THAT(cat_iid_fields, ElementsAre(VarIntField(_))); uint64_t cat_iid = cat_iid_fields.front().value.integer64; EXPECT_THAT( trace_field, AllFieldsWithId( perfetto_protos_TracePacket_interned_data_field_number, ElementsAre(AllFieldsWithId( perfetto_protos_InternedData_event_categories_field_number, ElementsAre(MsgField(UnorderedElementsAre( PbField(perfetto_protos_EventCategory_iid_field_number, VarIntField(cat_iid)), PbField(perfetto_protos_EventCategory_name_field_number, StringField("cat1"))))))))); } EXPECT_TRUE(found); } TEST_F(SharedLibTrackEventTest, TrackEventHlDynamicCategory) { TracingSession tracing_session = TracingSession::Builder() .set_data_source_name("track_event") .add_enabled_category("dyn1") .add_enabled_category("cat1") .add_disabled_category("*") .Build(); PERFETTO_TE(PERFETTO_TE_DYNAMIC_CATEGORY, PERFETTO_TE_INSTANT(""), PERFETTO_TE_DYNAMIC_CATEGORY_STRING("dyn2")); PERFETTO_TE(PERFETTO_TE_DYNAMIC_CATEGORY, PERFETTO_TE_INSTANT(""), PERFETTO_TE_DYNAMIC_CATEGORY_STRING("dyn1")); tracing_session.StopBlocking(); std::vector data = tracing_session.ReadBlocking(); bool found = false; for (struct PerfettoPbDecoderField trace_field : FieldView(data)) { ASSERT_THAT(trace_field, PbField(perfetto_protos_Trace_packet_field_number, MsgField(_))); IdFieldView track_event( trace_field, perfetto_protos_TracePacket_track_event_field_number); if (track_event.size() == 0) { continue; } found = true; EXPECT_THAT(track_event, ElementsAre(AllFieldsWithId( perfetto_protos_TrackEvent_categories_field_number, ElementsAre(StringField("dyn1"))))); } EXPECT_TRUE(found); } TEST_F(SharedLibTrackEventTest, TrackEventHlDynamicCategoryMultipleSessions) { TracingSession tracing_session1 = TracingSession::Builder() .set_data_source_name("track_event") .add_enabled_category("cat1") .add_enabled_category("dyn1") .add_disabled_category("dyn2") .add_disabled_category("*") .Build(); TracingSession tracing_session2 = TracingSession::Builder() .set_data_source_name("track_event") .add_enabled_category("cat1") .add_enabled_category("dyn2") .add_disabled_category("dyn1") .add_disabled_category("*") .Build(); PERFETTO_TE(PERFETTO_TE_DYNAMIC_CATEGORY, PERFETTO_TE_INSTANT("interned_string"), PERFETTO_TE_DYNAMIC_CATEGORY_STRING("dyn1")); PERFETTO_TE(PERFETTO_TE_DYNAMIC_CATEGORY, PERFETTO_TE_INSTANT("interned_string"), PERFETTO_TE_DYNAMIC_CATEGORY_STRING("dyn2")); PERFETTO_TE(cat1, PERFETTO_TE_INSTANT("")); tracing_session1.StopBlocking(); std::vector data1 = tracing_session1.ReadBlocking(); EXPECT_THAT( FieldView(data1), Contains(PbField( perfetto_protos_Trace_packet_field_number, MsgField(AllOf( Contains(PbField( perfetto_protos_TracePacket_track_event_field_number, MsgField(Contains(PbField( perfetto_protos_TrackEvent_categories_field_number, StringField("dyn1")))))), Contains(PbField( perfetto_protos_TracePacket_interned_data_field_number, MsgField(Contains(PbField( perfetto_protos_InternedData_event_names_field_number, MsgField(Contains( PbField(perfetto_protos_EventName_name_field_number, StringField("interned_string")))))))))))))); tracing_session2.StopBlocking(); std::vector data2 = tracing_session2.ReadBlocking(); EXPECT_THAT( FieldView(data2), Contains(PbField( perfetto_protos_Trace_packet_field_number, MsgField(AllOf( Contains(PbField( perfetto_protos_TracePacket_track_event_field_number, MsgField(Contains(PbField( perfetto_protos_TrackEvent_categories_field_number, StringField("dyn2")))))), Contains(PbField( perfetto_protos_TracePacket_interned_data_field_number, MsgField(Contains(PbField( perfetto_protos_InternedData_event_names_field_number, MsgField(Contains( PbField(perfetto_protos_EventName_name_field_number, StringField("interned_string")))))))))))))); } TEST_F(SharedLibTrackEventTest, TrackEventHlInstant) { TracingSession tracing_session = TracingSession::Builder() .set_data_source_name("track_event") .add_enabled_category("*") .Build(); PERFETTO_TE(cat1, PERFETTO_TE_INSTANT("event")); tracing_session.StopBlocking(); std::vector data = tracing_session.ReadBlocking(); bool found = false; for (struct PerfettoPbDecoderField trace_field : FieldView(data)) { ASSERT_THAT(trace_field, PbField(perfetto_protos_Trace_packet_field_number, MsgField(_))); IdFieldView track_event( trace_field, perfetto_protos_TracePacket_track_event_field_number); if (track_event.size() == 0) { continue; } found = true; ASSERT_THAT(track_event, ElementsAre(AllFieldsWithId( perfetto_protos_TrackEvent_type_field_number, ElementsAre(VarIntField( perfetto_protos_TrackEvent_TYPE_INSTANT))))); IdFieldView name_iid_fields( track_event.front(), perfetto_protos_TrackEvent_name_iid_field_number); ASSERT_THAT(name_iid_fields, ElementsAre(VarIntField(_))); uint64_t name_iid = name_iid_fields.front().value.integer64; EXPECT_THAT(trace_field, AllFieldsWithId( perfetto_protos_TracePacket_interned_data_field_number, ElementsAre(AllFieldsWithId( perfetto_protos_InternedData_event_names_field_number, ElementsAre(MsgField(UnorderedElementsAre( PbField(perfetto_protos_EventName_iid_field_number, VarIntField(name_iid)), PbField(perfetto_protos_EventName_name_field_number, StringField("event"))))))))); } EXPECT_TRUE(found); } TEST_F(SharedLibTrackEventTest, TrackEventLlInstant) { TracingSession tracing_session = TracingSession::Builder() .set_data_source_name("track_event") .add_enabled_category("*") .Build(); if (PERFETTO_UNLIKELY(PERFETTO_ATOMIC_LOAD_EXPLICIT( cat1.enabled, PERFETTO_MEMORY_ORDER_RELAXED))) { struct PerfettoTeTimestamp timestamp = PerfettoTeGetTimestamp(); int32_t type = PERFETTO_TE_TYPE_INSTANT; const char* name = "event"; for (struct PerfettoTeLlIterator ctx = PerfettoTeLlBeginSlowPath(&cat1, timestamp); ctx.impl.ds.tracer != nullptr; PerfettoTeLlNext(&cat1, timestamp, &ctx)) { uint64_t name_iid; { struct PerfettoDsRootTracePacket trace_packet; PerfettoTeLlPacketBegin(&ctx, &trace_packet); PerfettoTeLlWriteTimestamp(&trace_packet.msg, ×tamp); perfetto_protos_TracePacket_set_sequence_flags( &trace_packet.msg, perfetto_protos_TracePacket_SEQ_NEEDS_INCREMENTAL_STATE); { struct PerfettoTeLlInternContext intern_ctx; PerfettoTeLlInternContextInit(&intern_ctx, ctx.impl.incr, &trace_packet.msg); PerfettoTeLlInternRegisteredCat(&intern_ctx, &cat1); name_iid = PerfettoTeLlInternEventName(&intern_ctx, name); PerfettoTeLlInternContextDestroy(&intern_ctx); } { struct perfetto_protos_TrackEvent te_msg; perfetto_protos_TracePacket_begin_track_event(&trace_packet.msg, &te_msg); perfetto_protos_TrackEvent_set_type( &te_msg, static_cast(type)); PerfettoTeLlWriteRegisteredCat(&te_msg, &cat1); PerfettoTeLlWriteInternedEventName(&te_msg, name_iid); perfetto_protos_TracePacket_end_track_event(&trace_packet.msg, &te_msg); } PerfettoTeLlPacketEnd(&ctx, &trace_packet); } } } tracing_session.StopBlocking(); std::vector data = tracing_session.ReadBlocking(); bool found = false; for (struct PerfettoPbDecoderField trace_field : FieldView(data)) { ASSERT_THAT(trace_field, PbField(perfetto_protos_Trace_packet_field_number, MsgField(_))); IdFieldView track_event( trace_field, perfetto_protos_TracePacket_track_event_field_number); if (track_event.size() == 0) { continue; } found = true; ASSERT_THAT(track_event, ElementsAre(AllFieldsWithId( perfetto_protos_TrackEvent_type_field_number, ElementsAre(VarIntField( perfetto_protos_TrackEvent_TYPE_INSTANT))))); IdFieldView name_iid_fields( track_event.front(), perfetto_protos_TrackEvent_name_iid_field_number); ASSERT_THAT(name_iid_fields, ElementsAre(VarIntField(_))); uint64_t name_iid = name_iid_fields.front().value.integer64; EXPECT_THAT(trace_field, AllFieldsWithId( perfetto_protos_TracePacket_interned_data_field_number, ElementsAre(AllFieldsWithId( perfetto_protos_InternedData_event_names_field_number, ElementsAre(MsgField(UnorderedElementsAre( PbField(perfetto_protos_EventName_iid_field_number, VarIntField(name_iid)), PbField(perfetto_protos_EventName_name_field_number, StringField("event"))))))))); } EXPECT_TRUE(found); } TEST_F(SharedLibTrackEventTest, TrackEventHlInstantNoIntern) { TracingSession tracing_session = TracingSession::Builder() .set_data_source_name("track_event") .add_enabled_category("*") .Build(); PERFETTO_TE(cat1, PERFETTO_TE_INSTANT("event"), PERFETTO_TE_NO_INTERN()); tracing_session.StopBlocking(); std::vector data = tracing_session.ReadBlocking(); bool found = false; for (struct PerfettoPbDecoderField trace_field : FieldView(data)) { ASSERT_THAT(trace_field, PbField(perfetto_protos_Trace_packet_field_number, MsgField(_))); IdFieldView track_event( trace_field, perfetto_protos_TracePacket_track_event_field_number); if (track_event.size() == 0) { continue; } found = true; ASSERT_THAT( track_event, ElementsAre(AllOf( AllFieldsWithId(perfetto_protos_TrackEvent_type_field_number, ElementsAre(VarIntField( perfetto_protos_TrackEvent_TYPE_INSTANT))), AllFieldsWithId(perfetto_protos_TrackEvent_name_field_number, ElementsAre(StringField("event")))))); } EXPECT_TRUE(found); } TEST_F(SharedLibTrackEventTest, TrackEventHlDbgArg) { TracingSession tracing_session = TracingSession::Builder() .set_data_source_name("track_event") .add_enabled_category("*") .Build(); PERFETTO_TE(cat1, PERFETTO_TE_INSTANT("event"), PERFETTO_TE_ARG_UINT64("arg_name", 42)); tracing_session.StopBlocking(); std::vector data = tracing_session.ReadBlocking(); bool found = false; for (struct PerfettoPbDecoderField trace_field : FieldView(data)) { ASSERT_THAT(trace_field, PbField(perfetto_protos_Trace_packet_field_number, MsgField(_))); IdFieldView track_event( trace_field, perfetto_protos_TracePacket_track_event_field_number); if (track_event.size() == 0) { continue; } found = true; ASSERT_THAT(track_event, ElementsAre(AllFieldsWithId( perfetto_protos_TrackEvent_type_field_number, ElementsAre(VarIntField( perfetto_protos_TrackEvent_TYPE_INSTANT))))); IdFieldView name_iid_fields( track_event.front(), perfetto_protos_TrackEvent_name_iid_field_number); ASSERT_THAT(name_iid_fields, ElementsAre(VarIntField(_))); uint64_t name_iid = name_iid_fields.front().value.integer64; IdFieldView debug_annot_fields( track_event.front(), perfetto_protos_TrackEvent_debug_annotations_field_number); ASSERT_THAT( debug_annot_fields, ElementsAre(MsgField(UnorderedElementsAre( PbField(perfetto_protos_DebugAnnotation_name_iid_field_number, VarIntField(_)), PbField(perfetto_protos_DebugAnnotation_uint_value_field_number, VarIntField(42)))))); uint64_t arg_name_iid = IdFieldView(debug_annot_fields.front(), perfetto_protos_DebugAnnotation_name_iid_field_number) .front() .value.integer64; EXPECT_THAT( trace_field, AllFieldsWithId( perfetto_protos_TracePacket_interned_data_field_number, ElementsAre(AllOf( AllFieldsWithId( perfetto_protos_InternedData_event_names_field_number, ElementsAre(MsgField(UnorderedElementsAre( PbField(perfetto_protos_EventName_iid_field_number, VarIntField(name_iid)), PbField(perfetto_protos_EventName_name_field_number, StringField("event")))))), AllFieldsWithId( perfetto_protos_InternedData_debug_annotation_names_field_number, ElementsAre(MsgField(UnorderedElementsAre( PbField( perfetto_protos_DebugAnnotationName_iid_field_number, VarIntField(arg_name_iid)), PbField( perfetto_protos_DebugAnnotationName_name_field_number, StringField("arg_name")))))))))); } EXPECT_TRUE(found); } TEST_F(SharedLibTrackEventTest, TrackEventHlNamedTrack) { TracingSession tracing_session = TracingSession::Builder() .set_data_source_name("track_event") .add_enabled_category("*") .Build(); PERFETTO_TE(cat1, PERFETTO_TE_INSTANT("event"), PERFETTO_TE_NAMED_TRACK("MyTrack", 1, 2)); uint64_t kExpectedUuid = PerfettoTeNamedTrackUuid("MyTrack", 1, 2); tracing_session.StopBlocking(); std::vector data = tracing_session.ReadBlocking(); EXPECT_THAT( FieldView(data), AllOf( Contains(PbField( perfetto_protos_Trace_packet_field_number, AllFieldsWithId( perfetto_protos_TracePacket_track_descriptor_field_number, ElementsAre(MsgField(UnorderedElementsAre( PbField(perfetto_protos_TrackDescriptor_uuid_field_number, VarIntField(kExpectedUuid)), PbField(perfetto_protos_TrackDescriptor_name_field_number, StringField("MyTrack")), PbField( perfetto_protos_TrackDescriptor_parent_uuid_field_number, VarIntField(2)))))))), Contains(PbField( perfetto_protos_Trace_packet_field_number, AllFieldsWithId( perfetto_protos_TracePacket_track_event_field_number, ElementsAre(AllOf( AllFieldsWithId( perfetto_protos_TrackEvent_type_field_number, ElementsAre(VarIntField( perfetto_protos_TrackEvent_TYPE_INSTANT))), AllFieldsWithId( perfetto_protos_TrackEvent_track_uuid_field_number, ElementsAre(VarIntField(kExpectedUuid)))))))))); } TEST_F(SharedLibTrackEventTest, TrackEventHlRegisteredCounter) { TracingSession tracing_session = TracingSession::Builder() .set_data_source_name("track_event") .add_enabled_category("*") .Build(); PerfettoTeRegisteredTrack my_counter_track; PerfettoTeCounterTrackRegister(&my_counter_track, "MyCounter", PerfettoTeProcessTrackUuid()); PERFETTO_TE(cat1, PERFETTO_TE_COUNTER(), PERFETTO_TE_REGISTERED_TRACK(&my_counter_track), PERFETTO_TE_INT_COUNTER(42)); PerfettoTeRegisteredTrackUnregister(&my_counter_track); uint64_t kExpectedUuid = PerfettoTeCounterTrackUuid("MyCounter", PerfettoTeProcessTrackUuid()); tracing_session.StopBlocking(); std::vector data = tracing_session.ReadBlocking(); EXPECT_THAT( FieldView(data), AllOf( Contains(PbField( perfetto_protos_Trace_packet_field_number, AllFieldsWithId( perfetto_protos_TracePacket_track_descriptor_field_number, ElementsAre(MsgField(UnorderedElementsAre( PbField(perfetto_protos_TrackDescriptor_uuid_field_number, VarIntField(kExpectedUuid)), PbField(perfetto_protos_TrackDescriptor_name_field_number, StringField("MyCounter")), PbField( perfetto_protos_TrackDescriptor_parent_uuid_field_number, VarIntField(PerfettoTeProcessTrackUuid())), PbField( perfetto_protos_TrackDescriptor_counter_field_number, MsgField(_)))))))), Contains(PbField( perfetto_protos_Trace_packet_field_number, AllFieldsWithId( perfetto_protos_TracePacket_track_event_field_number, ElementsAre(AllOf( AllFieldsWithId( perfetto_protos_TrackEvent_type_field_number, ElementsAre(VarIntField( perfetto_protos_TrackEvent_TYPE_COUNTER))), AllFieldsWithId( perfetto_protos_TrackEvent_counter_value_field_number, ElementsAre(VarIntField(42))), AllFieldsWithId( perfetto_protos_TrackEvent_track_uuid_field_number, ElementsAre(VarIntField(kExpectedUuid)))))))))); } TEST_F(SharedLibTrackEventTest, Scoped) { TracingSession tracing_session = TracingSession::Builder() .set_data_source_name("track_event") .add_enabled_category("*") .Build(); { PERFETTO_TE_SCOPED(cat1, PERFETTO_TE_SLICE("slice"), PERFETTO_TE_ARG_UINT64("arg_name", 42)); PERFETTO_TE(cat1, PERFETTO_TE_INSTANT("event")); } tracing_session.StopBlocking(); std::vector data = tracing_session.ReadBlocking(); auto trace_view = FieldView(data); auto it = trace_view.begin(); for (; it != trace_view.end(); it++) { struct PerfettoPbDecoderField trace_field = *it; ASSERT_THAT(trace_field, PbField(perfetto_protos_Trace_packet_field_number, MsgField(_))); IdFieldView track_event( trace_field, perfetto_protos_TracePacket_track_event_field_number); if (track_event.size() == 0) { continue; } ASSERT_THAT(track_event, ElementsAre(AllFieldsWithId( perfetto_protos_TrackEvent_type_field_number, ElementsAre(VarIntField( perfetto_protos_TrackEvent_TYPE_SLICE_BEGIN))))); IdFieldView name_iid_fields( track_event.front(), perfetto_protos_TrackEvent_name_iid_field_number); ASSERT_THAT(name_iid_fields, ElementsAre(VarIntField(_))); uint64_t name_iid = name_iid_fields.front().value.integer64; IdFieldView debug_annot_fields( track_event.front(), perfetto_protos_TrackEvent_debug_annotations_field_number); ASSERT_THAT( debug_annot_fields, ElementsAre(MsgField(UnorderedElementsAre( PbField(perfetto_protos_DebugAnnotation_name_iid_field_number, VarIntField(_)), PbField(perfetto_protos_DebugAnnotation_uint_value_field_number, VarIntField(42)))))); uint64_t arg_name_iid = IdFieldView(debug_annot_fields.front(), perfetto_protos_DebugAnnotation_name_iid_field_number) .front() .value.integer64; EXPECT_THAT( trace_field, AllFieldsWithId( perfetto_protos_TracePacket_interned_data_field_number, ElementsAre(AllOf( AllFieldsWithId( perfetto_protos_InternedData_event_names_field_number, ElementsAre(MsgField(UnorderedElementsAre( PbField(perfetto_protos_EventName_iid_field_number, VarIntField(name_iid)), PbField(perfetto_protos_EventName_name_field_number, StringField("slice")))))), AllFieldsWithId( perfetto_protos_InternedData_debug_annotation_names_field_number, ElementsAre(MsgField(UnorderedElementsAre( PbField( perfetto_protos_DebugAnnotationName_iid_field_number, VarIntField(arg_name_iid)), PbField( perfetto_protos_DebugAnnotationName_name_field_number, StringField("arg_name")))))))))); it++; break; } ASSERT_NE(it, trace_view.end()); for (; it != trace_view.end(); it++) { struct PerfettoPbDecoderField trace_field = *it; ASSERT_THAT(trace_field, PbField(perfetto_protos_Trace_packet_field_number, MsgField(_))); IdFieldView track_event( trace_field, perfetto_protos_TracePacket_track_event_field_number); if (track_event.size() == 0) { continue; } ASSERT_THAT(track_event, ElementsAre(AllFieldsWithId( perfetto_protos_TrackEvent_type_field_number, ElementsAre(VarIntField( perfetto_protos_TrackEvent_TYPE_INSTANT))))); IdFieldView name_iid_fields( track_event.front(), perfetto_protos_TrackEvent_name_iid_field_number); ASSERT_THAT(name_iid_fields, ElementsAre(VarIntField(_))); uint64_t name_iid = name_iid_fields.front().value.integer64; EXPECT_THAT(trace_field, AllFieldsWithId( perfetto_protos_TracePacket_interned_data_field_number, ElementsAre(AllFieldsWithId( perfetto_protos_InternedData_event_names_field_number, ElementsAre(MsgField(UnorderedElementsAre( PbField(perfetto_protos_EventName_iid_field_number, VarIntField(name_iid)), PbField(perfetto_protos_EventName_name_field_number, StringField("event"))))))))); it++; break; } ASSERT_NE(it, trace_view.end()); for (; it != trace_view.end(); it++) { struct PerfettoPbDecoderField trace_field = *it; ASSERT_THAT(trace_field, PbField(perfetto_protos_Trace_packet_field_number, MsgField(_))); IdFieldView track_event( trace_field, perfetto_protos_TracePacket_track_event_field_number); if (track_event.size() == 0) { continue; } ASSERT_THAT(track_event, ElementsAre(AllFieldsWithId( perfetto_protos_TrackEvent_type_field_number, ElementsAre(VarIntField( perfetto_protos_TrackEvent_TYPE_SLICE_END))))); IdFieldView debug_annot_fields( track_event.front(), perfetto_protos_TrackEvent_debug_annotations_field_number); ASSERT_THAT(debug_annot_fields, ElementsAre()); it++; break; } } TEST_F(SharedLibTrackEventTest, ScopedDisabled) { TracingSession tracing_session = TracingSession::Builder() .set_data_source_name("track_event") .add_disabled_category("cat1") .Build(); // Check that the PERFETTO_TE_SCOPED macro does not have any effect if the // category is disabled. { PERFETTO_TE_SCOPED(cat1, PERFETTO_TE_SLICE("slice")); } tracing_session.StopBlocking(); std::vector data = tracing_session.ReadBlocking(); auto trace_view = FieldView(data); auto it = trace_view.begin(); for (; it != trace_view.end(); it++) { struct PerfettoPbDecoderField trace_field = *it; ASSERT_THAT(trace_field, PbField(perfetto_protos_Trace_packet_field_number, MsgField(_))); IdFieldView track_event( trace_field, perfetto_protos_TracePacket_track_event_field_number); ASSERT_EQ(track_event.size(), 0u); } } TEST_F(SharedLibTrackEventTest, ScopedSingleLine) { TracingSession tracing_session = TracingSession::Builder() .set_data_source_name("track_event") .add_enabled_category("*") .Build(); // Check that the PERFETTO_TE_SCOPED macro is expanded into a single // statement. Emitting the end event should not escape if (false) PERFETTO_TE_SCOPED(cat1, PERFETTO_TE_SLICE("slice")); tracing_session.StopBlocking(); std::vector data = tracing_session.ReadBlocking(); auto trace_view = FieldView(data); auto it = trace_view.begin(); for (; it != trace_view.end(); it++) { struct PerfettoPbDecoderField trace_field = *it; ASSERT_THAT(trace_field, PbField(perfetto_protos_Trace_packet_field_number, MsgField(_))); IdFieldView track_event( trace_field, perfetto_protos_TracePacket_track_event_field_number); ASSERT_EQ(track_event.size(), 0u); } } TEST_F(SharedLibTrackEventTest, ScopedCapture) { TracingSession tracing_session = TracingSession::Builder() .set_data_source_name("track_event") .add_enabled_category("*") .Build(); // Check that the PERFETTO_TE_SCOPED macro can capture variables. uint64_t value = 42; { PERFETTO_TE_SCOPED(cat1, PERFETTO_TE_SLICE("slice"), PERFETTO_TE_ARG_UINT64("arg_name", value)); } tracing_session.StopBlocking(); std::vector data = tracing_session.ReadBlocking(); auto trace_view = FieldView(data); auto it = trace_view.begin(); for (; it != trace_view.end(); it++) { struct PerfettoPbDecoderField trace_field = *it; ASSERT_THAT(trace_field, PbField(perfetto_protos_Trace_packet_field_number, MsgField(_))); IdFieldView track_event( trace_field, perfetto_protos_TracePacket_track_event_field_number); if (track_event.size() == 0) { continue; } ASSERT_THAT(track_event, ElementsAre(AllFieldsWithId( perfetto_protos_TrackEvent_type_field_number, ElementsAre(VarIntField( perfetto_protos_TrackEvent_TYPE_SLICE_BEGIN))))); IdFieldView name_iid_fields( track_event.front(), perfetto_protos_TrackEvent_name_iid_field_number); ASSERT_THAT(name_iid_fields, ElementsAre(VarIntField(_))); uint64_t name_iid = name_iid_fields.front().value.integer64; IdFieldView debug_annot_fields( track_event.front(), perfetto_protos_TrackEvent_debug_annotations_field_number); ASSERT_THAT( debug_annot_fields, ElementsAre(MsgField(UnorderedElementsAre( PbField(perfetto_protos_DebugAnnotation_name_iid_field_number, VarIntField(_)), PbField(perfetto_protos_DebugAnnotation_uint_value_field_number, VarIntField(42)))))); uint64_t arg_name_iid = IdFieldView(debug_annot_fields.front(), perfetto_protos_DebugAnnotation_name_iid_field_number) .front() .value.integer64; EXPECT_THAT( trace_field, AllFieldsWithId( perfetto_protos_TracePacket_interned_data_field_number, ElementsAre(AllOf( AllFieldsWithId( perfetto_protos_InternedData_event_names_field_number, ElementsAre(MsgField(UnorderedElementsAre( PbField(perfetto_protos_EventName_iid_field_number, VarIntField(name_iid)), PbField(perfetto_protos_EventName_name_field_number, StringField("slice")))))), AllFieldsWithId( perfetto_protos_InternedData_debug_annotation_names_field_number, ElementsAre(MsgField(UnorderedElementsAre( PbField( perfetto_protos_DebugAnnotationName_iid_field_number, VarIntField(arg_name_iid)), PbField( perfetto_protos_DebugAnnotationName_name_field_number, StringField("arg_name")))))))))); it++; break; } ASSERT_NE(it, trace_view.end()); for (; it != trace_view.end(); it++) { struct PerfettoPbDecoderField trace_field = *it; ASSERT_THAT(trace_field, PbField(perfetto_protos_Trace_packet_field_number, MsgField(_))); IdFieldView track_event( trace_field, perfetto_protos_TracePacket_track_event_field_number); if (track_event.size() == 0) { continue; } ASSERT_THAT(track_event, ElementsAre(AllFieldsWithId( perfetto_protos_TrackEvent_type_field_number, ElementsAre(VarIntField( perfetto_protos_TrackEvent_TYPE_SLICE_END))))); IdFieldView debug_annot_fields( track_event.front(), perfetto_protos_TrackEvent_debug_annotations_field_number); ASSERT_THAT(debug_annot_fields, ElementsAre()); it++; break; } } TEST_F(SharedLibTrackEventTest, ScopedFunc) { TracingSession tracing_session = TracingSession::Builder() .set_data_source_name("track_event") .add_enabled_category("*") .Build(); // Check that using __func__ works as expected. { PERFETTO_TE_SCOPED(cat1, PERFETTO_TE_SLICE(__func__)); } tracing_session.StopBlocking(); std::vector data = tracing_session.ReadBlocking(); auto trace_view = FieldView(data); auto it = trace_view.begin(); for (; it != trace_view.end(); it++) { struct PerfettoPbDecoderField trace_field = *it; ASSERT_THAT(trace_field, PbField(perfetto_protos_Trace_packet_field_number, MsgField(_))); IdFieldView track_event( trace_field, perfetto_protos_TracePacket_track_event_field_number); if (track_event.size() == 0) { continue; } ASSERT_THAT(track_event, ElementsAre(AllFieldsWithId( perfetto_protos_TrackEvent_type_field_number, ElementsAre(VarIntField( perfetto_protos_TrackEvent_TYPE_SLICE_BEGIN))))); IdFieldView name_iid_fields( track_event.front(), perfetto_protos_TrackEvent_name_iid_field_number); ASSERT_THAT(name_iid_fields, ElementsAre(VarIntField(_))); uint64_t name_iid = name_iid_fields.front().value.integer64; EXPECT_THAT(trace_field, AllFieldsWithId( perfetto_protos_TracePacket_interned_data_field_number, ElementsAre(AllFieldsWithId( perfetto_protos_InternedData_event_names_field_number, ElementsAre(MsgField(UnorderedElementsAre( PbField(perfetto_protos_EventName_iid_field_number, VarIntField(name_iid)), PbField(perfetto_protos_EventName_name_field_number, StringField(__func__))))))))); it++; break; } ASSERT_NE(it, trace_view.end()); for (; it != trace_view.end(); it++) { struct PerfettoPbDecoderField trace_field = *it; ASSERT_THAT(trace_field, PbField(perfetto_protos_Trace_packet_field_number, MsgField(_))); IdFieldView track_event( trace_field, perfetto_protos_TracePacket_track_event_field_number); if (track_event.size() == 0) { continue; } ASSERT_THAT(track_event, ElementsAre(AllFieldsWithId( perfetto_protos_TrackEvent_type_field_number, ElementsAre(VarIntField( perfetto_protos_TrackEvent_TYPE_SLICE_END))))); IdFieldView debug_annot_fields( track_event.front(), perfetto_protos_TrackEvent_debug_annotations_field_number); ASSERT_THAT(debug_annot_fields, ElementsAre()); it++; break; } } TEST_F(SharedLibTrackEventTest, TrackEventHlProtoFieldString) { TracingSession tracing_session = TracingSession::Builder() .set_data_source_name("track_event") .add_enabled_category("*") .Build(); PERFETTO_TE( cat1, PERFETTO_TE_INSTANT("event"), PERFETTO_TE_PROTO_FIELDS(PERFETTO_TE_PROTO_FIELD_NESTED( perfetto_protos_TrackEvent_debug_annotations_field_number, PERFETTO_TE_PROTO_FIELD_CSTR( perfetto_protos_DebugAnnotation_name_field_number, "name"), PERFETTO_TE_PROTO_FIELD_VARINT( perfetto_protos_DebugAnnotation_uint_value_field_number, 42)))); tracing_session.StopBlocking(); std::vector data = tracing_session.ReadBlocking(); EXPECT_THAT( FieldView(data), Contains(PbField( perfetto_protos_Trace_packet_field_number, AllFieldsWithId( perfetto_protos_TracePacket_track_event_field_number, ElementsAre(AllFieldsWithId( perfetto_protos_TrackEvent_debug_annotations_field_number, ElementsAre(MsgField(UnorderedElementsAre( PbField(perfetto_protos_DebugAnnotation_name_field_number, StringField("name")), PbField( perfetto_protos_DebugAnnotation_uint_value_field_number, VarIntField(42))))))))))); } } // namespace