From df90bdd52e30b84704bbd710c7e57558494c9b32 Mon Sep 17 00:00:00 2001 From: Hansong Zhang Date: Tue, 20 May 2025 15:58:22 -0700 Subject: [PATCH 01/10] Get rid of NativePeer.java Adds an additional layer without clear usage --- .../docs/delegates/xnnpack_README.md | 2 +- extension/android/BUCK | 1 - .../java/org/pytorch/executorch/Module.java | 76 ++++++++++--------- .../org/pytorch/executorch/NativePeer.java | 68 ----------------- extension/android/jni/jni_layer.cpp | 14 +--- 5 files changed, 43 insertions(+), 118 deletions(-) delete mode 100644 extension/android/executorch_android/src/main/java/org/pytorch/executorch/NativePeer.java diff --git a/examples/demo-apps/android/LlamaDemo/docs/delegates/xnnpack_README.md b/examples/demo-apps/android/LlamaDemo/docs/delegates/xnnpack_README.md index 7f1ee6df374..054d35db11d 100644 --- a/examples/demo-apps/android/LlamaDemo/docs/delegates/xnnpack_README.md +++ b/examples/demo-apps/android/LlamaDemo/docs/delegates/xnnpack_README.md @@ -172,7 +172,7 @@ This is running the shell script which configures the required core ExecuTorch, ``` bash examples/demo-apps/android/LlamaDemo/download_prebuilt_lib.sh ``` -The prebuilt AAR library contains the Java library and the JNI binding for NativePeer.java and ExecuTorch native library, including core ExecuTorch runtime libraries, XNNPACK backend, Portable kernels, Optimized kernels, and Quantized kernels. It comes with two ABI variants, arm64-v8a and x86_64. +The prebuilt AAR library contains the Java library and the JNI binding for Module.java and ExecuTorch native library, including core ExecuTorch runtime libraries, XNNPACK backend, Portable kernels, Optimized kernels, and Quantized kernels. It comes with two ABI variants, arm64-v8a and x86_64. If you need to use other dependencies (like tokenizer), please build from the local machine option. ## Run the Android Demo App diff --git a/extension/android/BUCK b/extension/android/BUCK index 34c9bc4b5a8..0fad11eb677 100644 --- a/extension/android/BUCK +++ b/extension/android/BUCK @@ -9,7 +9,6 @@ non_fbcode_target(_kind = fb_android_library, "executorch_android/src/main/java/org/pytorch/executorch/DType.java", "executorch_android/src/main/java/org/pytorch/executorch/EValue.java", "executorch_android/src/main/java/org/pytorch/executorch/Module.java", - "executorch_android/src/main/java/org/pytorch/executorch/NativePeer.java", "executorch_android/src/main/java/org/pytorch/executorch/Tensor.java", "executorch_android/src/main/java/org/pytorch/executorch/annotations/Experimental.java", ], diff --git a/extension/android/executorch_android/src/main/java/org/pytorch/executorch/Module.java b/extension/android/executorch_android/src/main/java/org/pytorch/executorch/Module.java index b31641d5a37..8b2fc81ecf7 100644 --- a/extension/android/executorch_android/src/main/java/org/pytorch/executorch/Module.java +++ b/extension/android/executorch_android/src/main/java/org/pytorch/executorch/Module.java @@ -9,6 +9,9 @@ package org.pytorch.executorch; import android.util.Log; + +import com.facebook.jni.HybridData; +import com.facebook.jni.annotations.DoNotStrip; import com.facebook.soloader.nativeloader.NativeLoader; import com.facebook.soloader.nativeloader.SystemDelegate; import java.io.File; @@ -24,6 +27,14 @@ @Experimental public class Module { + static { + if (!NativeLoader.isInitialized()) { + NativeLoader.init(new SystemDelegate()); + } + // Loads libexecutorch.so from jniLibs + NativeLoader.loadLibrary("executorch"); + } + /** Load mode for the module. Load the whole file as a buffer. */ public static final int LOAD_MODE_FILE = 0; @@ -36,10 +47,16 @@ public class Module { /** Load mode for the module. Use memory locking and ignore errors. */ public static final int LOAD_MODE_MMAP_USE_MLOCK_IGNORE_ERRORS = 3; - /** Reference to the NativePeer object of this module. */ - private NativePeer mNativePeer; + private final HybridData mHybridData; + + @DoNotStrip + private static native HybridData initHybrid(String moduleAbsolutePath, int loadMode); - /** Lock protecting the non-thread safe methods in NativePeer. */ + private Module(String moduleAbsolutePath, int loadMode) { + mHybridData = initHybrid(moduleAbsolutePath, loadMode); + } + + /** Lock protecting the non-thread safe methods in mHybridData. */ private Lock mLock = new ReentrantLock(); /** @@ -50,14 +67,11 @@ public class Module { * @return new {@link org.pytorch.executorch.Module} object which owns the model module. */ public static Module load(final String modelPath, int loadMode) { - if (!NativeLoader.isInitialized()) { - NativeLoader.init(new SystemDelegate()); - } File modelFile = new File(modelPath); if (!modelFile.canRead() || !modelFile.isFile()) { throw new RuntimeException("Cannot load model path " + modelPath); } - return new Module(new NativePeer(modelPath, loadMode)); + return new Module(modelPath, loadMode); } /** @@ -70,10 +84,6 @@ public static Module load(final String modelPath) { return load(modelPath, LOAD_MODE_FILE); } - Module(NativePeer nativePeer) { - this.mNativePeer = nativePeer; - } - /** * Runs the 'forward' method of this module with the specified arguments. * @@ -83,16 +93,7 @@ public static Module load(final String modelPath) { * @return return value from the 'forward' method. */ public EValue[] forward(EValue... inputs) { - try { - mLock.lock(); - if (mNativePeer == null) { - Log.e("ExecuTorch", "Attempt to use a destroyed module"); - return new EValue[0]; - } - return mNativePeer.forward(inputs); - } finally { - mLock.unlock(); - } + return execute("forward", inputs); } /** @@ -105,16 +106,19 @@ public EValue[] forward(EValue... inputs) { public EValue[] execute(String methodName, EValue... inputs) { try { mLock.lock(); - if (mNativePeer == null) { + if (!mHybridData.isValid()) { Log.e("ExecuTorch", "Attempt to use a destroyed module"); return new EValue[0]; } - return mNativePeer.execute(methodName, inputs); + return executeNative(methodName, inputs); } finally { mLock.unlock(); } } + @DoNotStrip + private native EValue[] executeNative(String methodName, EValue... inputs); + /** * Load a method on this module. This might help with the first time inference performance, * because otherwise the method is loaded lazily when it's execute. Note: this function is @@ -127,30 +131,31 @@ public EValue[] execute(String methodName, EValue... inputs) { public int loadMethod(String methodName) { try { mLock.lock(); - if (mNativePeer == null) { + if (!mHybridData.isValid()) { Log.e("ExecuTorch", "Attempt to use a destroyed module"); return 0x2; // InvalidState } - return mNativePeer.loadMethod(methodName); + return loadMethodNative(methodName); } finally { mLock.unlock(); } } + @DoNotStrip + private native int loadMethodNative(String methodName); + /** * Returns the names of the methods in a certain method. * * @param methodName method name to query * @return an array of backend name */ - public String[] getUsedBackends(String methodName) { - return mNativePeer.getUsedBackends(methodName); - } + @DoNotStrip + public native String[] getUsedBackends(String methodName); /** Retrieve the in-memory log buffer, containing the most recent ExecuTorch log entries. */ - public String[] readLogBuffer() { - return mNativePeer.readLogBuffer(); - } + @DoNotStrip + public native String[] readLogBuffer(); /** * Dump the ExecuTorch ETRecord file to /data/local/tmp/result.etdump. @@ -160,9 +165,8 @@ public String[] readLogBuffer() { * @return true if the etdump was successfully written, false otherwise. */ @Experimental - public boolean etdump() { - return mNativePeer.etdump(); - } + @DoNotStrip + public native boolean etdump(); /** * Explicitly destroys the native Module object. Calling this method is not required, as the @@ -173,13 +177,11 @@ public boolean etdump() { public void destroy() { if (mLock.tryLock()) { try { - mNativePeer.resetNative(); + mHybridData.resetNative(); } finally { - mNativePeer = null; mLock.unlock(); } } else { - mNativePeer = null; Log.w( "ExecuTorch", "Destroy was called while the module was in use. Resources will not be immediately" diff --git a/extension/android/executorch_android/src/main/java/org/pytorch/executorch/NativePeer.java b/extension/android/executorch_android/src/main/java/org/pytorch/executorch/NativePeer.java deleted file mode 100644 index 58d58de1b3e..00000000000 --- a/extension/android/executorch_android/src/main/java/org/pytorch/executorch/NativePeer.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * 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 com.facebook.jni.HybridData; -import com.facebook.jni.annotations.DoNotStrip; -import com.facebook.soloader.nativeloader.NativeLoader; -import org.pytorch.executorch.annotations.Experimental; - -/** - * Interface for the native peer object for entry points to the Module - * - *

Warning: These APIs are experimental and subject to change without notice - */ -@Experimental -class NativePeer { - static { - // Loads libexecutorch.so from jniLibs - NativeLoader.loadLibrary("executorch"); - } - - private final HybridData mHybridData; - - @DoNotStrip - private static native HybridData initHybrid(String moduleAbsolutePath, int loadMode); - - NativePeer(String moduleAbsolutePath, int loadMode) { - mHybridData = initHybrid(moduleAbsolutePath, loadMode); - } - - /** Clean up the native resources associated with this instance */ - public void resetNative() { - mHybridData.resetNative(); - } - - /** Run a "forward" call with the given inputs */ - @DoNotStrip - public native EValue[] forward(EValue... inputs); - - /** Run an arbitrary method on the module */ - @DoNotStrip - public native EValue[] execute(String methodName, EValue... inputs); - - /** - * Load a method on this module. - * - * @return the Error code if there was an error loading the method - */ - @DoNotStrip - public native int loadMethod(String methodName); - - /** Return the list of backends used by a method */ - @DoNotStrip - public native String[] getUsedBackends(String methodName); - - /** Retrieve the in-memory log buffer, containing the most recent ExecuTorch log entries. */ - @DoNotStrip - public native String[] readLogBuffer(); - - @DoNotStrip - public native boolean etdump(); -} diff --git a/extension/android/jni/jni_layer.cpp b/extension/android/jni/jni_layer.cpp index 048d5bffa78..3837f091740 100644 --- a/extension/android/jni/jni_layer.cpp +++ b/extension/android/jni/jni_layer.cpp @@ -223,7 +223,7 @@ class ExecuTorchJni : public facebook::jni::HybridClass { std::unique_ptr module_; public: - constexpr static auto kJavaDescriptor = "Lorg/pytorch/executorch/NativePeer;"; + constexpr static auto kJavaDescriptor = "Lorg/pytorch/executorch/Module;"; static facebook::jni::local_ref initHybrid( facebook::jni::alias_ref, @@ -271,13 +271,6 @@ class ExecuTorchJni : public facebook::jni::HybridClass { #endif } - facebook::jni::local_ref> forward( - facebook::jni::alias_ref< - facebook::jni::JArrayClass::javaobject> - jinputs) { - return execute_method("forward", jinputs); - } - facebook::jni::local_ref> execute( facebook::jni::alias_ref methodName, facebook::jni::alias_ref< @@ -459,9 +452,8 @@ class ExecuTorchJni : public facebook::jni::HybridClass { static void registerNatives() { registerHybrid({ makeNativeMethod("initHybrid", ExecuTorchJni::initHybrid), - makeNativeMethod("forward", ExecuTorchJni::forward), - makeNativeMethod("execute", ExecuTorchJni::execute), - makeNativeMethod("loadMethod", ExecuTorchJni::load_method), + makeNativeMethod("executeNative", ExecuTorchJni::execute), + makeNativeMethod("loadMethodNative", ExecuTorchJni::load_method), makeNativeMethod("readLogBuffer", ExecuTorchJni::readLogBuffer), makeNativeMethod("etdump", ExecuTorchJni::etdump), makeNativeMethod("getUsedBackends", ExecuTorchJni::getUsedBackends), From b69a166374d12b2353adad32fee5202e76ddfeab Mon Sep 17 00:00:00 2001 From: Hansong Zhang Date: Tue, 20 May 2025 16:18:45 -0700 Subject: [PATCH 02/10] metadata --- .../pytorch/executorch/MethodMetadata.java | 20 +++++++++++++++++++ .../java/org/pytorch/executorch/Module.java | 8 ++++++++ 2 files changed, 28 insertions(+) create mode 100644 extension/android/executorch_android/src/main/java/org/pytorch/executorch/MethodMetadata.java diff --git a/extension/android/executorch_android/src/main/java/org/pytorch/executorch/MethodMetadata.java b/extension/android/executorch_android/src/main/java/org/pytorch/executorch/MethodMetadata.java new file mode 100644 index 00000000000..810c9b54cc8 --- /dev/null +++ b/extension/android/executorch_android/src/main/java/org/pytorch/executorch/MethodMetadata.java @@ -0,0 +1,20 @@ +/* + * 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; + +/** + * Helper class to access the metadata for a method from a Module + */ +public class MethodMetadata { + private String name; + + public String getName() { + return name; + } +} diff --git a/extension/android/executorch_android/src/main/java/org/pytorch/executorch/Module.java b/extension/android/executorch_android/src/main/java/org/pytorch/executorch/Module.java index 8b2fc81ecf7..9ae44accf62 100644 --- a/extension/android/executorch_android/src/main/java/org/pytorch/executorch/Module.java +++ b/extension/android/executorch_android/src/main/java/org/pytorch/executorch/Module.java @@ -49,11 +49,19 @@ public class Module { private final HybridData mHybridData; + private final MethodMetadata[] mMethodMetadata; + @DoNotStrip private static native HybridData initHybrid(String moduleAbsolutePath, int loadMode); private Module(String moduleAbsolutePath, int loadMode) { mHybridData = initHybrid(moduleAbsolutePath, loadMode); + + populateMethodMeta(); + } + + void populateMethodMeta() { + mMethodMetadata = new MethodMetadata[1]; } /** Lock protecting the non-thread safe methods in mHybridData. */ From 2ce4b272ef5ec29cdfd2f67ff576321a541d2142 Mon Sep 17 00:00:00 2001 From: Hansong Zhang Date: Tue, 20 May 2025 16:19:39 -0700 Subject: [PATCH 03/10] Linter --- .../src/main/java/org/pytorch/executorch/Module.java | 1 - 1 file changed, 1 deletion(-) diff --git a/extension/android/executorch_android/src/main/java/org/pytorch/executorch/Module.java b/extension/android/executorch_android/src/main/java/org/pytorch/executorch/Module.java index 8b2fc81ecf7..88118bdc905 100644 --- a/extension/android/executorch_android/src/main/java/org/pytorch/executorch/Module.java +++ b/extension/android/executorch_android/src/main/java/org/pytorch/executorch/Module.java @@ -9,7 +9,6 @@ package org.pytorch.executorch; import android.util.Log; - import com.facebook.jni.HybridData; import com.facebook.jni.annotations.DoNotStrip; import com.facebook.soloader.nativeloader.NativeLoader; From 2fa10fd0baae8a16addddef4c5443c821f85310a Mon Sep 17 00:00:00 2001 From: Hansong Zhang Date: Tue, 20 May 2025 17:00:43 -0700 Subject: [PATCH 04/10] Add a new method metadata class, and allow users to get methods --- .../org/pytorch/executorch/ModuleE2ETest.java | 2 +- .../executorch/ModuleInstrumentationTest.java | 2 +- .../pytorch/executorch/MethodMetadata.java | 34 ++++++++++++--- .../java/org/pytorch/executorch/Module.java | 43 ++++++++++++++++--- extension/android/jni/jni_layer.cpp | 21 +++++++++ 5 files changed, 86 insertions(+), 16 deletions(-) diff --git a/extension/android/executorch_android/src/androidTest/java/org/pytorch/executorch/ModuleE2ETest.java b/extension/android/executorch_android/src/androidTest/java/org/pytorch/executorch/ModuleE2ETest.java index 444a5166d95..cf7a234e4b3 100644 --- a/extension/android/executorch_android/src/androidTest/java/org/pytorch/executorch/ModuleE2ETest.java +++ b/extension/android/executorch_android/src/androidTest/java/org/pytorch/executorch/ModuleE2ETest.java @@ -99,7 +99,7 @@ public void testXnnpackBackendRequired() throws IOException, URISyntaxException Module module = Module.load(getTestFilePath("/mv3_xnnpack_fp32.pte")); String[] expectedBackends = new String[] {"XnnpackBackend"}; - assertArrayEquals(expectedBackends, module.getUsedBackends("forward")); + assertArrayEquals(expectedBackends, module.getMethodMetadata("forward").getBackends()); } @Test diff --git a/extension/android/executorch_android/src/androidTest/java/org/pytorch/executorch/ModuleInstrumentationTest.java b/extension/android/executorch_android/src/androidTest/java/org/pytorch/executorch/ModuleInstrumentationTest.java index 21b6a0610fd..e23b2c7abaa 100644 --- a/extension/android/executorch_android/src/androidTest/java/org/pytorch/executorch/ModuleInstrumentationTest.java +++ b/extension/android/executorch_android/src/androidTest/java/org/pytorch/executorch/ModuleInstrumentationTest.java @@ -109,7 +109,7 @@ public void testModuleLoadMethodNonExistantMethod() throws IOException{ assertEquals(loadMethod, INVALID_ARGUMENT); } - @Test + @Test(expected = RuntimeException.class) public void testNonPteFile() throws IOException{ Module module = Module.load(getTestFilePath(NON_PTE_FILE_NAME)); diff --git a/extension/android/executorch_android/src/main/java/org/pytorch/executorch/MethodMetadata.java b/extension/android/executorch_android/src/main/java/org/pytorch/executorch/MethodMetadata.java index 810c9b54cc8..b2dde35a2d8 100644 --- a/extension/android/executorch_android/src/main/java/org/pytorch/executorch/MethodMetadata.java +++ b/extension/android/executorch_android/src/main/java/org/pytorch/executorch/MethodMetadata.java @@ -8,13 +8,33 @@ package org.pytorch.executorch; -/** - * Helper class to access the metadata for a method from a Module - */ +/** Helper class to access the metadata for a method from a Module */ public class MethodMetadata { - private String name; + private String mName; + + private String[] mBackends; + + MethodMetadata setName(String name) { + mName = name; + return this; + } + + /** + * @return Method name + */ + public String getName() { + return mName; + } + + MethodMetadata setBackends(String[] backends) { + mBackends = backends; + return this; + } - public String getName() { - return name; - } + /** + * @return Backends used for this method + */ + public String[] getBackends() { + return mBackends; + } } diff --git a/extension/android/executorch_android/src/main/java/org/pytorch/executorch/Module.java b/extension/android/executorch_android/src/main/java/org/pytorch/executorch/Module.java index 9ae44accf62..1100b357a41 100644 --- a/extension/android/executorch_android/src/main/java/org/pytorch/executorch/Module.java +++ b/extension/android/executorch_android/src/main/java/org/pytorch/executorch/Module.java @@ -9,12 +9,13 @@ package org.pytorch.executorch; import android.util.Log; - import com.facebook.jni.HybridData; import com.facebook.jni.annotations.DoNotStrip; import com.facebook.soloader.nativeloader.NativeLoader; import com.facebook.soloader.nativeloader.SystemDelegate; import java.io.File; +import java.util.HashMap; +import java.util.Map; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; import org.pytorch.executorch.annotations.Experimental; @@ -49,7 +50,7 @@ public class Module { private final HybridData mHybridData; - private final MethodMetadata[] mMethodMetadata; + private final Map mMethodMetadata; @DoNotStrip private static native HybridData initHybrid(String moduleAbsolutePath, int loadMode); @@ -57,11 +58,18 @@ public class Module { private Module(String moduleAbsolutePath, int loadMode) { mHybridData = initHybrid(moduleAbsolutePath, loadMode); - populateMethodMeta(); + mMethodMetadata = populateMethodMeta(); } - void populateMethodMeta() { - mMethodMetadata = new MethodMetadata[1]; + Map populateMethodMeta() { + String[] methods = getMethods(); + Map metadata = new HashMap(); + for (int i = 0; i < methods.length; i++) { + String name = methods[i]; + metadata.put(name, new MethodMetadata().setName(name).setBackends(getUsedBackends(name))); + } + + return metadata; } /** Lock protecting the non-thread safe methods in mHybridData. */ @@ -153,13 +161,34 @@ public int loadMethod(String methodName) { private native int loadMethodNative(String methodName); /** - * Returns the names of the methods in a certain method. + * Returns the names of the backends in a certain method. * * @param methodName method name to query * @return an array of backend name */ @DoNotStrip - public native String[] getUsedBackends(String methodName); + private native String[] getUsedBackends(String methodName); + + /** + * Returns the names of methods. + * + * @return name of methods in this Module + */ + @DoNotStrip + public native String[] getMethods(); + + /** + * Get the corresponding @MethodMetadata for a method + * + * @param name method name + * @return @MethodMetadata for this method + */ + public MethodMetadata getMethodMetadata(String name) { + if (!mMethodMetadata.containsKey(name)) { + throw new RuntimeException("method " + name + "does not exist for this module"); + } + return mMethodMetadata.get(name); + } /** Retrieve the in-memory log buffer, containing the most recent ExecuTorch log entries. */ @DoNotStrip diff --git a/extension/android/jni/jni_layer.cpp b/extension/android/jni/jni_layer.cpp index 3837f091740..ffd341ab103 100644 --- a/extension/android/jni/jni_layer.cpp +++ b/extension/android/jni/jni_layer.cpp @@ -429,6 +429,26 @@ class ExecuTorchJni : public facebook::jni::HybridClass { return false; } + facebook::jni::local_ref> getMethods() { + const auto& names_result = module_->method_names(); + if (!names_result.ok()) { + facebook::jni::throwNewJavaException( + facebook::jni::gJavaLangIllegalArgumentException, + "Cannot get load module"); + } + const auto& methods = names_result.get(); + facebook::jni::local_ref> ret = + facebook::jni::JArrayClass::newArray(methods.size()); + int i = 0; + for (auto s : methods) { + facebook::jni::local_ref method_name = + facebook::jni::make_jstring(s.c_str()); + (*ret)[i] = method_name; + i++; + } + return ret; + } + facebook::jni::local_ref> getUsedBackends( facebook::jni::alias_ref methodName) { auto methodMeta = module_->method_meta(methodName->toStdString()).get(); @@ -456,6 +476,7 @@ class ExecuTorchJni : public facebook::jni::HybridClass { makeNativeMethod("loadMethodNative", ExecuTorchJni::load_method), makeNativeMethod("readLogBuffer", ExecuTorchJni::readLogBuffer), makeNativeMethod("etdump", ExecuTorchJni::etdump), + makeNativeMethod("getMethods", ExecuTorchJni::getMethods), makeNativeMethod("getUsedBackends", ExecuTorchJni::getUsedBackends), }); } From 65c347ff5c80d53feb8821d4a90f0d6de1cb3266 Mon Sep 17 00:00:00 2001 From: Hansong Zhang Date: Tue, 20 May 2025 21:19:23 -0700 Subject: [PATCH 05/10] Fix --- .../src/main/java/org/pytorch/executorch/Module.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extension/android/executorch_android/src/main/java/org/pytorch/executorch/Module.java b/extension/android/executorch_android/src/main/java/org/pytorch/executorch/Module.java index 67cb7e85f5c..96ffff5df84 100644 --- a/extension/android/executorch_android/src/main/java/org/pytorch/executorch/Module.java +++ b/extension/android/executorch_android/src/main/java/org/pytorch/executorch/Module.java @@ -83,7 +83,7 @@ public static Module load(final String modelPath, int loadMode, int numThreads) if (!modelFile.canRead() || !modelFile.isFile()) { throw new RuntimeException("Cannot load model path " + modelPath); } - return new Module((modelPath, loadMode, numThreads); + return new Module(modelPath, loadMode, numThreads); } /** From 33fae4939e28d6c6139938f37738989ceba8f81c Mon Sep 17 00:00:00 2001 From: Hansong Zhang Date: Tue, 20 May 2025 21:24:09 -0700 Subject: [PATCH 06/10] lint --- .../src/main/java/org/pytorch/executorch/Module.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/extension/android/executorch_android/src/main/java/org/pytorch/executorch/Module.java b/extension/android/executorch_android/src/main/java/org/pytorch/executorch/Module.java index 96ffff5df84..2cb592dbb94 100644 --- a/extension/android/executorch_android/src/main/java/org/pytorch/executorch/Module.java +++ b/extension/android/executorch_android/src/main/java/org/pytorch/executorch/Module.java @@ -49,7 +49,8 @@ public class Module { private final HybridData mHybridData; @DoNotStrip - private static native HybridData initHybrid(String moduleAbsolutePath, int loadMode, int initHybrid); + private static native HybridData initHybrid( + String moduleAbsolutePath, int loadMode, int initHybrid); private Module(String moduleAbsolutePath, int loadMode, int numThreads) { mHybridData = initHybrid(moduleAbsolutePath, loadMode, numThreads); From cee315916576d84d1f122d9b77181282147d7bb6 Mon Sep 17 00:00:00 2001 From: Hansong Zhang Date: Wed, 21 May 2025 00:12:57 -0700 Subject: [PATCH 07/10] rename --- .../src/main/java/org/pytorch/executorch/Module.java | 6 +++++- extension/android/jni/jni_layer.cpp | 2 +- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/extension/android/executorch_android/src/main/java/org/pytorch/executorch/Module.java b/extension/android/executorch_android/src/main/java/org/pytorch/executorch/Module.java index 2cb592dbb94..bbfd3254111 100644 --- a/extension/android/executorch_android/src/main/java/org/pytorch/executorch/Module.java +++ b/extension/android/executorch_android/src/main/java/org/pytorch/executorch/Module.java @@ -167,8 +167,12 @@ public int loadMethod(String methodName) { public native String[] getUsedBackends(String methodName); /** Retrieve the in-memory log buffer, containing the most recent ExecuTorch log entries. */ + public String[] readLogBuffer() { + return readLogBufferNative(); + } + @DoNotStrip - public native String[] readLogBuffer(); + private native String[] readLogBufferNative(); /** * Dump the ExecuTorch ETRecord file to /data/local/tmp/result.etdump. diff --git a/extension/android/jni/jni_layer.cpp b/extension/android/jni/jni_layer.cpp index a9b92658d32..936593abee8 100644 --- a/extension/android/jni/jni_layer.cpp +++ b/extension/android/jni/jni_layer.cpp @@ -456,7 +456,7 @@ class ExecuTorchJni : public facebook::jni::HybridClass { makeNativeMethod("initHybrid", ExecuTorchJni::initHybrid), makeNativeMethod("executeNative", ExecuTorchJni::execute), makeNativeMethod("loadMethodNative", ExecuTorchJni::load_method), - makeNativeMethod("readLogBuffer", ExecuTorchJni::readLogBuffer), + makeNativeMethod("readLogBufferNative", ExecuTorchJni::readLogBuffer), makeNativeMethod("etdump", ExecuTorchJni::etdump), makeNativeMethod("getUsedBackends", ExecuTorchJni::getUsedBackends), }); From 27c028115092b2b2363dbc31de9e8ca7a4448c99 Mon Sep 17 00:00:00 2001 From: Hansong Zhang Date: Wed, 21 May 2025 10:48:49 -0700 Subject: [PATCH 08/10] Fix --- .../src/main/java/org/pytorch/executorch/Module.java | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/extension/android/executorch_android/src/main/java/org/pytorch/executorch/Module.java b/extension/android/executorch_android/src/main/java/org/pytorch/executorch/Module.java index dfe933e0418..a68c180aa82 100644 --- a/extension/android/executorch_android/src/main/java/org/pytorch/executorch/Module.java +++ b/extension/android/executorch_android/src/main/java/org/pytorch/executorch/Module.java @@ -56,9 +56,8 @@ public class Module { private static native HybridData initHybrid( String moduleAbsolutePath, int loadMode, int initHybrid); -<<<<<<< HEAD - private Module(String moduleAbsolutePath, int loadMode) { - mHybridData = initHybrid(moduleAbsolutePath, loadMode); + private Module(String moduleAbsolutePath, int loadMode, int numThreads) { + mHybridData = initHybrid(moduleAbsolutePath, loadMode, numThreads); mMethodMetadata = populateMethodMeta(); } @@ -72,10 +71,6 @@ Map populateMethodMeta() { } return metadata; -======= - private Module(String moduleAbsolutePath, int loadMode, int numThreads) { - mHybridData = initHybrid(moduleAbsolutePath, loadMode, numThreads); ->>>>>>> jni-layer-cpp } /** Lock protecting the non-thread safe methods in mHybridData. */ From 8da7261a195ad0253f5aae0e80bce8c5ad40b490 Mon Sep 17 00:00:00 2001 From: Hansong Zhang Date: Wed, 21 May 2025 11:52:47 -0700 Subject: [PATCH 09/10] new test --- .../org/pytorch/executorch/ModuleInstrumentationTest.kt | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/extension/android/executorch_android/src/androidTest/java/org/pytorch/executorch/ModuleInstrumentationTest.kt b/extension/android/executorch_android/src/androidTest/java/org/pytorch/executorch/ModuleInstrumentationTest.kt index 34aadaa0983..dd3f4b880a6 100644 --- a/extension/android/executorch_android/src/androidTest/java/org/pytorch/executorch/ModuleInstrumentationTest.kt +++ b/extension/android/executorch_android/src/androidTest/java/org/pytorch/executorch/ModuleInstrumentationTest.kt @@ -55,6 +55,15 @@ class ModuleInstrumentationTest { Assert.assertTrue(results[0].isTensor) } + @Test + @Throws(IOException::class, URISyntaxException::class) + fun testMethodMetadata() { + val module = Module.load(getTestFilePath(TEST_FILE_NAME)) + + Assert.assertArrayEquals(arrayOf("forward"), module.getMethods()) + Assert.assertTrue(module.getMethodMetadata("forward").backends.isEmpty()) + } + @Test @Throws(IOException::class) fun testModuleLoadMethodAndForward() { From 35792c255e85206ca026ab3b11173326e649ece9 Mon Sep 17 00:00:00 2001 From: Hansong Zhang Date: Wed, 21 May 2025 11:55:41 -0700 Subject: [PATCH 10/10] BUCK --- extension/android/BUCK | 1 + 1 file changed, 1 insertion(+) diff --git a/extension/android/BUCK b/extension/android/BUCK index 0fad11eb677..78ee57aae90 100644 --- a/extension/android/BUCK +++ b/extension/android/BUCK @@ -8,6 +8,7 @@ non_fbcode_target(_kind = fb_android_library, srcs = [ "executorch_android/src/main/java/org/pytorch/executorch/DType.java", "executorch_android/src/main/java/org/pytorch/executorch/EValue.java", + "executorch_android/src/main/java/org/pytorch/executorch/MethodMetadata.java", "executorch_android/src/main/java/org/pytorch/executorch/Module.java", "executorch_android/src/main/java/org/pytorch/executorch/Tensor.java", "executorch_android/src/main/java/org/pytorch/executorch/annotations/Experimental.java",