| /* |
| * 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 <thread> |
| |
| #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::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<void*>(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<const char*>( |
| 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<uint8_t> GetData() { |
| std::vector<uint8_t> 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 <typename T> |
| static std::vector<T> ParsePackedVarInt(const std::string& data) { |
| std::vector<T> ret; |
| const uint8_t* read_ptr = reinterpret_cast<const uint8_t*>(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<T>(val)); |
| } |
| return ret; |
| } |
| |
| template <typename T> |
| static std::vector<T> ParsePackedFixed(const std::string& data) { |
| std::vector<T> ret; |
| if (data.size() % sizeof(T)) { |
| ADD_FAILURE(); |
| return ret; |
| } |
| const uint8_t* read_ptr = reinterpret_cast<const uint8_t*>(data.data()); |
| const uint8_t* end = read_ptr + data.size(); |
| while (read_ptr < end) { |
| ret.push_back(*reinterpret_cast<const T*>(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<uint64_t>(-1))), |
| PbField(protozero_test_protos_EveryField_field_int64_field_number, |
| VarIntField(static_cast<uint64_t>(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<uint32_t>(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<uint32_t>(-69999))), |
| PbField(protozero_test_protos_EveryField_field_sfixed64_field_number, |
| Fixed64Field(static_cast<uint64_t>(-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<uint64_t>(-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<int32_t>, |
| ElementsAre(42, 255, -1)))), |
| PbField( |
| protozero_test_protos_PackedRepeatedFields_field_int64_field_number, |
| StringField(ResultOf( |
| ParsePackedVarInt<int64_t>, |
| ElementsAre(INT64_C(3000000000), INT64_C(-3000000000))))), |
| PbField( |
| protozero_test_protos_PackedRepeatedFields_field_uint32_field_number, |
| StringField(ResultOf(ParsePackedVarInt<uint32_t>, |
| ElementsAre(42, UINT32_C(3000000000))))), |
| PbField( |
| protozero_test_protos_PackedRepeatedFields_field_uint64_field_number, |
| StringField(ResultOf(ParsePackedVarInt<uint64_t>, |
| ElementsAre(42, UINT64_C(5000000000))))), |
| PbField( |
| protozero_test_protos_PackedRepeatedFields_signed_enum_field_number, |
| StringField( |
| ResultOf(ParsePackedVarInt<int32_t>, |
| 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<uint32_t>, |
| ElementsAre(42, UINT32_C(3000000000))))), |
| PbField( |
| protozero_test_protos_PackedRepeatedFields_field_fixed64_field_number, |
| StringField(ResultOf(ParsePackedFixed<uint64_t>, |
| ElementsAre(42, UINT64_C(5000000000))))), |
| PbField( |
| protozero_test_protos_PackedRepeatedFields_field_sfixed32_field_number, |
| StringField(ResultOf(ParsePackedFixed<int32_t>, |
| ElementsAre(42, 255, -1)))), |
| PbField( |
| protozero_test_protos_PackedRepeatedFields_field_sfixed64_field_number, |
| StringField(ResultOf( |
| ParsePackedFixed<int64_t>, |
| ElementsAre(INT64_C(3000000000), INT64_C(-3000000000))))), |
| PbField( |
| protozero_test_protos_PackedRepeatedFields_field_float_field_number, |
| StringField(ResultOf(ParsePackedFixed<float>, |
| ElementsAre(3.14f, 42.1f)))), |
| PbField( |
| protozero_test_protos_PackedRepeatedFields_field_double_field_number, |
| StringField(ResultOf(ParsePackedFixed<double>, |
| 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<SharedLibDataSourceTest*>(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<SharedLibDataSourceTest*>(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<SharedLibDataSourceTest*>(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<SharedLibDataSourceTest*>(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<SharedLibDataSourceTest*>(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<SharedLibDataSourceTest*>(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<Ds2CustomState*>(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<SharedLibDataSourceTest*>(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<Ds2CustomState*>(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<Ds2CustomState*>(ptr); |
| return state->actual; |
| } |
| |
| NiceMock<MockDs2Callbacks> 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<uint8_t> 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<uint8_t> 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<uint8_t> 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<WaitableEvent*>(p_notification)->Notify(); |
| }, |
| ¬ification); |
| } |
| |
| notification.WaitForNotification(); |
| EXPECT_TRUE(notification.IsNotified()); |
| } |
| |
| TEST_F(SharedLibDataSourceTest, LifetimeCallbacks) { |
| void* const kInstancePtr = reinterpret_cast<void*>(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) {} |
| } |
| |
| 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<uint8_t[]> 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<uint8_t> 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<uint8_t> 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<uint8_t> 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<uint8_t> 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<uint8_t> 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<uint8_t> 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<enum perfetto_protos_TrackEvent_Type>(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<uint8_t> 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<uint8_t> 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<uint8_t> 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<uint8_t> 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<uint8_t> 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<uint8_t> 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<uint8_t> 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<uint8_t> 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<uint8_t> 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<uint8_t> 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; |
| } |
| } |
| |
| } // namespace |