Skip to content

Instantly share code, notes, and snippets.

@paulproteus
Last active June 30, 2020 02:29
Show Gist options
  • Save paulproteus/85395702cd78bb9a92bea06ff28ca7c9 to your computer and use it in GitHub Desktop.
Save paulproteus/85395702cd78bb9a92bea06ff28ca7c9 to your computer and use it in GitHub Desktop.
Performance notes for BeeWare/Android/Python

Current performance worries

  • Unpacking stdlib is very slow. See "things that look promising" below.

  • There's a somewhat sad trade-off between disk I/O being slow on one hand, and bytecode-compiling PYCs being slow on the other.

Things I tried that look promising:

  • If you put the Python *.so modules in the jniLibs directory, then you can add it to PYTHONPATH, ignore PYTHONHOME, and import the libs straight from jnilibs-land. Not bad.

  • Therefore I can probably oxidized_importer-ify stdlib's pure-Python parts, and perhaps even add PYCs to that. TBD. I can use ZipFile to read the oxidized_importer data straight out of the APK, which would do a copy, but that's OK.

  • Switching to checked-hash or unchecked-hash invalidation mode for PYCs looks very, very promising. SOURCE_DATE_EPOCH in the environment during build and runtime is one way to cause that.

Things I tried that didn't work out:

  • If I use zipimport to wrap the stdlib, I think it's really slow when zipimport fails to do an import? Seems odd.

  • Remove list() from rubicon-java java/api.py itertools.product() call -- didn't seem to change anything (but I didn't necessarily benchmark well)

  • Switch rubicon-java java/api.py to a less exception-heavy idiom -- actually I never really tried this

  • Make stdlib a ZIP file -- this only ever worsened second-launch. Note that you have to do zipfile.zip/lib/python3.7 to get the stdlib to be findable.

  • Using oxidized_importer -- well, I didn't try this for stdlib, it's probably peaceful for stdlib

  • Adding PYCs to stdlib -- I very briefly tested this but didn't record results well

  • Doing less JavaClass definition work at import time -- all of android_widgets.py takes a mere 10ms to import tops, and 10ms is fine.

  • Implementing a getMethod() method. I half-tried this. My measurement environment is so noisy, but I think that the following (if added to toga's src/android/toga_android/libs/activity.py) should save 80ms or so. Is that enough to break the abstraction layer? Probably. Only TextView is as painful to deal with; other classes are just fast (approx 1ms). Maybe they don't have as many methods.

# Performance optimization: explicitly get a reference to the
# setPythonApp method for efficiency. This allows us to skip
# rubicon-java's convenient machinery for making Python stubs
# dynamically for Java methods.
def set_python_app(python_app):
    java_method =  java.GetStaticMethodID(MainActivity.__jni__,
        b"setPythonApp", b"(Lorg/beeware/android/IPythonApp;)V")
    java.CallStaticVoidMethod(MainActivity.__jni__, java_method, python_app)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment