简体   繁体   中英

Why does adding an If-statement inside a this method slow it down so drastically?

I came across this in answering another question . I was trying to diagnose which code change had a greater effect on the speed. I used a boolean flag in a for loop to switch between using helper methods to construct a Color .

The interesting behavior is that when I decided which one was faster and removed the if the speed of the code amplified 10x. Taking 140ms before and just 13ms afterward. I should only be removing one calculation out of about 7 from the loop. Why such a drastic increase in speed?

Slow code: (runs in 141 milliseconds when helperMethods is false) *See edit 2

public static void applyAlphaGetPixels(Bitmap b, Bitmap bAlpha, boolean helperMethods) {
    int w = b.getWidth();
    int h = b.getHeight();
    int[] colorPixels = new int[w*h];
    int[] alphaPixels = new int[w*h];
    b.getPixels(colorPixels, 0, w, 0, 0, w, h);
    bAlpha.getPixels(alphaPixels, 0, w, 0, 0, w, h);
    for(int j = 0; j < colorPixels.length;j++){
        if(helperMethods){
            colorPixels[j] = Color.argb(Color.alpha(alphaPixels[j]), Color.red(colorPixels[j]), Color.green(colorPixels[j]), Color.blue(colorPixels[j]));
        } else colorPixels[j] = alphaPixels[j] | (0x00FFFFFF & colorPixels[j]);
    }
    b.setPixels(colorPixels, 0, w, 0, 0, w, h);
}

Fast Code: (Runs in 13ms)

public static void applyAlphaGetPixels(Bitmap b, Bitmap bAlpha) {
    int w = b.getWidth();
    int h = b.getHeight();
    int[] colorPixels = new int[w*h];
    int[] alphaPixels = new int[w*h];
    b.getPixels(colorPixels, 0, w, 0, 0, w, h);
    bAlpha.getPixels(alphaPixels, 0, w, 0, 0, w, h);
    for(int j = 0; j < colorPixels.length;j++){
        colorPixels[j] = alphaPixels[j] | (0x00FFFFFF & colorPixels[j]);
    }
    b.setPixels(colorPixels, 0, w, 0, 0, w, h);
}

EDIT: It seems the issue is not with the fact that the if is inside the loop. If I elevate the if outside of the loop. The code runs slightly faster but still at the slow speeds with 131ms:

public static void applyAlphaGetPixels(Bitmap b, Bitmap bAlpha, boolean helperMethods) {
    int w = b.getWidth();
    int h = b.getHeight();
    int[] colorPixels = new int[w*h];
    int[] alphaPixels = new int[w*h];
    b.getPixels(colorPixels, 0, w, 0, 0, w, h);
    bAlpha.getPixels(alphaPixels, 0, w, 0, 0, w, h);
    if (helperMethods) {
        for (int j = 0; j < colorPixels.length;j++) {
            colorPixels[j] = Color.argb(Color.alpha(alphaPixels[j]),
                                        Color.red(colorPixels[j]),
                                        Color.green(colorPixels[j]),
                                        Color.blue(colorPixels[j]));
        }
    } else {
        for (int j = 0; j < colorPixels.length;j++) {
             colorPixels[j] = alphaPixels[j] | (0x00FFFFFF & colorPixels[j]);
        }
    }

    b.setPixels(colorPixels, 0, w, 0, 0, w, h);
}

EDIT 2: I'm dumb. Really really dumb. Earlier in the call stack I used another boolean flag to switch between between using this method and using another method that uses getPixel instead of getPixels . I had this flag set wrong for all of my calls that have the helperMethod parameter. When I made new calls to the version without helperMethod I did it correct. The performance boost is because of getPixels not the if statement.

Actual Slow code:

public static void applyAlphaGetPixel(Bitmap b, Bitmap bAlpha, boolean helperMethods) {
    int w = b.getWidth();
    int h = b.getHeight();
    for(int y=0; y < h; ++y) {
        for(int x=0; x < w; ++x) {
            int pixel = b.getPixel(x,y);
            int finalPixel;
            if(helperMethods){
                finalPixel = Color.argb(Color.alpha(bAlpha.getPixel(x,y)), Color.red(pixel), Color.green(pixel), Color.blue(pixel));
            } else{
                finalPixel = bAlpha.getPixel(x,y) | (0x00FFFFFF & pixel);
            }
            b.setPixel(x,y,finalPixel);
        }
    }
}

Note:All speeds are an average of 100 runs.

Try hoisting the condition out of the loop:

if (helperMethods) {
    for (int j = 0; j < colorPixels.length;j++) {
        colorPixels[j] = Color.argb(Color.alpha(alphaPixels[j]),
                                    Color.red(colorPixels[j]),
                                    Color.green(colorPixels[j]),
                                    Color.blue(colorPixels[j]));
    }
} else {
    for (int j = 0; j < colorPixels.length;j++) {
         colorPixels[j] = alphaPixels[j] | (0x00FFFFFF & colorPixels[j]);
    }
}

In the 'fast code' you never run the statement

colorPixels[j] = Color.argb(Color.alpha(alphaPixels[j]), Color.red(colorPixels[j]), Color.green(colorPixels[j]), Color.blue(colorPixels[j])); 

But in the 'slow code' if the boolean is set to true at least once you run this addiotional statement that makes the time longer. If your condition is always false then the if statement is checked about 7 times in each iteration through the loop. Try to place the if outside the loop.

It is probably your profiling code, that confusing you. Try to isolate the part of the code that you want to profile and just measure that part, avoid GCable operations like creating Bitmaps in your cases.

If I call your test code with

testing.loadDrawable(this, false, true, false)

it runs slow. But if I call it with

testing.loadDrawable(this, true, true, false)

That's a similar (still worse) number. So useGetPixels makes all the difference. Which I guess gets the Bitmap data into a local buffer and set the results later.

In your fast code you don't use class Color at all. I assume initialization of this class takes some time, it has lots of static method and static code.

You can try to do following: make sure Color class is fully loaded and initialized before making your test (you can call any static method from Color class before calling your applyAlphaGetPixels() method). Then run your test and compare results.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM