Android Studio Hot Swap providing unexplained performance boost

  • Replies:2
  • OpenNot stickiedUnanswered
  • Forum posts: 2

May 17, 2017 9:42:41 PM via Website

I've made an image processing algorithm (some nested for loops checking byte values and changing them) for an app I'm making for my Samsung Galaxy S4. When I launch the app the algorithm takes around 50 - 70 ms per frame. However, if I then do a Hot Swap, even if the only change is adding an unused variable, the time taken goes down to 5 - 10 ms. According to Logcat, memory and CPU usage does not change. I'm using Android Studio 2.3.1 with gradle 3.3.

Does anyone have any idea at all what might be causing this? I'd like to have the improved performance by default.

  • Forum posts: 54

May 18, 2017 5:42:03 PM via Website

Maybe there is a possibility to use any premade 3rd part library which is efficient and optimized? If no, then maybe you could post any code snippet or pseudo-code so we will be able to suggest on how to improve it.
P.S. nice nick, I guess what country are you from (lightbulb)

  • Forum posts: 2

May 18, 2017 6:04:48 PM via Website

Well, I'm not sure if such an algorithm is used anywhere, so my best guess would be that I won't find it online. I'm using OpenCV, that's where the Mat comes from. Although I do not think there is much optimisation to be done to the code itself, it must be something to do with Android Studio... Well, either way, here's the code (the website messed up the indentation):

public static Mat dissolve(Mat inputImage, final int checkLength, final int stepSize, int type)
{
    // check input format
    if(inputImage.channels() != 1)
        throw new IllegalArgumentException("Input image must have one channel. Found: " + inputImage.channels());

    // ensure the matrix is continuous.
    if(!inputImage.isContinuous())
        inputImage = Mem.add(inputImage.clone());

    // get byte array
    final byte[] dataIn = new byte[(int) inputImage.total()];
    inputImage.get(0, 0, dataIn);

    // create output array
    final byte[] dataOut = new byte[dataIn.length];

    // some value pre-calcs
    final int imgCols = inputImage.cols();
    final int yDelimiter = inputImage.rows() - checkLength;
    final int xDelimiter = inputImage.cols() - checkLength;

    // select an algorithm and process it
    switch (type)
    {
        case TYPE_X: processTypeX(checkLength, stepSize, imgCols, xDelimiter, yDelimiter, dataIn, dataOut); break; // This is never called
        case TYPE_L: processTypeL(checkLength, stepSize, imgCols, xDelimiter, yDelimiter, dataIn, dataOut); break; // This is always called
        default: throw new IllegalArgumentException("type must be selected from the static options (which are int values 1 and 2). Found: " + type);
    }

    // return adjusted mat
    Mat mat = inputImage.clone();
    mat.put(0, 0, dataOut);
    return mat;
}

private static void processTypeL(int checkLength, int stepSize, int imgCols, int xDelimiter, int yDelimiter, byte[] dataIn, byte[] dataOut)
{
for (int y = checkLength; y < yDelimiter; y++)
{
for (int x = checkLength; x < xDelimiter; x++)
{
boolean xOk = true;
boolean yOk = true;

            // get left
            int rowModifier = y * imgCols;
            int maxX = x + rowModifier;
            int minX = x - checkLength + rowModifier;
            for (int xLoc = minX; xLoc < maxX; xLoc += stepSize)
            {
                if (dataIn[xLoc] == 0)
                {
                    xOk = false;
                    break;
                }
            }

            // get right
            if (!xOk)
            {
                xOk = true; // if this one suceeds, that's fine
                maxX = x + checkLength + rowModifier;
                minX = x + rowModifier;
                for (int xLoc = minX; xLoc < maxX; xLoc += stepSize)
                {
                    if (dataIn[xLoc] == 0)
                    {
                        xOk = false;
                        break;
                    }
                }
            }


            // only check the other axis if x is OK, because we need both
            if (xOk)
            {
                // get top
                int maxY = ((y + checkLength) * imgCols) + x;
                int minY = (y * imgCols) + x;
                int stepSizeMult = imgCols * stepSize;
                for (int yLoc = minY; yLoc < maxY; yLoc += stepSizeMult)
                {
                    if (dataIn[yLoc] == 0)
                    {
                        yOk = false;
                        break;
                    }
                }

                // get bottom
                if (!yOk)
                {
                    yOk = true;
                    maxY = (y * imgCols) + x;
                    minY = ((y - checkLength) * imgCols) + x;
                    for (int yLoc = minY; yLoc < maxY; yLoc += stepSizeMult)
                    {
                        if (dataIn[yLoc] == 0)
                        {
                            yOk = false;
                            break;
                        }
                    }
                }

                dataOut[rowModifier + x] = (yOk && xOk ? (byte) -1 : (byte) 0);

            }
        }
    }
}

And I think you got the country right ;)