Processing seemingly capped at 35% cpu

Is this a feature or is there some way of changing this? No matter what I throw at it, programs which would eat cpu in p5.js, never go above 35% cpu. Don’t get me wrong there is clearly asignificant loss in performance but I would expect the cpu usage to escalate until it can’t, however in my case the cpu seems restricted to 35% regardless of however many particles or lines I’m simulating/drawing.

2 Likes

Is this running in the browser? Which one? Which OS?

I’m using the processing ide, windows

The same for me on Windows.

Hey There!

As I am aware processing uses only a single thread the animation one so it won’t utilize all of your CPU as the gap to do so isn’t open.

1 Like

@paulgoux just to be sure, your using the current versions of Processing and Windows OS?

can you give an example sketch?

processing 3.5.3. I can but the sketch is rather large.

This is an alternative sketch and again same issue, however this one is restricted to around 13-14%

int cols, rows;
int scl = 20;
int w = 2000;
int h = 1600;

float flying = 0;

float[][] terrain;

void setup() {
  size(600, 600, P3D);
  cols = w / scl;
  rows = h/ scl;
  terrain = new float[cols][rows];
}


void draw() {

  flying -= 0.1;

  float yoff = flying;
  for (int y = 0; y < rows; y++) {
    float xoff = 0;
    for (int x = 0; x < cols; x++) {
      terrain[x][y] = map(noise(xoff, yoff), 0, 1, -100, 100);
      xoff += 0.2;
    }
    yoff += 0.2;
  }



  background(0);
  stroke(255);
  fill(120);

  translate(width/2, height/2+50);
  rotateX(PI/3);
  translate(-w/2, -h/2);
  for (int y = 0; y < rows-1; y++) {
    beginShape(TRIANGLE_STRIP);
    for (int x = 0; x < cols; x++) {
      vertex(x*scl, y*scl, terrain[x][y]);
      vertex(x*scl, (y+1)*scl, terrain[x][y+1]);
      //rect(x*scl, y*scl, scl, scl);
    }
    endShape();
  }
}

change the w and h values to an extra factor of 10 and it will still run but still only uses 13% cpu

i’m not sure this is a good example though as it might be gpu dependent, and im using a lenovo t440p

otherwise heres the sketch in question, change len and ylen to something over 200.


int sides = 6;
int len = 30;
int ylen = 20;
float w = 1100/len;
float u = 660/ylen;
float uu = (u/ylen)/2;
float theta = radians(360/sides);
ArrayList<Cell> grid = new ArrayList<Cell>();
ArrayList<Cell> current = new ArrayList<Cell>();
float ratio = w/2 * sin(theta);
  
void setup() {

  size(1100, 660);
  background(204);
  //noLoop();
  // Run the constructor without parameters
      
      createGrid();
      
     for (int j=0;j<grid.size();j++){
       
       float c1 = round(random(0,255));
       float c2 = round(random(0,255));
       float c3 = round(random(0,255));
       color col = color(c1,c2,c3);
       
      
      //grid.get(j).col = col;

      
    }
}

class Cell {
  float x, y, wid, length;
  int xpos, ypos, id, oid, t;
  //boolean[] walls;
  ArrayList<Boolean> walls =new ArrayList<Boolean>();
  ArrayList<float[]> edge =new ArrayList<float[]>();
  ArrayList<float[]> vertex =new ArrayList<float[]>();
  boolean visited,hilight,mpos;
  color col, col2, pcol;
  int rpos, score;

  Cell (float _x, float _y, float _wid, int _id, int _ypos, int _xpos) {

    x     = _x;
    y     = _y;
    xpos = _xpos;
    ypos = _ypos;
    id    = _id;
    oid   = _id;
    rpos = -1;
    //mpos = false;
    //this.a = 0;
    hilight = false;
    visited = false;
    score = 0;
    color col   = color(0, 255, 234);
    color pcol  = col;
    color col2  = color(0, 0, 0);
    length = 0;
    t = 0;
  }
  void init() {
    for (int i=0; i<sides; i++) {
      float thetab =  theta * i;
      float thetac =  theta * i+theta;
      float []a = {x+w/2*sin(thetab), y+w/2*cos(thetab), x+w/2*sin(thetac), y+w/2*cos(thetac)};
      float []b = {x+w/2*sin(thetac), y+w/2*cos(thetac)};
      walls.add(true);
      edge.add( a);
      vertex.add(b);
      length = dist(x+w/2*sin(thetab), y+w/2*cos(thetab), x+w/2*sin(thetac), y+w/2*cos(thetac));
    }
  };

  void showid() {
    //color a = color(255, 0, 0);
    fill(255, 0, 0);
    fill(0, 13, 255);
    text(oid, x, y);
  };

  void draw (float c) {

    if (hilight) {
      col = color(255, 0, 102);
    }
    lShape(x, y, col2, walls);
    if (t==1) {
      visited = true;
    } else {
      //visited = false;
    }
    if (visited ==true) {
      fill(255, 0, 0);
    }
  };

  void fillshape() {
    beginShape();
    for (int k=0; k<sides; k++) {


      float thetab =  theta * k;
      float thetac =  theta * k+theta;
      fill(col);
      if (visited) {
        fill(pcol);
      }
      noStroke();
      vertex(x+w/2*sin(thetac), y+w/2*cos(thetac));
    }
    endShape();
  };

  void highlight() {
    beginShape();
    for (float k=0; k<sides; k++) {
      noStroke();
      float thetab =  theta * k;
      float thetac =  theta * k+theta;
      fill(0, 0, 255, 100);
      vertex(x+w/2*sin(thetac), y+w/2*cos(thetac));
    }
    endShape();
  };

  Cell checkNeighbors() {
    int x = xpos;
    int y = ypos;
    ArrayList<Cell> neighbours = new ArrayList<Cell>();
    //due to the offset introduced to make the hexagonal grid a slight adjustment needs to be made for the x values
    float k = pow(-1, y);
    if (k==1) {
      x=x+1;
    }
    //ArrayList<Cell> btmL = new ArrayList<Cell>();
    Cell btmL = grid.get(index(x-1, y+1));
    Cell btmR = grid.get(index(x, y+1));
    Cell topL = grid.get(index(x-1, y-1));
    if (k==-1) {
      x=x-1;
    }
    if (k==1) {
      x=x-1;
    }
    Cell topR = grid.get(index(x+1, y-1));
    if (k==-1) {
      x=x+1;
    }
    Cell left = grid.get(index(x-1, y));
    Cell right = grid.get(index(x+1, y));


    fill(255, 0, 0);
    if (right != null) {
      //text(right.id,x,y);
    }
    if (topL != null&& !topL.visited) {
      topL.rpos = 3;
      neighbours.add(topL);
    }
    if (topR != null && !topR.visited) {
      topR.rpos = 2;
      neighbours.add(topR);
    }
    if (right != null && !right.visited) {
      right.rpos = 1;
      neighbours.add(right);
    }
    if (btmR != null &&!btmR.visited) {
      btmR.rpos = 0;
      neighbours.add(btmR);
    }
    if (btmL != null &&!btmL.visited) {
      btmL.rpos = 5;
      neighbours.add(btmL);
    }
    if (left != null &&!left.visited) {
      left.rpos = 4;
      neighbours.add(left);
    }
    int n = neighbours.size()-1;
    if (neighbours.size()>0) {
      //text(neighbours.aid,x,y);
      int r = round(random(0, n));
      n = n;

      return neighbours.get(r);
    } else {
      return null;
    }
  };

  Cell nthPass() {
    int x = xpos;
    int y = ypos;
    ArrayList<Cell> neighbours = new ArrayList<Cell>();
    //due to the offset introduced to make the hexagonal grid a slight adjustment needs to be made for the x values
    float k = pow(-1, y);
    if (k==1) {
      x=x+1;
    }
    //ArrayList<Cell> btmL = new ArrayList<Cell>();
    Cell btmL = grid.get(index(x-1, y+1));
    Cell btmR = grid.get(index(x, y+1));
    Cell topL = grid.get(index(x-1, y-1));
    if (k==-1) {
      x=x-1;
    }
    if (k==1) {
      x=x-1;
    }
    Cell topR = grid.get(index(x+1, y-1));
    if (k==-1) {
      x=x+1;
    }
    Cell left = grid.get(index(x-1, y));
    Cell right = grid.get(index(x+1, y));

    if (topL != null && id!=topL.id) {
      topL.rpos = 3;
      neighbours.add(topL);
    }
    if (topR != null && id!=topR.id) {
      topR.rpos = 2;
      neighbours.add(topR);
    }
    if (right != null && id!=right.id) {
      right.rpos = 1;
      neighbours.add(right);
    }
    if (btmR != null && id!=btmR.id) {
      btmR.rpos = 0;
      neighbours.add(btmR);
    }
    if (btmL != null && id!=btmL.id) {
      btmL.rpos = 5;
      neighbours.add(btmL);
    }
    if (left != null && id!=left.id) {
      left.rpos = 4;
      neighbours.add(left);
    }
    if (neighbours.size()>0) {
      int r = round(random(0, neighbours.size()-1));
      return neighbours.get(r);
    } else {
      return null;
    }
  };

  void histScore() {

    int x = xpos;
    int y = ypos;
    ArrayList<Cell> neighbours = new ArrayList<Cell>();
    //due to the offset introduced to make the hexagonal grid a slight adjustment needs to be made for the x values
    float k = pow(-1, y);
    if (k==1) {
      x=x+1;
    }
    //ArrayList<Cell> btmL = new ArrayList<Cell>();
    Cell btmL = grid.get(index(x-1, y+1));
    Cell btmR = grid.get(index(x, y+1));
    Cell topL = grid.get(index(x-1, y-1));
    if (k==-1) {
      x=x-1;
    }
    if (k==1) {
      x=x-1;
    }
    Cell topR = grid.get(index(x+1, y-1));
    if (k==-1) {
      x=x+1;
    }
    Cell left = grid.get(index(x-1, y));
    Cell right = grid.get(index(x+1, y));

    int a = 0;
    if (topL != null &&topL.walls.get(0)==false&&walls.get(3)==false&&id!=topL.id) {
      topL.rpos = 3;
      neighbours.add(topL);
      a ++;
    }
    if (topR != null &&topR.walls.get(5)==false&&walls.get(2)==false&&id!=topR.id) {
      topR.rpos = 2;
      neighbours.add(topR);
      a ++;
    }
    if (right != null &&right.walls.get(4)==false&&walls.get(1)==false&&id!=right.id) {
      right.rpos = 1;
      neighbours.add(right);
      a ++;
    }
    if (btmR != null &&btmR.walls.get(3)==false&&walls.get(0)==false&&id!=btmR.id) {
      btmR.rpos = 0;
      neighbours.add(btmR);
      a ++;
    }
    if (btmL != null &&btmL.walls.get(2)==false&&walls.get(5)==false&&id!=btmL.id) {
      btmL.rpos = 5;
      neighbours.add(btmL);
      a ++ ;
    }
    if (left != null &&left.walls.get(1)==false&&walls.get(4)==false&&id!=left.id) {
      left.rpos = 4;
      neighbours.add(left);
      a ++;
    }
    int n = neighbours.size();
    if (n > 0) {
      fill(255, 0, 0);
      score = 1;
    } else {
    }
  };

  void hover() {
    //noLoop();
    float x = mouseX;
    float y = mouseY;
    //float[] a = edge;
    ArrayList<float []> a = edge;
    //text(a.length,10,10);
    for (int i=0; i<a.size(); i++) {

      float[] b = a.get(i);
      float x1 = b[0];
      float y1 = b[1];
      float x2 = b[2];
      float y2 = b[3];

      float d1 = dist(x, y, x1, y1);
      float d2 = dist(x, y, x2, y2);
      float d3 = dist(x1, y1, x2, y2);
      float d4 = d1+d2;
      float d5 = dist(x, y, x, y);
      float dy = y1-y2;
      float dx = x1-x2;
      float dy2 = y2-y1;
      float dx2 = x2-x1;
      float dmx = x-x1;
      float dmy = y-y1;
      float dmx2 = x-x2;
      float dmy2 = y-y2;
      //fill(255, 0, 0);

      float thetaXY1 = atan2(dy, dx);
      float thetaXY2= atan2(dy2, dx2);
      float thetaMXY2 = atan2(dmy, dmx);
      float thetaMXY1 = atan2(dmy2, dmx2);

      if ((thetaXY1>=0&&thetaMXY1>=thetaXY1&&thetaMXY1>=0&&d1<=length&&d2<=length)||(thetaXY1<=0&&thetaMXY1<=0&&thetaMXY1>=thetaXY1&&d1<=length&&d2<=length)||(thetaXY2>=0&&thetaMXY2>=0&&thetaMXY2<=thetaXY2&&d1<=length&&d2<=length)||(thetaXY2<=0&&thetaXY2<=0&&thetaMXY2<=thetaXY2&&d1<=length&&d2<=length)||d5<=length/1.5) {
        text("hello",x,y);
        mpos = true;
      }
      else{
        mpos = false;
      }
    }
    //loop();
  };

  void checkp() {

    if (mpos==true) {
      col =  color(29, 131, 240);
      col2 = color(212, 8, 8);
    } else {
      col = color(0, 204, 255);
      col2 = color(162, 0, 255);
    }
  };

  Boolean toggle() {
    if(mousePressed){
    if (mpos==true) {
      t++;
      if (t==2) {
        t=0;
      }
    }
    }
    return true;
  };
};

void createGrid(){

  for (int j=0;j<ylen;j++){
      float a = round(ylen/1.5);
      for(int i=0;i<len;i++){
          float k = pow(-1,j);
          float x = (ratio*1.5-1)+(ratio*2)*i+ratio/2*k;
          float y = (w/2)+(u-uu)*j;
          int id = i+j*(len);
          grid.add(new Cell(x,y,w,id,j,i));

      }}

      for(int i=0;i<grid.size();i++){
            grid.get(i).init();
       }

  };

void lShape (float x,float y,color colour,ArrayList<Boolean> array){
            for(int k=0;k<sides;k++){

                  if(array.get(k)==true){
                    float thetab =  theta * k;
                    float thetac =  theta * k+theta;
              stroke(colour);
              strokeWeight(0);
              line(x+w/2*sin(thetab),y+w/2*cos(thetab),x+w/2*sin(thetac),y+w/2*cos(thetac));
          }else{
              noStroke();
          }
       }
};

void setups(){
    for(int i=0;i<grid.size();i++){
        grid.get(i).fillshape();
        grid.get(i).hover();

        grid.get(i).draw(sides);
        grid.get(i).checkp();
        //grid.get(i).histScore();
        //grid[i].toggle();
    }

    fill(255);
    text("PRESS LEFT MOUSE TO START",100,10);
    for (int i = 0; i < current.size(); i++) {
        current.get(i).visited = true;
    }
};

int index (int i,int j){
    if(i<0||i>len-1||j<0||j>ylen-1){
        return -1;
    }
    else{
        return i+j*len;
    }
};

void draw() {
  background(51);
  
  setups();
}

void mouseClicked(){
  
  
};

void mousePressed(){
  
  
};

void mouseDragged(){
  
  
};

void mouseOver(){
  
  
};

can you experiment with this version?

ArrayList<Female> females = new ArrayList<Female>();
boolean diagp=false; //true;


void setup() {
  size(600, 600);
  frameRate(120);
  for (int i = 0; i < 1000; i++) {
    PVector location = new PVector(height/2, width/2);
    int[] colours = {floor(random(255)), floor(random(255)), floor(random(255))};
    Female newFem = new Female(location, "female", 1, colours, 16, 10, 10, 10, 10, 50);
    for (int x = 0; x < newFem.moves.length; x++) {
      newFem.moves[x] = new PVector(random(-0.5, 0.5), random(-0.5, 0.5));
    }
    females.add(newFem);
  }
  noStroke();
}
void draw() {
  background(255);
  for (int i = 0; i < females.size()-1; i++) {
    females.get(i).move();
    females.get(i).display();
  }
  if ( frameCount%100  == 0 ) println("fps: "+ frameRate );
}

//Breeder entity object

class Ent {
  ////Abstract properties
  int id;
  int age;
  //'male' or 'female'
  String gender;
  //PVectors
  PVector location;
  PVector velocity = new PVector();
  //n pixels per frame
  float speed;

  ////Physical properties
  //0-255
  int[] colour;
  //4, 8, 16
  int size;

  ////Combat properties
  float hp;
  float damage;
  float b_velocity;
  float f_rate;

  ////Hunger
  boolean hungry = false;
  int hunger = 0;
  int hungermax;

  Ent(PVector location_, String gender_, float speed_, int[] colour_, int size_, float hp_, float damage_, float b_velocity_, float f_rate_) {
    id = floor(random(10000000, 99999999));
    location = location_;
    gender = gender_;
    speed = speed_;
    colour = colour_;
    size = size_;
    hp = hp_;
    damage = damage_;
    b_velocity = b_velocity_;
    f_rate = f_rate_;
  }

  Ent() {
  }

  //void move(){    
  //  location.add(velocity.x * speed, velocity.y * speed);
  //} 
  //Draw Ent on step
  void display() {
    fill(colour[0], colour[1], colour[2]);
    //Wall wrap
    if (location.y > height) {
      location.y = 0.00;
      if (diagp) println("more than height");
    }
    if (location.y < 0) {
      location.y = height;
      if (diagp) println("less than height");
    }
    if (location.x > width) {
      location.x = 0.00;
    }
    if (location.x < 0) {
      location.x = width;
    }
    rect(location.x, location.y, size, size, 5.00);
  }
}



class Female extends Ent {

  boolean pregnant = false;
  int gestation = 0;
  int gestperiod;
  PVector[] moves = new PVector[90];

  int food;
  ////Movement
  //increment 
  int stepcount = 0;
  //change direction when stepcount is a modulus of stepchange
  int stepchange;
  //which move is it up to
  int movenumber = 0;

  Female(PVector location_, String gender_, float speed_, int[] colour_, int size_, float hp_, float damage_, float b_velocity_, float f_rate_, int gestperiod_) {
    super(location_, gender_, speed_, colour_, size_, hp_, damage_, b_velocity_, f_rate_);
    gestperiod = gestperiod_;
    stepchange = floor(random(50, 100));
  }

  void move() {
    if (stepcount % stepchange == 0) {
      velocity.set(moves[movenumber]);
      if (diagp) println(moves[movenumber].x);
      if (diagp) println(velocity);
      if (diagp) println(stepchange);
      movenumber++;
      if (movenumber == 90) {
        movenumber = 0;
      }
    }
    location.add(velocity);
    stepcount++;
  }
}

-a- ask for 120 FPS and shows the actual FPS
-b- can switch the println diagnostic

( i feel that the println ( at every draw ) is kind of handicap )

where does the println info appear? I cant see anything in the console or the sketch.

Ok so the 15% limitation was due to my power management, but once turned off its still restricted to 35%

Hey There!

Trying using thread() and see if yoy can squeeze the CPU.

https://processing.org/reference/thread_.html

there is a boolean in line 2 to enable your printing again,
but when disabled i see a lot more FPS

Thanks for all your answers everyone, I shall take a look into the threat method. I suppose for now I will just assume its a feature.

1 Like

Just thought I’d revisit this question and see if we can find a solution. For some sketches, ie the spacial partitioning sketch, open processing is a better alternative than the native processing app, however I find it odd that in this day and age this seems to be a limitation which has not yet been overcome. I have not yet looked into threading, as honestly i don’t understand it or how to implement it I am still fairly new to programming, however if someone can point me in the right direction I will read the docs and give it a go. However the ideal solution would obviously be to have my apps be able to utilize the totality of the cpu’s resources.

Anyways if anybody knows any way around this please, any info would be greatly appreciated.

1 Like

even more bad news:

it will not get better soon

with: canvas 800*800 and 5000 of your ?items? ( i not read your code… )

MOD test code
ArrayList<Female> females = new ArrayList<Female>();
boolean diagp=false; //true;
int many = 5000;

void setup() {
  size(800,800);
  frameRate(120);
  for (int i = 0; i < many; i++) {
    PVector location = new PVector(height/2, width/2);
    int[] colours = {floor(random(255)), floor(random(255)), floor(random(255))};
    Female newFem = new Female(location, "female", 1, colours, 16, 10, 10, 10, 10, 50);
    for (int x = 0; x < newFem.moves.length; x++) {
      newFem.moves[x] = new PVector(random(-0.5, 0.5), random(-0.5, 0.5));
    }
    females.add(newFem);
  }
  noStroke();
}
void draw() {
  background(255);
  for (int i = 0; i < females.size()-1; i++) {
    females.get(i).move();
    females.get(i).display();
  }
  if ( frameCount%100  == 0 ) println("fps: "+ frameRate );
}

//Breeder entity object

class Ent {
  ////Abstract properties
  int id;
  int age;
  //'male' or 'female'
  String gender;
  //PVectors
  PVector location;
  PVector velocity = new PVector();
  //n pixels per frame
  float speed;

  ////Physical properties
  //0-255
  int[] colour;
  //4, 8, 16
  int size;

  ////Combat properties
  float hp;
  float damage;
  float b_velocity;
  float f_rate;

  ////Hunger
  boolean hungry = false;
  int hunger = 0;
  int hungermax;

  Ent(PVector location_, String gender_, float speed_, int[] colour_, int size_, float hp_, float damage_, float b_velocity_, float f_rate_) {
    id = floor(random(10000000, 99999999));
    location = location_;
    gender = gender_;
    speed = speed_;
    colour = colour_;
    size = size_;
    hp = hp_;
    damage = damage_;
    b_velocity = b_velocity_;
    f_rate = f_rate_;
  }

  Ent() {
  }

  //void move(){    
  //  location.add(velocity.x * speed, velocity.y * speed);
  //} 
  //Draw Ent on step
  void display() {
    fill(colour[0], colour[1], colour[2]);
    //Wall wrap
    if (location.y > height) {
      location.y = 0.00;
      if (diagp) println("more than height");
    }
    if (location.y < 0) {
      location.y = height;
      if (diagp) println("less than height");
    }
    if (location.x > width) {
      location.x = 0.00;
    }
    if (location.x < 0) {
      location.x = width;
    }
    rect(location.x, location.y, size, size, 5.00);
  }
}



class Female extends Ent {

  boolean pregnant = false;
  int gestation = 0;
  int gestperiod;
  PVector[] moves = new PVector[90];

  int food;
  ////Movement
  //increment 
  int stepcount = 0;
  //change direction when stepcount is a modulus of stepchange
  int stepchange;
  //which move is it up to
  int movenumber = 0;

  Female(PVector location_, String gender_, float speed_, int[] colour_, int size_, float hp_, float damage_, float b_velocity_, float f_rate_, int gestperiod_) {
    super(location_, gender_, speed_, colour_, size_, hp_, damage_, b_velocity_, f_rate_);
    gestperiod = gestperiod_;
    stepchange = floor(random(50, 100));
  }

  void move() {
    if (stepcount % stepchange == 0) {
      velocity.set(moves[movenumber]);
      if (diagp) println(moves[movenumber].x);
      if (diagp) println(velocity);
      if (diagp) println(stepchange);
      movenumber++;
      if (movenumber == 90) {
        movenumber = 0;
      }
    }
    location.add(velocity);
    stepcount++;
  }
}

our usual JAVA 8 Processing 3.5.3

and now i try the JAVA11 version ( possible Processing 4.0.0 beta ) @sampottinger

and same ( or even less ) FPS
and i hoped it might be more ?efficient?
( i not understand why the GPU usage value changed / 12% to 36% / )

so:

processing is cooking on one burner?

2 Likes

OK I might be wrong Javascript is not my thing but surely JS runs in a browser :thinking: in which case the browser’s JS interpreter is running the program, not Processing or the JVM. Perhaps it is being capped by the browser to stop it becoming unresponsive.

Hey there!

On my mac, I ran it and it capped out one of my CPUs to get to 32 FPS on the new Java 11 version. I’ll have to give it a go on a windows machine later. It isn’t expected to use more than one core unless you tell it to explicitly but, that said, Java (specifically the Java 11 version) makes it easy to extend out to other cores and, for sake of demonstration, I went ahead and coded that up for you at: https://gist.github.com/sampottinger/85a76161f959ed407d8f2b87508556dd. Note that running this sketch will require using that new version: https://github.com/sampottinger/processing.

Still, the parallelization there didn’t honestly give me a huge boost. After a little profiling, you may notice are spending almost all of your time in fill and rect! The default renderer in Processing is good at some things but it doesn’t seem to be doing a great job here. However, switch to FX2D (see the code above) and you easily hit 100 FPS on my machine (still without necessarily using up all your cores’ capacity). This means that your work isn’t limited by the computation your sketch has to do (parallelizing the computation at that rate helped a little but not a lot) and, instead, the bottleneck seems to be in the drawing pipeline. It’s hard to say exactly where that is without digging but it may be that you are seeing that some renderers are optimized for certain drawing behaviors over others.

19%20AM

As for Java 11 (the potential new alpha) vs Java 8 (current processing), Java 11 made a lot of changes in the bits that deal with drawing and the way it interacts with the OS. Those aren’t necessarily better or worse… the java community just decided to optimize for some behaviors over others.

Let me know if that helps!

3 Likes

Converted draw() to Java’s classic syntax: :coffee:

import java.util.function.Consumer;

static final Consumer<Female> ACTION = new Consumer<Female>() {
  @Override void accept(final Female f) {
    f.move();
    f.wallWrap();
  }
};

void draw() {
  background(-1);
  females.parallelStream().forEach(ACTION);
  for (final Female f : females)  f.display();
  getSurface().setTitle("fps: " + round(frameRate));
}