Skip to content

Commit 9a9a904

Browse files
author
Github Executorch
committed
Add runtime control to Android ETDump profiling
Enhances existing EXECUTORCH_ANDROID_PROFILING with runtime control API. Replaces hardcoded profiling with flexible, production-ready implementation. New Capabilities: - Runtime profiling control via ETDump.enableProfiling()/disableProfiling() - Configurable output paths - Programmatic data access with getETDumpData() - Zero performance overhead when profiling is disabled - Single APK deployment (enable/disable at runtime) Implementation: - Add ETDump.java: Public Java API for profiling control - Add executorch_jni_etdump.cpp: JNI implementation with global ETDumpManager - Modify jni_layer.cpp: Integrate ETDump with Module loading - Modify CMakeLists.txt: Enhance EXECUTORCH_ANDROID_PROFILING flag Backward Compatible: - Same build flag (EXECUTORCH_ANDROID_PROFILING) - Default behavior: profiling disabled (zero overhead) - Users who already enable profiling get new features automatically Usage: // Build with: -DEXECUTORCH_ANDROID_PROFILING=ON ETDump.enableProfiling("/sdcard/profile.etdump"); Module module = Module.load("model.pte"); module.forward(inputs); ETDump.writeETDump(); ETDump.disableProfiling();
1 parent aea2784 commit 9a9a904

File tree

7 files changed

+566
-8
lines changed

7 files changed

+566
-8
lines changed

extension/android/CMakeLists.txt

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -91,11 +91,35 @@ list(
9191
fbjni
9292
)
9393

94+
# =============================================================================
95+
# Android ETDump Profiling with Runtime Control
96+
# =============================================================================
9497
if(EXECUTORCH_ANDROID_PROFILING)
95-
list(APPEND link_libraries etdump flatccrt)
98+
# Add ETDump JNI implementation
99+
target_sources(executorch_jni PRIVATE jni/jni_etdump.cpp)
100+
101+
# Add SDK include directories for ETDump headers
102+
target_include_directories(
103+
executorch_jni
104+
PRIVATE
105+
${EXECUTORCH_ROOT}/sdk
106+
${EXECUTORCH_ROOT}/third-party/flatcc/include
107+
)
108+
109+
# Add compile definitions
96110
target_compile_definitions(
97-
executorch_jni PUBLIC EXECUTORCH_ANDROID_PROFILING=1
111+
executorch_jni
112+
PUBLIC
113+
ET_EVENT_TRACER_ENABLED
114+
EXECUTORCH_ANDROID_PROFILING=1
98115
)
116+
117+
# Link ETDump libraries
118+
list(APPEND link_libraries etdump flatccrt)
119+
120+
message(STATUS "Android ETDump profiling with runtime control: ENABLED")
121+
else()
122+
message(STATUS "Android ETDump profiling: DISABLED")
99123
endif()
100124

101125
if(TARGET optimized_native_cpu_ops_lib)
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
/*
2+
* Copyright (c) Meta Platforms, Inc. and affiliates.
3+
* All rights reserved.
4+
*
5+
* This source code is licensed under the BSD-style license found in the
6+
* LICENSE file in the root directory of this source tree.
7+
*/
8+
9+
package org.pytorch.executorch;
10+
11+
import android.util.Log;
12+
13+
/**
14+
* ETDump provides runtime control for ExecuTorch profiling.
15+
*
16+
* <p>Enable profiling before loading models to capture execution traces.
17+
* Use Module.writeETDumpToPath() to write profiling data to custom locations.
18+
*
19+
* <p>Example usage:
20+
* <pre>{@code
21+
* // Enable profiling
22+
* ETDump.enableProfiling();
23+
*
24+
* // Load and run model
25+
* Module module = Module.load("model.pte");
26+
* module.forward(inputs);
27+
*
28+
* // Write profiling data to custom path (no root access needed!)
29+
* module.writeETDumpToPath(getCacheDir() + "/profile.etdump");
30+
*
31+
* // Disable profiling
32+
* ETDump.disableProfiling();
33+
* }</pre>
34+
*/
35+
public class ETDump {
36+
private static final String TAG = "ExecuTorch-ETDump";
37+
38+
static {
39+
try {
40+
System.loadLibrary("executorch");
41+
nativeInit();
42+
} catch (UnsatisfiedLinkError e) {
43+
Log.e(TAG, "Failed to load executorch library", e);
44+
throw e;
45+
}
46+
}
47+
48+
/**
49+
* Initialize the ETDump subsystem.
50+
* Called automatically when the class is loaded.
51+
*/
52+
private static native void nativeInit();
53+
54+
/**
55+
* Enable profiling for subsequently loaded models.
56+
*
57+
* <p>Modules loaded after calling this method will capture profiling data.
58+
* This has zero runtime overhead until a model is actually loaded.
59+
*
60+
* @return true if profiling was successfully enabled
61+
*/
62+
public static boolean enableProfiling() {
63+
boolean result = nativeEnableProfiling();
64+
if (result) {
65+
Log.i(TAG, "Profiling enabled");
66+
} else {
67+
Log.e(TAG, "Failed to enable profiling");
68+
}
69+
return result;
70+
}
71+
72+
/**
73+
* Disable profiling.
74+
*
75+
* <p>Modules loaded after calling this method will not capture profiling data.
76+
*/
77+
public static void disableProfiling() {
78+
nativeDisableProfiling();
79+
Log.i(TAG, "Profiling disabled");
80+
}
81+
82+
/**
83+
* Check if profiling is currently enabled.
84+
*
85+
* @return true if profiling is enabled
86+
*/
87+
public static boolean isProfilingEnabled() {
88+
return nativeIsProfilingEnabled();
89+
}
90+
91+
// Native methods
92+
private static native boolean nativeEnableProfiling();
93+
private static native void nativeDisableProfiling();
94+
private static native boolean nativeIsProfilingEnabled();
95+
}

extension/android/executorch_android/src/main/java/org/pytorch/executorch/Module.java

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -257,4 +257,70 @@ public void destroy() {
257257
+ " released.");
258258
}
259259
}
260+
/**
261+
* Write ETDump profiling data to a specific path.
262+
*
263+
* <p>This allows writing profiling data to custom locations such as
264+
* app cache directory or external storage. No root access required.
265+
*
266+
* <p>Example:
267+
* <pre>{@code
268+
* Module module = Module.load("model.pte");
269+
* module.forward(inputs);
270+
* module.writeETDumpToPath(getCacheDir() + "/profile.etdump");
271+
* }</pre>
272+
*
273+
* @param outputPath The file path where ETDump data will be written.
274+
* Must be a writable location.
275+
* @return true if the data was successfully written, false otherwise
276+
*/
277+
@DoNotStrip
278+
public boolean writeETDumpToPath(String outputPath) {
279+
if (outputPath == null || outputPath.isEmpty()) {
280+
android.util.Log.e("ExecuTorch-Module", "Output path cannot be null or empty");
281+
return false;
282+
}
283+
284+
// Validate that parent directory exists
285+
java.io.File file = new java.io.File(outputPath);
286+
java.io.File parentDir = file.getParentFile();
287+
if (parentDir != null && !parentDir.exists()) {
288+
if (!parentDir.mkdirs()) {
289+
android.util.Log.e("ExecuTorch-Module", "Failed to create parent directory: " + parentDir);
290+
return false;
291+
}
292+
}
293+
294+
return nativeWriteETDumpToPath(outputPath);
295+
}
296+
297+
/**
298+
* Get ETDump profiling data as a byte array.
299+
*
300+
* <p>This is useful for custom handling of profiling data, such as
301+
* uploading to a server or processing in-memory without writing to disk.
302+
*
303+
* <p>Example:
304+
* <pre>{@code
305+
* Module module = Module.load("model.pte");
306+
* module.forward(inputs);
307+
* byte[] profileData = module.getETDumpData();
308+
* if (profileData != null) {
309+
* uploadToServer(profileData);
310+
* }
311+
* }</pre>
312+
*
313+
* @return byte array containing the ETDump data, or null if no data is available
314+
*/
315+
@DoNotStrip
316+
public byte[] getETDumpData() {
317+
return nativeGetETDumpData();
318+
}
319+
320+
@DoNotStrip
321+
private native boolean nativeWriteETDumpToPath(String outputPath);
322+
323+
@DoNotStrip
324+
private native byte[] nativeGetETDumpData();
325+
260326
}

0 commit comments

Comments
 (0)