Android™ x86 Support

Posted on August 12, 2014

Android™ tablets and smartphones equipped with Intel Atom CPUs are getting more and more popular. Therefore the Murl Engine allows creating Android™ apps with native x86-support since version 1.00.4754Beta.

Short Summary:

  • Murl Engine provides Android™ x86 libs for all upcoming releases
  • Android™ x86 support is activated per default
  • Performance boost of about 1.6x / 2.5x

Background

Originally all Android™ devices were typically equipped with an ARM CPU. Since 2012 also Android™ devices with Intel x86 Atom CPUs are available. Some examples of Android™ devices running on Intel Architecture are: Samsung Galaxy Tab 3 10.1, Asus MemoPad FHD 10, Dell Venue 7/8, Motorola Razr I, Lenovo K900 or more recently the HP 7.

Intel developed a Binary Translator called Houdini which allows existing Android™ apps with native ARM code to run also on Android™ devices with Intel architecture. The Binary Translator reads native ARM code and on the fly translates it into equivalent x86 code.

Hence almost every ARM NDK application will run also on Android™ x86 devices without modification. However the NDK bridging technology is slower and may cause problems in certain cases. Therefore adding x86 support is in most cases the preferred option.

How It Works

All upcoming releases of the Murl Engine will also provide precompiled libraries for Android™ x86 devices. The Android™ build scripts will automatically build and include also x86 Android™ code per default.

The parameter MURL_ANDROID_CPUS can be used in the common Make file projekt/common/gnumake/module_yourapp.mk to select the supported CPU architectures for your app. Example:

MURL_ANDROID_CPUS := armeabi
MURL_ANDROID_CPUS += armeabi-v7a
MURL_ANDROID_CPUS += x86

The specified values correspond to the values of the APP_ABI parameter of the Android™ NDK build environment (ABI is short for "Application Binary Interface").

armeabi         ARM-based CPUs that support at least the ARMv5TE instruction set
armeabi-v7a     ARM-based CPUs that support ARM Architecture v7-a instruction set 
                with Thumb-2 instructions und VFPv3-D16 hardware FPU.
x86             x86-based CPUs. The NDK build uses the following gcc flags:
                -march=i686 -mtune=atom -mstackrealign -msse3 -mfpmath=sse -m32
    

The Murl Engine build scripts additionally add the parameter -mssse3. This is safe because all x86 Android™ devices support SSSE3 (see also http://ph0b.com/improving-x86-support-of-android-apps-libs-engines). Further information about the different architectures can be found in the NDK documentation in the file docs/CPU-ARCH-ABIS.html.

You can check the lib directory in your APK archive to verify that the correct libraries have been included. Remember that the .apk file is an archive file compressed with the zip format. You can e.g. rename it to .zip and view/extract the content with your favorite compression tool.

Is It Worth It?

The performance gain resulting from the use of native x86 code compared to the use of the Binary Translator obviously depends on the type of app, the used features and furthermore on the version of the Binary Translator. To get a better feeling we did some simple benchmark testing with the Murl Engine. Please note that this simple tests are not suited to deduce a general conclusion about performance gain you would see in production code. Hence, you may wish to do your own testing.

An Asus Memo Pad FHD 10 was used as test device, which was generously lent to us by Intel. The tablet is equipped with a dual core 1.6 GHz Intel® Atom™ Z2560 CPU with an integrated PowerVR SGX544 GPU and has a 10.1 inch WUXGA display with a resolution of 1920 x 1200 pixel.

The test results with the Murl Engine show that on average the armeabi-v7a code runs 1.6 times slower and armeabi code runs 2.5 times slower than native x86 code. Detailed information about the performed tests can be found below.

App Size

The additional x86 files will of course increase the overall size of the APK file. If the app size is a critical factor, you may want to consider splitting the app into individual APK files for every cpu architecture. When doing so, please note that the version code of the x86 APK needs to be greater than the version code of the ARM APK (parameter MURL_ANDROID_VERSION_CODE in the common Make file).

x86 version code > armeabi-v7a version code > armeabi version code

Google Play will serve the compatible APK with the highest version number. Further information can be found in section Multiple APK Support of the Android™ developer documentation.

Benchmarks

An Asus Memo Pad FHD 10 has been used to execute the tests. The values reflect the needed processing time. Hence greater values are worse than lesser values.

Summary

x86 armeabi-v7a armeabi
GenerateData 100% 150% 249%
Calc UInt32 100% 190% 239%
Sort Array 100% 174% 208%
Calc Pi 100% 149% 367%
Scenegraph 100% 131% 180%

GenerateData

Create 20,000,000 random values and store them in three initial empty containers (UInt32Array, FloatArray, DoubleArray).

    Util::TT800 rng(42);
    UInt32Array uInt32Array;
    FloatArray floatArray;
    DoubleArray doubleArray;
    for (UInt32 i = 0; i < mMax; i++)
    {
        UInt32 val = rng.Rand();
        uInt32Array.Add(val);
        floatArray.Add(Float(val));
        doubleArray.Add(Double(val));
    }
    
t [ms] x86 armeabi-v7a armeabi
average value 5837 8728 14517
relative standard deviation 0.99% 0.79% 1.79%
relative difference 100% 150% 249%

Calc UInt32

Calculate a UInt32 value from the 20,000,000 randomly generated values in the container.

    UInt32 a = 0;
    UInt32 lastIndex = uInt32Array.GetCount() - 1;
    for (UInt32 i = 0; i < lastIndex; i++)
    {
        a += (uInt32Array[lastIndex-i] * uInt32Array[i]) / 2147483648;
    }
    
t [ms] x86 armeabi-v7a armeabi
average value 130 247 310
relative standard deviation 0.00% 2.34% 0.00%
relative difference 100% 190% 238%

Sort Array

Sort a UInt32Array with 2,000,000 random numbers using the quicksort algorithm.

    Util::SortArray(uInt32Array, false);
    
t [ms] x86 armeabi-v7a armeabi
average value 1581 2753 3282
relative standard deviation 0.46% 0.76% 1.09%
relative difference 100% 174% 208%

Calc PI

Calculate the number Pi using the Leibniz formula with 40,000,000 summands.

    Double quaterpi = 1;
    UInt32 divisor = 3;
    for (UInt32 i=0; i < mMax; i++)
    {
        quaterpi -= Double(1) / divisor;
        divisor  += 2;
        quaterpi += Double(1) / divisor;
        divisor  += 2;
    }
    
t [ms] x86 armeabi-v7a armeabi
average value 1933 2883 7093
relative standard deviation 0.05% 0.14% 0.08%
relative difference 100% 149% 367%

Scenegraph

Process a scene graph with 20,000 sprite objects which will be rendered on random positions.

    SInt32 widthX = (state->GetAppConfiguration()->GetDisplaySurfaceSizeX() - 64) / 2;
    SInt32 widthY = (state->GetAppConfiguration()->GetDisplaySurfaceSizeY() - 64) / 2;
    Graph::IRoot* root = state->GetGraphRoot();
    const Graph::INodeArray& spriteList = mSpriteGroup->GetChildren();
    UInt32 count = spriteList.GetCount();
    Util::TT800 rng;
    for (UInt32 i = 0; i < count; i++)
    {
        Graph::ITransform* node = (dynamic_cast<Graph::IPlaneGeometry*>(spriteList[i]))->GetTransformInterface();
        node->SetPosition(rng.RandSInt(-widthX, widthX),rng.RandSInt(-widthY, widthY),0);
    }
    
t [ms] x86 armeabi-v7a armeabi
average value 129.1 169. 233.0
relative standard deviation 2.45% 1.05% 2.00%
relative difference 100% 131% 180%


Don't miss out on any update,
subscribe to our newsletter.


Copyright © 2011-2017 Spraylight GmbH.