-
Notifications
You must be signed in to change notification settings - Fork 971
Add runtime control to Android ETDump profiling #16359
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,95 @@ | ||
| /* | ||
| * Copyright (c) Meta Platforms, Inc. and affiliates. | ||
| * All rights reserved. | ||
| * | ||
| * This source code is licensed under the BSD-style license found in the | ||
| * LICENSE file in the root directory of this source tree. | ||
| */ | ||
|
|
||
| package org.pytorch.executorch; | ||
|
|
||
| import android.util.Log; | ||
|
|
||
| /** | ||
| * ETDump provides runtime control for ExecuTorch profiling. | ||
| * | ||
| * <p>Enable profiling before loading models to capture execution traces. Use | ||
| * Module.writeETDumpToPath() to write profiling data to custom locations. | ||
| * | ||
| * <p>Example usage: | ||
| * | ||
| * <pre>{@code | ||
| * // Enable profiling | ||
| * ETDump.enableProfiling(); | ||
| * | ||
| * // Load and run model | ||
| * Module module = Module.load("model.pte"); | ||
| * module.forward(inputs); | ||
| * | ||
| * // Write profiling data to custom path (no root access needed!) | ||
| * module.writeETDumpToPath(getCacheDir() + "/profile.etdump"); | ||
| * | ||
| * // Disable profiling | ||
| * ETDump.disableProfiling(); | ||
| * }</pre> | ||
| */ | ||
| public class ETDump { | ||
| private static final String TAG = "ExecuTorch-ETDump"; | ||
|
|
||
| static { | ||
| try { | ||
| System.loadLibrary("executorch"); | ||
| nativeInit(); | ||
| } catch (UnsatisfiedLinkError e) { | ||
| Log.e(TAG, "Failed to load executorch library", e); | ||
| throw e; | ||
| } | ||
|
Comment on lines
+39
to
+46
|
||
| } | ||
|
|
||
| /** Initialize the ETDump subsystem. Called automatically when the class is loaded. */ | ||
| private static native void nativeInit(); | ||
|
Comment on lines
+39
to
+50
|
||
|
|
||
| /** | ||
| * Enable profiling for subsequently loaded models. | ||
| * | ||
| * <p>Modules loaded after calling this method will capture profiling data. This has zero runtime | ||
| * overhead until a model is actually loaded. | ||
| * | ||
| * @return true if profiling was successfully enabled | ||
| */ | ||
| public static boolean enableProfiling() { | ||
| boolean result = nativeEnableProfiling(); | ||
| if (result) { | ||
| Log.i(TAG, "Profiling enabled"); | ||
| } else { | ||
| Log.e(TAG, "Failed to enable profiling"); | ||
| } | ||
| return result; | ||
| } | ||
|
Comment on lines
+52
to
+68
|
||
|
|
||
| /** | ||
| * Disable profiling. | ||
| * | ||
| * <p>Modules loaded after calling this method will not capture profiling data. | ||
| */ | ||
| public static void disableProfiling() { | ||
| nativeDisableProfiling(); | ||
| Log.i(TAG, "Profiling disabled"); | ||
| } | ||
|
|
||
| /** | ||
| * Check if profiling is currently enabled. | ||
| * | ||
| * @return true if profiling is enabled | ||
| */ | ||
| public static boolean isProfilingEnabled() { | ||
| return nativeIsProfilingEnabled(); | ||
| } | ||
|
|
||
| // Native methods | ||
| private static native boolean nativeEnableProfiling(); | ||
|
|
||
| private static native void nativeDisableProfiling(); | ||
|
|
||
| private static native boolean nativeIsProfilingEnabled(); | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,80 @@ | ||
| /* | ||
| * Copyright (c) Meta Platforms, Inc. and affiliates. | ||
| * All rights reserved. | ||
| * | ||
| * This source code is licensed under the BSD-style license found in the | ||
| * LICENSE file in the root directory of this source tree. | ||
| */ | ||
|
|
||
| #include <fbjni/fbjni.h> | ||
| #include <jni.h> | ||
|
|
||
| #ifdef EXECUTORCH_ANDROID_PROFILING | ||
|
|
||
| #include "jni_etdump.h" | ||
|
|
||
| namespace executorch { | ||
| namespace extension { | ||
| namespace jni { | ||
|
|
||
| // ============================================================================ | ||
| // Global ETDump Manager | ||
| // ============================================================================ | ||
|
|
||
| // Global ETDump manager (one per process) | ||
| static std::unique_ptr<ETDumpManager> g_etdump_manager = nullptr; | ||
|
Comment on lines
+9
to
+25
|
||
|
|
||
| extern "C" ETDumpManager* getGlobalETDumpManager() { | ||
| return g_etdump_manager.get(); | ||
| } | ||
|
|
||
| // ============================================================================ | ||
| // JNI Methods for ETDump Java class | ||
| // ============================================================================ | ||
|
|
||
| // Initialize ETDump manager | ||
| extern "C" JNIEXPORT void JNICALL | ||
| Java_org_pytorch_executorch_ETDump_nativeInit(JNIEnv* env, jclass clazz) { | ||
| if (!g_etdump_manager) { | ||
| g_etdump_manager = std::make_unique<ETDumpManager>(); | ||
| } | ||
| } | ||
|
|
||
| // Enable profiling | ||
| extern "C" JNIEXPORT jboolean JNICALL | ||
| Java_org_pytorch_executorch_ETDump_nativeEnableProfiling( | ||
| JNIEnv* env, | ||
| jclass clazz) { | ||
| if (!g_etdump_manager) { | ||
| g_etdump_manager = std::make_unique<ETDumpManager>(); | ||
| } | ||
| g_etdump_manager->enableProfiling(); | ||
| return JNI_TRUE; | ||
| } | ||
|
|
||
| // Disable profiling | ||
| extern "C" JNIEXPORT void JNICALL | ||
| Java_org_pytorch_executorch_ETDump_nativeDisableProfiling( | ||
| JNIEnv* env, | ||
| jclass clazz) { | ||
| if (g_etdump_manager) { | ||
| g_etdump_manager->disableProfiling(); | ||
| } | ||
| } | ||
|
|
||
| // Check if profiling is enabled | ||
| extern "C" JNIEXPORT jboolean JNICALL | ||
| Java_org_pytorch_executorch_ETDump_nativeIsProfilingEnabled( | ||
| JNIEnv* env, | ||
| jclass clazz) { | ||
| if (!g_etdump_manager) { | ||
| return JNI_FALSE; | ||
| } | ||
| return g_etdump_manager->isProfilingEnabled() ? JNI_TRUE : JNI_FALSE; | ||
| } | ||
|
|
||
| } // namespace jni | ||
| } // namespace extension | ||
| } // namespace executorch | ||
|
|
||
| #endif // EXECUTORCH_ANDROID_PROFILING | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,63 @@ | ||
| /* | ||
| * Copyright (c) Meta Platforms, Inc. and affiliates. | ||
| * All rights reserved. | ||
| * | ||
| * This source code is licensed under the BSD-style license found in the | ||
| * LICENSE file in the root directory of this source tree. | ||
| */ | ||
|
|
||
| #pragma once | ||
|
|
||
| #ifdef EXECUTORCH_ANDROID_PROFILING | ||
| #include <executorch/devtools/etdump/etdump_flatcc.h> | ||
|
|
||
| namespace executorch { | ||
| namespace extension { | ||
| namespace jni { | ||
|
|
||
| /** | ||
| * ETDumpManager manages the global profiling enabled state. | ||
| * This is a singleton that controls whether newly loaded modules | ||
| * should capture profiling data. | ||
| */ | ||
| class ETDumpManager { | ||
| public: | ||
| ETDumpManager() : profiling_enabled_(false) {} | ||
|
|
||
| /** | ||
| * Enable profiling for subsequently loaded modules. | ||
| */ | ||
| void enableProfiling() { | ||
| profiling_enabled_ = true; | ||
| } | ||
|
|
||
| /** | ||
| * Disable profiling. | ||
| */ | ||
| void disableProfiling() { | ||
| profiling_enabled_ = false; | ||
| } | ||
|
|
||
| /** | ||
| * Check if profiling is currently enabled. | ||
| * @return true if profiling is enabled | ||
| */ | ||
| bool isProfilingEnabled() const { | ||
| return profiling_enabled_; | ||
| } | ||
|
|
||
| private: | ||
| bool profiling_enabled_; | ||
| }; | ||
|
Comment on lines
+45
to
+51
|
||
|
|
||
| /** | ||
| * Get the global ETDump manager instance. | ||
| * @return Pointer to the global ETDumpManager, or nullptr if not initialized | ||
| */ | ||
| extern "C" ETDumpManager* getGlobalETDumpManager(); | ||
|
|
||
| } // namespace jni | ||
| } // namespace extension | ||
| } // namespace executorch | ||
|
|
||
| #endif // EXECUTORCH_ANDROID_PROFILING | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ETDump.javais added unconditionally to the Android AAR, but its JNI implementation (jni_etdump.cpp) is only compiled whenEXECUTORCH_ANDROID_PROFILINGis ON. This combination makes the Java API unsafe to reference in non-profiling builds (native symbols won’t exist). Consider always compiling/linking JNI stubs for ETDump (returning false/no-op when profiling is disabled), or conditionally excluding the Java source from the Gradle build when the flag is OFF.