pretty

Tuesday 24 July 2012

RVCT vs GCC - performance comparison on mergesort


I heard about RVCT compiler produced by ARM a lot of times. Some people are saying that it produces 30% faster code than GCC ARM compiler. Our real-time mobile application is compiled with GCC, so I decided to give RVCT a try.

I have downloaded 30-day evaluation RVDS Toolchain 4.1 which includes RVCT compiler. GCC that I use is of a little aged version 4.4.1 (July 22, 2009).

As the project we are working on is quite big and there is a lot of templates usage and so on, I would need to spend some time to make it compilable with RVCT ( "And then you discover that there are no two compilers that implement templates the same way" ). Just for now I have decided to make a small test apps to compare these compilers at first glance.

I am going to test the speed of the code that would implement two versions of a mergesort algorithm. First is iterative mergesort from here (replacing the line 34 with: l_max = (r - 1 < size) ? r - 1: size - 1;) iterative, and the second one is recursive from there . Both of the two versions I'm going to test on the same input file with 100000 unsorted integers. I generated the content for this file by heavy usage of rand() function.

The actual code looks like this, so I measure only time it takes merge to complete the sort.
DWORD t1 = GetTickCount();
mergeSort(arrayOne, arrayTwo, 100000);
DWORD t2 = GetTickCount() - t1;

On my desktop machine (Core i5-2400) the code compiled with Microsoft CL compiler with /O2 optimization took about 9-12 ms, and with optimization turned off 17-20 ms. But that's for comparison, lets move to GCC ARM and RVCT. I set GCC to -O3 optimization level, as well as RVCT. Here are the estimates for 5 consequential runs acquired on LG Optimus One P500 mobile phone with 600 MHz ARM 11 processor.

Iterative mergesort, milliseconds
RVCT - 133 135 133 135 140
GCC - 149 149 143 146 145

Recursive mergesort, milliseconds
RVCT - 92 89 88 88 91
GCC - 93 98 92 101 92

Results speak for themselves. It is prominent that in the above case implementation details of the same algorithm far outweigh the choice of a compiler. Anyway, I still have 20-something days left of evaluation for RVCT, and I am going to try it on a larger project. Upgrading GCC is an option also.

Wednesday 18 July 2012

Marmalade splash screen issue resolved (for Android)


The glorious hour's gone forth, I finally managed to display the splash screen in a Marmalade-based android application in a proper way.

As you may know there is a problem with splash screens in Marmalade SDK. That problem is not new - it has been around a year since it first emerged link to the marmalade forum. Basically this problem manifests itself (at least on Android) with a long blank screen period after program launch. After this a splashscreen is shown (either yours or standard) followed by the short blank screen period, and only after that your main() function is triggered. This might be due to initialization of glContext, however, it takes longer for the apps with more resources.

Some people suggest to show splashscreen manually from main(), but I cannot agree with this proposal because it is always too late to launch fireworks from main() see this. I've decided to approach this issue in a different way. For Android it is possible to override standard Marmalade's LoaderActivity with your own custom activity. I think you have already guessed what it means, and yes this approach works.

Now for the details and sample code. My custom activity is based on the "examples\AndroidJNI\s3eAndroidLVL" source provided with Marmalade.
package com.android.mainactivity;

import com.ideaworks3d.marmalade.LoaderActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.content.Context;
import android.widget.ImageView;
import android.view.ViewGroup.LayoutParams;
import java.util.Timer;
import java.util.TimerTask;
import android.view.ViewGroup;

public class MainActivity extends LoaderActivity {
 
    private static MainActivity m_Activity;
    private ImageView m_ImgView;
 
    private final Runnable m_UiThreadStartLogo = new Runnable(){
       public void run(){ 
           m_ImgView = new ImageView((Context)LoaderActivity.m_Activity);
           m_ImgView.setBackgroundResource(0x7f020001);
           m_ImgView.setVisibility(View.VISIBLE);
           LoaderActivity.m_Activity.addContentView(m_ImgView, new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
       }
    };
 
    private final Runnable m_UiThreadStopLogo = new Runnable(){
       public void run(){ 
           if (m_ImgView != null){
               //m_ImgView.setVisibility(View.INVISIBLE);
               ViewGroup vg = (ViewGroup)(m_ImgView.getParent());
               vg.removeView(m_ImgView);
           }
       }
    };

    public class CustomTimerTask extends TimerTask {
       public void run() {
           LoaderActivity.m_Activity.runOnUiThread(m_UiThreadStopLogo);
       }
    }

    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        m_Activity = this;
        LoaderActivity.m_Activity.runOnUiThread(m_UiThreadStartLogo);
  
        Timer timer = new Timer();
        TimerTask updateProfile = new CustomTimerTask();
        timer.schedule(updateProfile, 4000);
    }

    protected void onDestroy() {
        super.onDestroy(); 
    }
}

After building the jar file do not forget to mention it in mkb file, like this:
deployments
{
 android-custom-activity='com.android.mainactivity.MainActivity'
 android-external-jars='NativeExtensions/SplashScreenFix/java/mainactivity.jar'
...
}

In the "onCreate" method of the custom MainActivity I launch the ImageView. This ImageView is set to show the splash image. In the above case for simplicity I have put a numerical id for an image that is included in my Marmalade project through Gallery Icon setting (it doesn't have to be 170x170 if you would check the "Allow non-standart icon sizes checkbox). When the project is built for android target this image will be located in: "...\android\release\intermediate_files\res\drawable"
and you can find its numerical id in:
"...\android\release \intermediate_files\src\com\proj\myproj\R.java".

Now the splash image will be shown immediately after launch. The only trouble it woudn't go away automatically, effectively covering all your app) In the above code I hide it on timer, that is set to 4 seconds delay. The better approach would be to use jni interface and call stopLogo as the first instruction in your main(). Anyhow, I would still prefer to have timer as a last resort, to be sure that the logo screen will hide eventually.

I have used Maramalde 6.0.5 SDK.

Update:

Q:Can you give the c++ code + java modification to call stopLogo as JNI call instead of timer?

A: In your MainActivity declare "static MainActivity m_Activity" field and initialize it in OnCreate() to "this", also declare "public boolean StopMyLogo()" method, that would actually hide th logo view. To call this method from c++ take as a reference \Marmalade\6.0\examples\AndroidJNI\s3eAndroidLVL\source\s3eAndroidLVL.cpp. You should write something like this (error checking omitted):
void StopMyLogo()
{
 if (!s3eAndroidJNIAvailable()) return;
 JavaVM* jvm = (JavaVM*)s3eAndroidJNIGetVM();
 JNIEnv* env = NULL;
 jvm->GetEnv((void**)&env, JNI_VERSION_1_6);
 jclass Activity = env->FindClass("com/android/mainactivity/MainActivity");
 jfieldID fid = env->GetStaticFieldID(Activity, "m_Activity", "Lcom/android/mainactivity/MainActivity;");
 jobject m_Activity = env->GetStaticObjectField(MainActivity, fid);
 jmethodID pMethod = env->GetMethodID(MainActivity, "StopMyLogo", "()Z");
 env->CallVoidMethod(m_Activity, pMethod); //Or CallBooleanMethod()
}


Update 2 (as of September 2013) :

If you will follow Google's optimization advices for tablets and change targetSdkVersion to "14", your activity will be restarted on screen rotation event, triggering onCreate() method again! You don't want the splash screen to reappear when the user rotates a phone. Make sure you run m_UiThreadStartLogo just once. For example, you can add to activity's settings in the manifest android:configChanges="orientation|screenSize". This way activity would not be restarted when screen is about to rotate.