99package org .pytorch .executorch ;
1010
1111import android .util .Log ;
12+
13+ import com .facebook .jni .HybridData ;
14+ import com .facebook .jni .annotations .DoNotStrip ;
1215import com .facebook .soloader .nativeloader .NativeLoader ;
1316import com .facebook .soloader .nativeloader .SystemDelegate ;
1417import java .io .File ;
2427@ Experimental
2528public class Module {
2629
30+ static {
31+ if (!NativeLoader .isInitialized ()) {
32+ NativeLoader .init (new SystemDelegate ());
33+ }
34+ // Loads libexecutorch.so from jniLibs
35+ NativeLoader .loadLibrary ("executorch" );
36+ }
37+
2738 /** Load mode for the module. Load the whole file as a buffer. */
2839 public static final int LOAD_MODE_FILE = 0 ;
2940
@@ -36,10 +47,16 @@ public class Module {
3647 /** Load mode for the module. Use memory locking and ignore errors. */
3748 public static final int LOAD_MODE_MMAP_USE_MLOCK_IGNORE_ERRORS = 3 ;
3849
39- /** Reference to the NativePeer object of this module. */
40- private NativePeer mNativePeer ;
50+ private final HybridData mHybridData ;
51+
52+ @ DoNotStrip
53+ private static native HybridData initHybrid (String moduleAbsolutePath , int loadMode );
4154
42- /** Lock protecting the non-thread safe methods in NativePeer. */
55+ private Module (String moduleAbsolutePath , int loadMode ) {
56+ mHybridData = initHybrid (moduleAbsolutePath , loadMode );
57+ }
58+
59+ /** Lock protecting the non-thread safe methods in mHybridData. */
4360 private Lock mLock = new ReentrantLock ();
4461
4562 /**
@@ -50,14 +67,11 @@ public class Module {
5067 * @return new {@link org.pytorch.executorch.Module} object which owns the model module.
5168 */
5269 public static Module load (final String modelPath , int loadMode ) {
53- if (!NativeLoader .isInitialized ()) {
54- NativeLoader .init (new SystemDelegate ());
55- }
5670 File modelFile = new File (modelPath );
5771 if (!modelFile .canRead () || !modelFile .isFile ()) {
5872 throw new RuntimeException ("Cannot load model path " + modelPath );
5973 }
60- return new Module (new NativePeer ( modelPath , loadMode ) );
74+ return new Module (modelPath , loadMode );
6175 }
6276
6377 /**
@@ -70,10 +84,6 @@ public static Module load(final String modelPath) {
7084 return load (modelPath , LOAD_MODE_FILE );
7185 }
7286
73- Module (NativePeer nativePeer ) {
74- this .mNativePeer = nativePeer ;
75- }
76-
7787 /**
7888 * Runs the 'forward' method of this module with the specified arguments.
7989 *
@@ -83,16 +93,7 @@ public static Module load(final String modelPath) {
8393 * @return return value from the 'forward' method.
8494 */
8595 public EValue [] forward (EValue ... inputs ) {
86- try {
87- mLock .lock ();
88- if (mNativePeer == null ) {
89- Log .e ("ExecuTorch" , "Attempt to use a destroyed module" );
90- return new EValue [0 ];
91- }
92- return mNativePeer .forward (inputs );
93- } finally {
94- mLock .unlock ();
95- }
96+ return execute ("forward" , inputs );
9697 }
9798
9899 /**
@@ -105,16 +106,19 @@ public EValue[] forward(EValue... inputs) {
105106 public EValue [] execute (String methodName , EValue ... inputs ) {
106107 try {
107108 mLock .lock ();
108- if (mNativePeer == null ) {
109+ if (! mHybridData . isValid () ) {
109110 Log .e ("ExecuTorch" , "Attempt to use a destroyed module" );
110111 return new EValue [0 ];
111112 }
112- return mNativePeer . execute (methodName , inputs );
113+ return executeNative (methodName , inputs );
113114 } finally {
114115 mLock .unlock ();
115116 }
116117 }
117118
119+ @ DoNotStrip
120+ private native EValue [] executeNative (String methodName , EValue ... inputs );
121+
118122 /**
119123 * Load a method on this module. This might help with the first time inference performance,
120124 * 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) {
127131 public int loadMethod (String methodName ) {
128132 try {
129133 mLock .lock ();
130- if (mNativePeer == null ) {
134+ if (! mHybridData . isValid () ) {
131135 Log .e ("ExecuTorch" , "Attempt to use a destroyed module" );
132136 return 0x2 ; // InvalidState
133137 }
134- return mNativePeer . loadMethod (methodName );
138+ return loadMethodNative (methodName );
135139 } finally {
136140 mLock .unlock ();
137141 }
138142 }
139143
144+ @ DoNotStrip
145+ private native int loadMethodNative (String methodName );
146+
140147 /**
141148 * Returns the names of the methods in a certain method.
142149 *
143150 * @param methodName method name to query
144151 * @return an array of backend name
145152 */
146- public String [] getUsedBackends (String methodName ) {
147- return mNativePeer .getUsedBackends (methodName );
148- }
153+ @ DoNotStrip
154+ public native String [] getUsedBackends (String methodName );
149155
150156 /** Retrieve the in-memory log buffer, containing the most recent ExecuTorch log entries. */
151- public String [] readLogBuffer () {
152- return mNativePeer .readLogBuffer ();
153- }
157+ @ DoNotStrip
158+ public native String [] readLogBuffer ();
154159
155160 /**
156161 * Dump the ExecuTorch ETRecord file to /data/local/tmp/result.etdump.
@@ -160,9 +165,8 @@ public String[] readLogBuffer() {
160165 * @return true if the etdump was successfully written, false otherwise.
161166 */
162167 @ Experimental
163- public boolean etdump () {
164- return mNativePeer .etdump ();
165- }
168+ @ DoNotStrip
169+ public native boolean etdump ();
166170
167171 /**
168172 * Explicitly destroys the native Module object. Calling this method is not required, as the
@@ -173,13 +177,11 @@ public boolean etdump() {
173177 public void destroy () {
174178 if (mLock .tryLock ()) {
175179 try {
176- mNativePeer .resetNative ();
180+ mHybridData .resetNative ();
177181 } finally {
178- mNativePeer = null ;
179182 mLock .unlock ();
180183 }
181184 } else {
182- mNativePeer = null ;
183185 Log .w (
184186 "ExecuTorch" ,
185187 "Destroy was called while the module was in use. Resources will not be immediately"
0 commit comments