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

Commit 4a429a89 authored by Zimuzo Ezeozue's avatar Zimuzo Ezeozue Committed by Android (Google) Code Review
Browse files

Merge changes from topic "perfetto_test" into main

* changes:
  Added Perfetto tests to TracePerfTest
  Expose perfetto start and stop sessions
parents 8ee3a094 65bfe59d
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -50,6 +50,7 @@ android_test {
        "junit-params",
        "core-tests-support",
        "guava",
        "perfetto_trace_java_protos",
    ],

    libs: ["android.test.base.stubs.system"],
+75 −0
Original line number Diff line number Diff line
@@ -17,6 +17,8 @@

package android.os;

import static android.os.PerfettoTrace.Category;

import android.perftests.utils.BenchmarkState;
import android.perftests.utils.PerfStatusReporter;
import android.perftests.utils.ShellHelper;
@@ -31,19 +33,35 @@ import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;

import perfetto.protos.DataSourceConfigOuterClass.DataSourceConfig;
import perfetto.protos.TraceConfigOuterClass.TraceConfig;
import perfetto.protos.TraceConfigOuterClass.TraceConfig.BufferConfig;
import perfetto.protos.TraceConfigOuterClass.TraceConfig.DataSource;
import perfetto.protos.TrackEventConfigOuterClass.TrackEventConfig;

@RunWith(AndroidJUnit4.class)
public class TracePerfTest {
    @Rule
    public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();

    private static final String FOO = "foo";
    private static final Category FOO_CATEGORY = new Category(FOO);
    private static PerfettoTrace.Session sPerfettoSession;

    @BeforeClass
    public static void startTracing() {
        ShellHelper.runShellCommandRaw("atrace -c --async_start -a *");
        PerfettoTrace.register(false /* isBackendInProcess */);
        FOO_CATEGORY.register();
        sPerfettoSession = new PerfettoTrace.Session(false /* isBackendInProcess */,
                                                      getTraceConfig(FOO).toByteArray());
    }

    @AfterClass
    public static void endTracing() {
        ShellHelper.runShellCommandRaw("atrace --async_stop");
        FOO_CATEGORY.unregister();
        sPerfettoSession.close();
    }

    @Before
@@ -84,4 +102,61 @@ public class TracePerfTest {
            Trace.setCounter("testCounter", 123);
        }
    }

    @Test
    public void testInstant() {
        Trace.instant(Trace.TRACE_TAG_APP, "testInstantA");

        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
        while (state.keepRunning()) {
            Trace.instant(Trace.TRACE_TAG_APP, "testInstantA");
        }
    }

    @Test
    public void testInstantPerfetto() {
        PerfettoTrace.instant(FOO_CATEGORY, "testInstantP").emit();

        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
        while (state.keepRunning()) {
            PerfettoTrace.instant(FOO_CATEGORY, "testInstantP").emit();
        }
    }

    @Test
    public void testInstantPerfettoWithArgs() {
        PerfettoTrace.instant(FOO_CATEGORY, "testInstantP")
                .addArg("foo", "bar")
                .addFlow(1)
                .emit();

        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
        while (state.keepRunning()) {
            PerfettoTrace.instant(FOO_CATEGORY, "testInstantP")
                    .addArg("foo", "bar")
                    .addFlow(1)
                    .emit();
        }
    }

    private static TraceConfig getTraceConfig(String cat) {
        BufferConfig bufferConfig = BufferConfig.newBuilder().setSizeKb(1024).build();
        TrackEventConfig trackEventConfig = TrackEventConfig
                .newBuilder()
                .addEnabledCategories(cat)
                .build();
        DataSourceConfig dsConfig = DataSourceConfig
                .newBuilder()
                .setName("track_event")
                .setTargetBuffer(0)
                .setTrackEventConfig(trackEventConfig)
                .build();
        DataSource ds = DataSource.newBuilder().setConfig(dsConfig).build();
        TraceConfig traceConfig = TraceConfig
                .newBuilder()
                .addBuffers(bufferConfig)
                .addDataSources(ds)
                .build();
        return traceConfig;
    }
}
+33 −3
Original line number Diff line number Diff line
@@ -154,14 +154,44 @@ public final class PerfettoTrace {
        }
    }

    /**
     * Manages a perfetto tracing session.
     * Constructing this object with a config automatically starts a tracing session. Each session
     * must be closed after use and then the resulting trace bytes can be read.
     *
     * The session could be in process or system wide, depending on {@code isBackendInProcess}.
     * This functionality is intended for testing.
     */
    public static final class Session {
        private final long mPtr;

        /**
         * Session ctor.
         */
        public Session(boolean isBackendInProcess, byte[] config) {
            mPtr = native_start_session(isBackendInProcess, config);
        }

        /**
         * Closes the session and returns the trace.
         */
        public byte[] close() {
            return native_stop_session(mPtr);
        }
    }

    @CriticalNative
    private static native long native_get_process_track_uuid();

    @CriticalNative
    private static native long native_get_thread_track_uuid(long tid);

    @FastNative
    private static native void native_activate_trigger(String name, int ttlMs);
    @FastNative
    private static native void native_register(boolean isBackendInProcess);

    private static native long native_start_session(boolean isBackendInProcess, byte[] config);
    private static native byte[] native_stop_session(long ptr);

    /**
     * Writes a trace message to indicate a given section of code was invoked.
@@ -307,7 +337,7 @@ public final class PerfettoTrace {
    /**
     * Registers the process with Perfetto.
     */
    public static void register() {
        Trace.registerWithPerfetto();
    public static void register(boolean isBackendInProcess) {
        native_register(isBackendInProcess);
    }
}
+1 −3
Original line number Diff line number Diff line
@@ -164,8 +164,6 @@ public final class Trace {
    private static native void nativeInstant(long tag, String name);
    @FastNative
    private static native void nativeInstantForTrack(long tag, String trackName, String name);
    @FastNative
    private static native void nativeRegisterWithPerfetto();

    private Trace() {
    }
@@ -545,6 +543,6 @@ public final class Trace {
     * @hide
     */
    public static void registerWithPerfetto() {
        nativeRegisterWithPerfetto();
        PerfettoTrace.register(false /* isBackendInProcess */);
    }
}
+41 −1
Original line number Diff line number Diff line
@@ -24,9 +24,12 @@
#include <nativehelper/scoped_primitive_array.h>
#include <nativehelper/scoped_utf_chars.h>
#include <nativehelper/utils.h>
#include <tracing_perfetto.h>
#include <tracing_sdk.h>

namespace android {
constexpr int kFlushTimeoutMs = 5000;

template <typename T>
inline static T* toPointer(jlong ptr) {
    return reinterpret_cast<T*>(static_cast<uintptr_t>(ptr));
@@ -51,6 +54,10 @@ static void android_os_PerfettoTrace_activate_trigger(JNIEnv* env, jclass, jstri
    tracing_perfetto::activate_trigger(name_chars.c_str(), static_cast<uint32_t>(ttl_ms));
}

void android_os_PerfettoTrace_register(bool is_backend_in_process) {
    tracing_perfetto::registerWithPerfetto(is_backend_in_process);
}

static jlong android_os_PerfettoTraceCategory_init(JNIEnv* env, jclass, jstring name, jstring tag,
                                                   jstring severity) {
    ScopedUtfChars name_chars = GET_UTF_OR_RETURN(env, name);
@@ -85,6 +92,36 @@ static jlong android_os_PerfettoTraceCategory_get_extra_ptr(jlong ptr) {
    return toJLong(category->get());
}

static jlong android_os_PerfettoTrace_start_session(JNIEnv* env, jclass /* obj */,
                                                    jboolean is_backend_in_process,
                                                    jbyteArray config_bytes) {
    jsize length = env->GetArrayLength(config_bytes);
    std::vector<uint8_t> data;
    data.reserve(length);
    env->GetByteArrayRegion(config_bytes, 0, length, reinterpret_cast<jbyte*>(data.data()));

    tracing_perfetto::Session* session =
            new tracing_perfetto::Session(is_backend_in_process, data.data(), length);

    return reinterpret_cast<long>(session);
}

static jbyteArray android_os_PerfettoTrace_stop_session([[maybe_unused]] JNIEnv* env,
                                                        jclass /* obj */, jlong ptr) {
    tracing_perfetto::Session* session = reinterpret_cast<tracing_perfetto::Session*>(ptr);

    session->FlushBlocking(kFlushTimeoutMs);
    session->StopBlocking();

    std::vector<uint8_t> data = session->ReadBlocking();

    delete session;

    jbyteArray bytes = env->NewByteArray(data.size());
    env->SetByteArrayRegion(bytes, 0, data.size(), reinterpret_cast<jbyte*>(data.data()));
    return bytes;
}

static const JNINativeMethod gCategoryMethods[] = {
        {"native_init", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)J",
         (void*)android_os_PerfettoTraceCategory_init},
@@ -101,7 +138,10 @@ static const JNINativeMethod gTraceMethods[] =
         {"native_get_thread_track_uuid", "(J)J",
          (void*)android_os_PerfettoTrace_get_thread_track_uuid},
         {"native_activate_trigger", "(Ljava/lang/String;I)V",
          (void*)android_os_PerfettoTrace_activate_trigger}};
          (void*)android_os_PerfettoTrace_activate_trigger},
         {"native_register", "(Z)V", (void*)android_os_PerfettoTrace_register},
         {"native_start_session", "(Z[B)J", (void*)android_os_PerfettoTrace_start_session},
         {"native_stop_session", "(J)[B", (void*)android_os_PerfettoTrace_stop_session}};

int register_android_os_PerfettoTrace(JNIEnv* env) {
    int res = jniRegisterNativeMethods(env, "android/os/PerfettoTrace", gTraceMethods,
Loading