Performance degradation in Java – Android – RenderScript – SDK 21

Performance degradation in Java – Android – RenderScript – SDK 21 … here is a solution to the problem.

Performance degradation in Java – Android – RenderScript – SDK 21

I’m working on a project that requires complex Photoshop type blending effects. I’m using a custom RenderScript script to solve this problem.

I’ve been testing it on my Samsung Galaxy S4 device running Kitkat and everything works well and very fast.

Then I tried to test it on a Nexus 5 running Lollipop and I noticed a sudden drop in performance.

I started timing the various parts in the code to see which ones were slowing down and came to the following conclusion:

Allocation.createFromBitmap
- Runtime on Kitkat - ~5-10 millisec
- Runtime on Lollipop - ~100-150 millisec

mRenderScript.destory()
- Runtime on Kitkat - ~1-3 millisec
- Runtime on Lollipop - ~60-100 millisec

I’m curious why performance suddenly drops when creating Allocation objects and destroying RenderScript objects on devices that should be more powerful, compared to more advanced operating systems.

Is there anything I can do for the API 21 OS to make these methods run faster?

Has anyone encountered this issue or can reproduce it?

I should have noticed that the actual run of the script (i.e. the ScriptC.forEach method) runs very fast on both devices/OS. Also, I’m using the native RenderScript API, not any supporting libraries.

Any comments would be appreciated.

Edit:

Here I copied the relevant line of the Androids Lollipop-release source code in Github Allocation.java

static public Allocation createFromBitmap(RenderScript rs, Bitmap b) {
        if (rs.getApplicationContext().getApplicationInfo().targetSdkVersion >= 18) {
            return createFromBitmap(rs, b, MipmapControl.MIPMAP_NONE,
                                    USAGE_SHARED | USAGE_SCRIPT | USAGE_GRAPHICS_TEXTURE);
        }
        return createFromBitmap(rs, b, MipmapControl.MIPMAP_NONE,
                                USAGE_GRAPHICS_TEXTURE);
    }

Notice how Allocation is created by default using the USAGE_SHARED flag when the target SDK is higher than 17. Could it be that these extra flags are causing the problem? Should I use the USAGE_GRAPHICS_TEXTURE flag instead?

Edit 2

Watching R. Jason Sam’s suggestion when When the Nexus 5 is connected to my computer, I run the following script:

adb shell setprop debug.rs.default-CPU-driver 1

After that, the run time of the above functions is significantly faster (~30-40 ms and 20-50 ms, respectively). Still not as fast as the device before Lollipop, but within acceptable performance limits.

The only problem I have with this solution is that unless I don’t understand something, it can’t be considered a solution because it requires me to call this script on every problematic device before I can run the app on it.

Is there anything I can do in my code to simulate this adb call?

Final edit

Well, the problem seems to stem from the fact that I’m creating a new RenderScript object every time I call a function that uses RenderScript to perform blending effects.

I

did some code refactoring, and now, instead of creating a new RenderScript object every time the effect method is called, I reuse the same object every time. Creating the first creation of a RenderScript object on a Lollipop device still takes longer, but now the problem is mitigated because I continue to reuse the same object across multiple method calls.

I’ll add it as an answer.

Solution

The problem seems to stem from the fact that every time I call a function that uses RenderScript to perform blending effects, I’m creating a new RenderScript object.

I

did some code refactoring, and now, instead of creating a new RenderScript object every time the effect method is called, I reuse the same object every time. The first creation of a RenderScript object still takes longer to create on a Lollipop device, but now the problem is mitigated because I continue to reuse the same object in multiple method calls.

Once I’m sure I don’t need it anymore to make sure there are no memory leaks, I’ll definitely call destory() on the shared RenderScript object.

According to the this post, it seems that RenderScript is reused object rather than creating a new one every time is fair practice, but I’m happy to hear from others about their experiences in this matter. It’s a pity that there isn’t much documentation on this topic online, but so far everything seems to work fine on multiple devices/operating systems.

Related Problems and Solutions