Any idea why recent Android Mode versions are slower than older ones?

edited April 2016 in Android Mode

I did a basic test to compare the versions for which PApplet extends Fragment against versions for which PApplet extends Activity. in terms of frame rates.

My test consisted of displaying lots of ellipses, with background() being called at each frame.

http://imgur.com/a/e2Bvx

As seen in the above pictures, the older version (Release 0239) had as much as 72% more frames than the newer one (Release 0249) for a dot count of 500.

I used the following code:

ArrayList<Dot> dots = new ArrayList<Dot>();

@ Override
public void settings() {
    //Call size/fullscreen from here
    fullScreen(PConstants.P3D);
}

@ Override
public void setup() {
    textSize(displayWidth/20);
}

@ Override
public void draw() {
    background(0);
    for (Dot dot : dots){
        dot.move();
        dot.display();
    }
    noStroke();
    fill(150,0,0);
    rect(0,0,displayWidth, displayHeight/10);
    fill(255);
    text("Release 0249: #dots: " + dots.size() + ", frameRate: " + (int)(frameRate), 0, displayHeight/20);
}

@ Override
public void mouseDragged(){
    dots.add(new Dot());
}

@ Override
public void mousePressed(){
    if (mouseY <= displayHeight/10){
        dots.clear();
    }else{
        dots.add(new Dot(true));
    }
}

class Dot {
    float x, y;
    float speedX, speedY;
    int r = MainActivity.randInt(0 , 255);
    int g = MainActivity.randInt(0 , 255);
    int b = MainActivity.randInt(0 , 255);

    Dot(){
        x = mouseX;
        y = mouseY;
        speedX = (mouseX - pmouseX)/5;
        speedY = (mouseY - pmouseY)/5;
    }

    Dot(boolean mousePressed){
        x = mouseX;
        y = mouseY;
    }

    void display(){
        fill(r,g,b);
        ellipse(x, y, displayWidth/30, displayWidth/30);
    }

    void move(){
        accelerate();
        checkBounds();
        x += speedX;
        y += speedY;
    }

    void checkBounds(){
        if (x <= 0){
            speedX *= -1;
            x = 0;
        }else if (x >= displayWidth){
            speedX *= -1;
            x = displayWidth;
        }
        if (y <= 0){
            speedY *= -1;
            y = 0;
        }else if (y >= displayHeight){
            speedY *= -1;
            y = displayHeight;
        }
    }

    void accelerate(){
        speedX += MainActivity.randInt(-displayWidth/800, displayWidth/800);
        speedY += MainActivity.randInt(-displayWidth/800, displayWidth/800);
    }
}

Hopefully the code is formatted well...

Press or drag to create dots. Touch red area to reset. Read red area info to draw conclusions. The same code was used for both versions apart from sketchRenderer() instead of settings() - shouldn't make a difference.

The test above uses dots. But it would be great to test other stuff, like images, lines, pshapes etc. and under different cases (different renderers etc.) It would be great if you could emulate the test and confirm if you reach the same conclusion. Different releases are here:

https://github.com/processing/processing-android/releases

So, assuming my results are correct, my main question is: why are newer releases slower than older ones? Is this related to the fact that older ones extend Activity and newer ones extend Fragment?

Any thoughts appreciated.

Answers

  • edited April 2016

    @wit221

    I just tried your code and am getting very different results to you. I am guessing you are not using the Processing IDE? I edited it a bit to get it to run from the Processing IDE (as below) (the MainActivity references threw errors and i can't see a need for settings() or the @ Overrides?

    I couldn't get 239 to run at all, probably because I am on 3.0.1 and it needs an earlier processing release? But I did try 246, 248 and 249...

    249 has a bad bug that just shows a grey screen (reported elsewhere) but 246 and 248 both give me a 58/59 fps for 500 ellipses and even at 1000 ellipses I am still getting about 40 fps. Both much higher than the rates you are getting!

    Maybe not using PDE is the issue for you?

        ArrayList<Dot> dots = new ArrayList<Dot>();
    
        public void setup() {
            textSize(displayWidth/20);
        }
    
        public void draw() {
            background(0);
            for (Dot dot : dots){
                dot.move();
                dot.display();
            }
            noStroke();
            fill(150,0,0);
            rect(0,0,displayWidth, displayHeight/10);
            fill(255);
            text("Release 0248: #dots: " + dots.size() + ", frameRate: " + (int)(frameRate), 0, displayHeight/20);
        }
    
        public void mouseDragged(){
            dots.add(new Dot());
        }
    
        public void mousePressed(){
            if (mouseY <= displayHeight/10){
                dots.clear();
            }else{
                dots.add(new Dot(true));
            }
        }
    
        class Dot {
            float x, y;
            float speedX, speedY;
            int r = (int)random(0 , 255);
            int g = (int)random(0 , 255);
            int b = (int)random(0 , 255);
    
            Dot(){
                x = mouseX;
                y = mouseY;
                speedX = (mouseX - pmouseX)/5;
                speedY = (mouseY - pmouseY)/5;
            }
    
            Dot(boolean mousePressed){
                x = mouseX;
                y = mouseY;
            }
    
            void display(){
                fill(r,g,b);
                ellipse(x, y, displayWidth/30, displayWidth/30);
            }
    
            void move(){
                accelerate();
                checkBounds();
                x += speedX;
                y += speedY;
            }
    
            void checkBounds(){
                if (x <= 0){
                    speedX *= -1;
                    x = 0;
                }else if (x >= displayWidth){
                    speedX *= -1;
                    x = displayWidth;
                }
                if (y <= 0){
                    speedY *= -1;
                    y = 0;
                }else if (y >= displayHeight){
                    speedY *= -1;
                    y = displayHeight;
                }
            }
    
            void accelerate(){
                speedX += (int)random(-displayWidth/800, displayWidth/800);
                speedY += (int)random(-displayWidth/800, displayWidth/800);
            }
        }
    
  • edited April 2016

    Thank for your comment. The disparities in results are interesting.

    I am including a different code that is good for working in PDE. Also, it includes the possibility to create triangles, lines, rectangles on top of dots - more ways to compare versions. Again, press the triangle box to reset all triangles - same for other shapes.

    import java.util.ArrayList;
    import java.util.Random;
    int dots, lines, rects, triangles;
    ArrayList < Item > items = new ArrayList < Item > ();
    static Random rand = new Random();
    
    public static int randInt(double min, double max) {
     return rand.nextInt(((int) max - (int) min) + 1) + (int) min;
    }
    
    public static float randFloat(float min, float max) {
     return min + rand.nextFloat() * (max - min);
    }
    
    public void setup() {
     textSize(displayWidth / 20);
    }
    
    public void draw() {
     background(0);
    
     stroke(255);
     strokeWeight((float)(0.005 * displayWidth));
     line(0, (float)(0.625 * displayHeight), displayWidth, (float)(0.625 * displayHeight));
     line((float)(0.5 * displayWidth), (float)(0.25 * displayHeight), (float)(0.5 * displayWidth), displayHeight);
    
     for (Item item: items) {
      item.move();
      item.display();
     }
     noStroke();
    
     fill(150, 0, 0, 150);
     rect(0, 0, displayWidth, displayHeight / 20);
    
     fill(0, 150, 0, 150);
     rect(0, (float)(0.05 * displayHeight), displayWidth, displayHeight / 20);
    
     fill(0, 0, 150, 150);
     rect(0, (float)(0.1 * displayHeight), displayWidth, displayHeight / 20);
    
     fill(150, 0, 150, 150);
     rect(0, (float)(0.15 * displayHeight), displayWidth, displayHeight / 20);
    
     fill(150, 150, 0, 150);
     rect(0, (float)(0.2 * displayHeight), displayWidth, displayHeight / 20);
    
     fill(255);
     text("Release 0239: #items: " + items.size() + ", frameRate: " + (int)(frameRate), 0, (float)(0.04 * displayHeight));
     text("Ellipses: " + dots, (float)(0.4 * displayWidth), (float)(0.09 * displayHeight));
     text("Lines: " + lines, (float)(0.4 * displayWidth), (float)(0.14 * displayHeight));
     text("Rects: " + rects, (float)(0.4 * displayWidth), (float)(0.19 * displayHeight));
     text("Triangles: " + triangles, (float)(0.4 * displayWidth), (float)(0.24 * displayHeight));    
    }
    
    public void mouseDragged() {
     addItem();
    }
    
    @ Override
    public void mousePressed() {
     if (mouseY <= (float)(0.05 * displayHeight)) {
      items.clear();
      dots = lines = triangles = rects = 0;
     } else if (mouseY <= (float)(0.1 * displayHeight)) {
      removeItem(Dot.class);
      dots = 0;
     } else if (mouseY <= (float)(0.15 * displayHeight)) {
      removeItem(Line.class);
      lines = 0;
     } else if (mouseY <= (float)(0.20 * displayHeight)) {
      removeItem(Rect.class);
      rects = 0;
     } else if (mouseY <= (float)(0.25 * displayHeight)) {
      removeItem(Triangle.class);
      triangles = 0;
     } else {
      addItem();
     }
    }
    
    void addItem() {
     if (mouseX <= (float)(0.5 * displayWidth) &&
      mouseY >= (float)(0.25 * displayHeight) && mouseY <= (float)(0.625 * displayHeight)) {
      dots++;
      items.add(new Dot());
     } else if (mouseX > (float)(0.5 * displayWidth) &&
      mouseY >= (float)(0.25 * displayHeight) && mouseY <= (float)(0.625 * displayHeight)) {
      lines++;
      items.add(new Line());
     } else if (mouseX < (float)(0.5 * displayWidth) &&
      mouseY > (float)(0.625 * displayHeight)) {
      rects++;
      items.add(new Rect());
     } else if (mouseX > (float)(0.5 * displayWidth) &&
      mouseY > (float)(0.625 * displayHeight)) {
      triangles++;
      items.add(new Triangle());
     }
    }
    
    void removeItem(Class < ? > myClass) {
     ArrayList < Item > temp = new ArrayList < Item > ();
     for (Item item: items) {
      if (!myClass.isInstance(item)) {
       temp.add(item);
      }
     }
     items = new ArrayList < Item > (temp);
    }
    
    class Item {
     float x, y, dX, dY, ddX, ddY;
     final int r = randInt(0, 255);
     final int g = randInt(0, 255);
     final int b = randInt(0, 255);
     final float ddVIncr = (float)(0.0005 * displayWidth);
     final float dV = 0.75 f;
    
     Item() {
      x = mouseX;
      y = mouseY;
      dX = (mouseX - pmouseX) / 5;
      dY = (mouseY - pmouseY) / 5;
     }
    
     void display() {}
    
     void move() {
      accelerate();
      checkBounds();
      x += dX;
      y += dY;
     }
    
     void checkBounds() {
      if (x <= 0) {
       dX *= -dV;
       x = 0;
      } else if (x >= displayWidth) {
       dX *= -dV;
       x = displayWidth;
      }
      if (y <= (float)(0.25 * displayHeight)) {
       dY *= -dV;
       y = (float)(0.25 * displayHeight);
      } else if (y >= displayHeight) {
       dY *= -dV;
       y = displayHeight;
      }
     }
    
     void accelerate() {
      surge();
      dX += ddX;
      dY += ddY;
     }
    
     void surge() {
      ddX = randInt(-ddVIncr, ddVIncr);
      ddY = randInt(-ddVIncr, ddVIncr);
     }
    }
    
    class Dot extends Item {
     Dot() {
      super();
     }
    
     void display() {
      noStroke();
      fill(r, g, b);
      ellipse(x, y, displayWidth / 30, displayWidth / 30);
     }
    }
    
    class Line extends Item {
     float xOffset = randFloat(-(float)(0.1 * displayWidth), (float)(0.1 * displayWidth));
     float yOffset = randFloat(-(float)(0.1 * displayWidth), (float)(0.1 * displayWidth));
     Line() {
      super();
     }
    
     void display() {
      stroke(r, g, b);
      strokeWeight(((float)(0.01 * displayWidth)));
      line(x - xOffset, y - yOffset, x + xOffset, y + yOffset);
     }
    }
    
    class Rect extends Item {
     float xOffset = randFloat(-(float)(0.05 * displayWidth), (float)(0.05 * displayWidth));
     float yOffset = randFloat(-(float)(0.05 * displayWidth), (float)(0.05 * displayWidth));
    
     Rect() {
      super();
     }
    
     void display() {
      noStroke();
      fill(r, g, b);
      rect(x - xOffset, y - yOffset, xOffset, yOffset);
     }
    }
    
    class Triangle extends Item {
     float dMax = (float)(0.05 * displayWidth);
     float dx1 = randFloat(-dMax, dMax);
     float dy1 = randFloat(-dMax, dMax);
     float dx2 = randFloat(-dMax, dMax);
     float dy2 = randFloat(-dMax, dMax);
     float dx3 = randFloat(-dMax, dMax);
     float dy3 = randFloat(-dMax, dMax);
    
     Triangle() {
      super();
     }
    
     void display() {
      noStroke();
      fill(r, g, b);
      triangle(x + dx1, y + dy2, x + dx2, y + dy3, x + dx3, y + dy3);
     }
    }
    

    Might not be the most efficient code, but as long as the same code is employed on various versions then that doesn't matter.

    I tried that code in the PDE and I am getting same results. The reason I had originally used Eclipse is because it is very easy to just change the Processing versions and compare them quickly.

    Well, maybe you are getting great results because your device is highly performant - could you tell me what kind of device you tested on? But we can't really reach any conclusion if we only test one version. Maybe for an older version your device would have maintained circa 50 fps for 1000 ellipses, which is 10 higher then the newer versions?

  • My phone is an LG Leon 4G LTE ... a budget phone with a quad core 1.2GHz processor. I will test again later today or tomorrow with an older version of Processing to see what happens.

  • edited April 2016

    I just tested using APDE which is over a year old now so based on an old version of everything! Also tried AIDE using an exported project using an old ( 1 year) processing version. Framerates were 44 for 500 dots and 21 for 1000, for both tests, so for me that means old versions of processing are much slower than new versions. I assume this is due to better opengl in latest release?? Very strange to have this difference between us though. I will still test on my PC later.

  • I confirm my initial results, unfortunately... Some older versions are slower indeed, but there doesn't seem to be a clear trend. Each version has its peculiarities... The latest version, 0249, handles lines and ellipses the worst of all I have tested, that's for sure.

    I have repeated the below three times, each time I got very similar results.

    Pdata

  • OK... With PC for 500 shapes 239 ie old gives 42 fps for ellipses 59 for rects 43 for triangles and 17 for lines 249 ie latest gives 58/59 for everything except lines which is still 17.

    So lines is much worse than everything else .. I will avoid lots of lines!

  • This is very confusing. Here are my results:

    pr_andr_perf

Sign In or Register to comment.