Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 32bd1529 authored by Zimuzo Ezeozue's avatar Zimuzo Ezeozue
Browse files

Support perfetto track_event prefer

Trace.java now supports per-category tracing to perfetto if specified
in the config. When we trace to perfetto, the event will be missing from
the ftrace buffer. This means that a concurrent session that has the
same category enabled for atrace will be missing the atrace event.
To avoid this, the config can specify that the perfetto event can be
preferred. This means that despite the category being enabled for
atrace, we will trace to perfetto if the category is enabled there.

By default, the perfetto event is not preferred, but it can be preferred
explicitly in the config with atrace_categories_prefer_track_event.

Bug: 303199244
Test: atest libtracing_perfetto_tests
Flag: android.os.flags.perfetto_sdk_tracing
Change-Id: Idf7cfc7c7f9c8ac4191cabff3d958926606f564b
parent 0bab9286
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -40,6 +40,7 @@ cc_library_shared {
    ],

    shared_libs: [
        "libbase",
        "libcutils",
        "libperfetto_c",
        "android.os.flags-aconfig-cc-host",
+0 −30
Original line number Diff line number Diff line
/*
 * Copyright 2024 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.
 */

#ifndef TRACE_RESULT_H
#define TRACE_RESULT_H

namespace tracing_perfetto {

enum class Result {
  SUCCESS,
  NOT_SUPPORTED,
  INVALID_INPUT,
};

}

#endif  // TRACE_RESULT_H
+9 −12
Original line number Diff line number Diff line
@@ -19,35 +19,32 @@

#include <stdint.h>

#include "trace_result.h"

namespace tracing_perfetto {

void registerWithPerfetto(bool test = false);

Result traceBegin(uint64_t category, const char* name);
void traceBegin(uint64_t category, const char* name);

Result traceEnd(uint64_t category);
void traceEnd(uint64_t category);

Result traceAsyncBegin(uint64_t category, const char* name, int32_t cookie);
void traceAsyncBegin(uint64_t category, const char* name, int32_t cookie);

Result traceAsyncEnd(uint64_t category, const char* name, int32_t cookie);
void traceAsyncEnd(uint64_t category, const char* name, int32_t cookie);

Result traceAsyncBeginForTrack(uint64_t category, const char* name,
void traceAsyncBeginForTrack(uint64_t category, const char* name,
                               const char* trackName, int32_t cookie);

Result traceAsyncEndForTrack(uint64_t category, const char* trackName,
void traceAsyncEndForTrack(uint64_t category, const char* trackName,
                             int32_t cookie);

Result traceInstant(uint64_t category, const char* name);
void traceInstant(uint64_t category, const char* name);

Result traceInstantForTrack(uint64_t category, const char* trackName,
void traceInstantForTrack(uint64_t category, const char* trackName,
                            const char* name);

Result traceCounter(uint64_t category, const char* name, int64_t value);
void traceCounter(uint64_t category, const char* name, int64_t value);

bool isTagEnabled(uint64_t category);

}  // namespace tracing_perfetto

#endif  // TRACING_PERFETTO_H
+3 −0
Original line number Diff line number Diff line
@@ -26,6 +26,7 @@ cc_test {
    static_libs: [
        "libflagtest",
        "libgmock",
        "perfetto_trace_protos",
    ],
    cflags: [
        "-Wall",
@@ -35,6 +36,8 @@ cc_test {
        "android.os.flags-aconfig-cc-host",
        "libbase",
        "libperfetto_c",
        "liblog",
        "libprotobuf-cpp-lite",
        "libtracing_perfetto",
    ],
    srcs: [
+161 −46
Original line number Diff line number Diff line
@@ -16,10 +16,10 @@

#include "tracing_perfetto.h"

#include <thread>

#include <android_os.h>
#include <flag_macros.h>
#include <thread>
#include <unistd.h>

#include "gtest/gtest.h"
#include "perfetto/public/abi/data_source_abi.h"
@@ -45,67 +45,182 @@
#include "trace_categories.h"
#include "utils.h"

#include "protos/perfetto/trace/trace.pb.h"
#include "protos/perfetto/trace/trace_packet.pb.h"
#include "protos/perfetto/trace/interned_data/interned_data.pb.h"

#include <fstream>
#include <iterator>
namespace tracing_perfetto {

using ::perfetto::shlib::test_utils::AllFieldsWithId;
using ::perfetto::shlib::test_utils::FieldView;
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::protos::Trace;
using ::perfetto::protos::TracePacket;
using ::perfetto::protos::EventCategory;
using ::perfetto::protos::EventName;
using ::perfetto::protos::FtraceEvent;
using ::perfetto::protos::FtraceEventBundle;
using ::perfetto::protos::InternedData;

using ::perfetto::shlib::test_utils::TracingSession;
using ::perfetto::shlib::test_utils::VarIntField;
using ::testing::_;
using ::testing::ElementsAre;
using ::testing::UnorderedElementsAre;

const auto PERFETTO_SDK_TRACING = ACONFIG_FLAG(android::os, perfetto_sdk_tracing);

// TODO(b/303199244): Add tests for all the library functions.
class TracingPerfettoTest : public testing::Test {
 protected:
  void SetUp() override {
    tracing_perfetto::registerWithPerfetto(true /* test */);
    tracing_perfetto::registerWithPerfetto(false /* test */);
  }
};

// TODO(b/303199244): Add tests for all the library functions.

TEST_F_WITH_FLAGS(TracingPerfettoTest, traceInstant,
                  REQUIRES_FLAGS_ENABLED(PERFETTO_SDK_TRACING)) {
  TracingSession tracing_session =
      TracingSession::Builder().set_data_source_name("track_event").Build();
  tracing_perfetto::traceInstant(TRACE_CATEGORY_INPUT, "");

Trace stopSession(TracingSession& tracing_session) {
  tracing_session.FlushBlocking(5000);
  tracing_session.StopBlocking();
  std::vector<uint8_t> data = tracing_session.ReadBlocking();
  std::string data_string(data.begin(), data.end());

  perfetto::protos::Trace trace;
  trace.ParseFromString(data_string);

  return trace;
}

void verifyTrackEvent(const Trace& trace, const std::string expected_category,
                      const std::string& expected_name) {
  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;
  for (const TracePacket& packet: trace.packet()) {
    if (packet.has_track_event() && packet.has_interned_data()) {

      const InternedData& interned_data = packet.interned_data();
      if (interned_data.event_categories_size() > 0) {
        const EventCategory& event_category = packet.interned_data().event_categories(0);
        if (event_category.name() == expected_category) {
          found = true;
        }
      }

      if (interned_data.event_names_size() > 0) {
        const EventName& event_name = packet.interned_data().event_names(0);
        if (event_name.name() == expected_name) {
          found &= true;
        }
      }

      if (found) {
        break;
      }
    }
  }
  EXPECT_TRUE(found);
}

void verifyAtraceEvent(const Trace& trace, const std::string& expected_name) {
  std::string expected_print_buf = "I|" + std::to_string(gettid()) + "|" + expected_name + "\n";

  bool found = false;
  for (const TracePacket& packet: trace.packet()) {
    if (packet.has_ftrace_events()) {
      const FtraceEventBundle& ftrace_events_bundle = packet.ftrace_events();

      if (ftrace_events_bundle.event_size() > 0) {
        const FtraceEvent& ftrace_event = ftrace_events_bundle.event(0);
        if (ftrace_event.has_print() && (ftrace_event.print().buf() == expected_print_buf)) {
          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("input")))))))));
          break;
        }
      }
    }
  }
  EXPECT_TRUE(found);
}

TEST_F_WITH_FLAGS(TracingPerfettoTest, traceInstantWithPerfetto,
                  REQUIRES_FLAGS_ENABLED(PERFETTO_SDK_TRACING)) {
  std::string event_category = "input";
  std::string event_name = "traceInstantWithPerfetto";

  TracingSession tracing_session =
      TracingSession::Builder().add_enabled_category(event_category).Build();

  tracing_perfetto::traceInstant(TRACE_CATEGORY_INPUT, event_name.c_str());

  Trace trace = stopSession(tracing_session);

  verifyTrackEvent(trace, event_category, event_name);
}

TEST_F_WITH_FLAGS(TracingPerfettoTest, traceInstantWithAtrace,
                  REQUIRES_FLAGS_ENABLED(PERFETTO_SDK_TRACING)) {
  std::string event_category = "input";
  std::string event_name = "traceInstantWithAtrace";

  TracingSession tracing_session =
      TracingSession::Builder().add_atrace_category(event_category).Build();

  tracing_perfetto::traceInstant(TRACE_CATEGORY_INPUT, event_name.c_str());

  Trace trace = stopSession(tracing_session);

  verifyAtraceEvent(trace, event_name);
}

TEST_F_WITH_FLAGS(TracingPerfettoTest, traceInstantWithPerfettoAndAtrace,
                  REQUIRES_FLAGS_ENABLED(PERFETTO_SDK_TRACING)) {
  std::string event_category = "input";
  std::string event_name = "traceInstantWithPerfettoAndAtrace";

  TracingSession tracing_session =
      TracingSession::Builder()
      .add_atrace_category(event_category)
      .add_enabled_category(event_category).Build();

  tracing_perfetto::traceInstant(TRACE_CATEGORY_INPUT, event_name.c_str());

  Trace trace = stopSession(tracing_session);

  verifyAtraceEvent(trace, event_name);
}

TEST_F_WITH_FLAGS(TracingPerfettoTest, traceInstantWithPerfettoAndAtraceAndPreferTrackEvent,
                  REQUIRES_FLAGS_ENABLED(PERFETTO_SDK_TRACING)) {
  std::string event_category = "input";
  std::string event_name = "traceInstantWithPerfettoAndAtraceAndPreferTrackEvent";

  TracingSession tracing_session =
      TracingSession::Builder()
      .add_atrace_category(event_category)
      .add_atrace_category_prefer_sdk(event_category)
      .add_enabled_category(event_category).Build();

  tracing_perfetto::traceInstant(TRACE_CATEGORY_INPUT, event_name.c_str());

  Trace trace = stopSession(tracing_session);

  verifyTrackEvent(trace, event_category, event_name);
}

TEST_F_WITH_FLAGS(TracingPerfettoTest, traceInstantWithPerfettoAndAtraceConcurrently,
                  REQUIRES_FLAGS_ENABLED(PERFETTO_SDK_TRACING)) {
  std::string event_category = "input";
  std::string event_name = "traceInstantWithPerfettoAndAtraceConcurrently";

  TracingSession perfetto_tracing_session =
      TracingSession::Builder()
      .add_atrace_category(event_category)
      .add_atrace_category_prefer_sdk(event_category)
      .add_enabled_category(event_category).Build();

  TracingSession atrace_tracing_session =
      TracingSession::Builder()
      .add_atrace_category(event_category)
      .add_enabled_category(event_category).Build();

  tracing_perfetto::traceInstant(TRACE_CATEGORY_INPUT, event_name.c_str());

  Trace atrace_trace = stopSession(atrace_tracing_session);
  Trace perfetto_trace = stopSession(perfetto_tracing_session);

  verifyAtraceEvent(atrace_trace, event_name);
  verifyAtraceEvent(perfetto_trace, event_name);
}
}  // namespace tracing_perfetto
Loading