Grafica using A TON of memory

Hello everybody,

I’ve built a simple GUI in processing (P3) to show some sensor data in near real-time and have hit a bit of a snag with Grafica.

I’m plotting three values over a 25 point span and it quickly (20s) uses up all of my available memory and becomes very laggy.

The data is polled live and saved in a FIFO like this:

// located in setup we import grafica, declare our linkedLists, variables, etc.
#import grafica.*;

LinkedList<Integer> E1c = new LinkedList<Integer>();
LinkedList<Integer> E3c = new LinkedList<Integer>();
LinkedList<Integer> E4c = new LinkedList<Integer>();
int nPoints = 25;

float E1, E2, E3, E4;
void Convert2uStrain() {
  //Convert to strain
       //not shown....gathering data...converting data => E1, E2, E3 are floats

//Array containing the last nPoints
if (running == true) {
  if (len < nPoints){
    E1c.push(int(E1 * 1000000));
    E3c.push(int(E3 * 1000000));
    E4c.push(int(E4 * 1000000));
    len++;
  }  
  else {
    E1c.removeLast();
    E3c.removeLast();
    E4c.removeLast(); 
    E1c.push(int(E1 * 1000000));
    E3c.push(int(E3 * 1000000));
    E4c.push(int(E4 * 1000000));
  }
 }  
}

Then we’re graphing the data in another function called in draw() like this:

void PlotValues() {
 
// are we running and is the graphing mode selected?
if (running == true && graph == true) {     
    
  //setup legend
    String[] legends = new String[]{"11\"", "Torsional", "27\""};
    float[] leg1 = new float[]{0.07, 0.22, 0.42};
    float[] leg2 = new float[]{0.92, 0.92, 0.92};
   
 //Set up Arrays for each strain stream and initiate plot
   GPointsArray points = new GPointsArray(nPoints); 
   GPointsArray points3 = new GPointsArray(nPoints); 
   GPointsArray points4 = new GPointsArray(nPoints); 
   GPlot plot = new GPlot(this);
   
   //Set up plot properties
    plot.setDim(450, 300);
    plot.setPos(-512, 0);
    plot.setXLim(0, nPoints);
    plot.getXAxis().setNTicks(0);
    plot.setYLim(-4000, 4000);
    plot.getYAxis().setNTicks(9);
    plot.getYAxis().setAxisLabelText("MicroStrain");
    plot.setPointColor(color(0,200,0));
    
// If we are running... add the last nPoints to the graphing arrays
    if (running == true && len >= nPoints) {
      for (int i = 0; i < nPoints; i++) {
        points.add(i, E1c.get(i));
        points3.add(i, E3c.get(i));
        points4.add(i, E4c.get(i));
      }
      
//Set which points to plot and their colors
      plot.setPoints(points);
      plot.setLineColor(color(0, 10, 255));
      plot.addLayer("E3", points3);
      plot.getLayer("E3").setLineColor(color(255, 0, 10));
      plot.addLayer("E4", points4);
      plot.getLayer("E4").setLineColor(color(0, 255, 10));
     

 //Draw the plot its self
      plot.beginDraw();
      //plot.drawBox();
      plot.drawXAxis();
      plot.drawYAxis();
      plot.drawLines();
      plot.drawGridLines(GPlot.HORIZONTAL);
      plot.drawLegend(legends, leg1, leg2);
      plot.endDraw();
    }
  }
}

Any tips on how I can reduce this memory hogging?

Thanks,
Twain

Are you calling plotValues in draw()?

Kf

Yes,

my draw() routine basically looks like:

void draw() {
    serialEvent();  // read and parse incoming serial data

    GyroShow();  //Show module twisting based on IMU

    Convert2uStrain(); //convert data and save into a FIFO array

    SavetoCSV(); //Save current data (E1, E3, E4) to a .csv file

    PlotValues(); //Plot the values from FIFO array

}

If i were to save the FIFO buffer and plot it all in a Private class function would that keep the memory local?

[edit] Nope, that didn’t help anything. however I did move the creation of the FIFO array and the plotting into a single private function.

Thanks again for the help

The concept of having a setup and draw function is that you create in setup what persist in your application. You update your created objects in draw. I do not have much experience with Grafica but that would be my approach. I have to say probably Grafica is not the one delaying your app. I am suspecting it is your SaveToCVS() function. Can you show the content of that function? Remember that draw runs 60 fps (!)

Kf

2 Likes

Hi Kfajer,

I’ll look into setting up the graph just once setup(), but there’s only so much that I can move out as I need to gather the data in “real-time” before graphing it… That is, as the data comes in the graph needs to update.

I came to the assumption that it’s the graphing (not saving) that’s affecting the memory because if I comment the graphing code out the problem desists! Also the saving bit isn’t using the fifo array or anything, just saving the current variable to a .csv

For the record, SavetoCSV() looks like this:

//global variables
float A1, A2, A3, A4;
float E1, E2, E3, E4;
Table table;
String Path = "path/Goes/Here.csv";

//part of setup that's required
void setup() {

  //Set up GIU box
  size(1024, 768, P3D);
  frameRate(60);  
  s = loadShape("...");
  smooth();
...
 table = new Table();  
  table.addColumn("A1"); table.addColumn("A2"); table.addColumn("A3"); 
  table.addColumn("A4");
  table.addColumn(""); table.addColumn("E1"); table.addColumn("E3"); 
  table.addColumn("E4");  

...
}


void SavetoCSV() {

  if (A1 != 0) {
    TableRow newRow = table.addRow();
    newRow.setFloat("A1", (A1));
    newRow.setFloat("A2", (A2));
    newRow.setFloat("A3", (A3));
    newRow.setFloat("A4", (A4));

    newRow.setFloat("E1", (E1*1000000));
    newRow.setFloat("E3", (E3*1000000));
    newRow.setFloat("E4", (E4*1000000));

    saveTable(table, Path);
  }
}

You are creating 3 new GPointsArray and new GPlot approximately 60 times a second I doubt that garbage collection is keeping up. Is it not possible to create these in setup and reuse them each frame?

3 Likes

For those of you who are following along…

Moving the initiaion/creation of the GPlot and the GPointsArrays to setup() did indeed lighten the CPU load up and stop the memory leak!

Just need to figure out how to clear the plot each go around as it’s plotting over its self time and time again… but that should be simple.

The code currently looks like:

//Global variables 
LinkedList<Integer> E1c = new LinkedList<Integer>();
LinkedList<Integer> E3c = new LinkedList<Integer>();
LinkedList<Integer> E4c = new LinkedList<Integer>();
int nPoints = 25;
GPlot plot;

String[] legends = new String[]{"11\"", "Torsional", "27\""};
float[] leg1 = new float[]{0.07, 0.22, 0.42};
float[] leg2 = new float[]{0.92, 0.92, 0.92};

void setup() {
...
setupPlot();

...
}

void setupPlot() {
  //Set up Arrays for each strain stream and initiate plot
  GPointsArray points = new GPointsArray(nPoints); 
  GPointsArray points3 = new GPointsArray(nPoints); 
  GPointsArray points4 = new GPointsArray(nPoints); 
  
   for (int p = 0; p < nPoints; p++) {
    points.add(p, 0);
    points3.add(p,0);
    points4.add(p,0);
  }
  
  plot = new GPlot(this);
  
  //Set up plot properties
  plot.setDim(450, 300);
  plot.setPos(-512, 0);
  plot.setXLim(0, nPoints);
  plot.getXAxis().setNTicks(0);
  plot.setYLim(-4000, 4000);
  plot.getYAxis().setNTicks(9);
  plot.getYAxis().setAxisLabelText("MicroStrain");
  plot.setPointColor(color(0, 200, 0));
    
  //Set which points to plot and their colors
  plot.setPoints(points);
  plot.addLayer("E3", points3);
  plot.addLayer("E4", points4);
  
  plot.setLineColor(color(0, 10, 255));
  plot.getLayer("E3").setLineColor(color(255, 0, 10));
  plot.getLayer("E4").setLineColor(color(0, 255, 10)); 
 
}

void PlotValues() {

 //Array containing the last nPoints
  if (running == true) {
    if (len < nPoints) {
      E1c.push(int(E1 * 1000000));
      E3c.push(int(E3 * 1000000));
      E4c.push(int(E4 * 1000000));
      len++;
    } else {
      E1c.removeLast();
      E3c.removeLast();
      E4c.removeLast();

      E1c.push(int(E1 * 1000000));
      E3c.push(int(E3 * 1000000));
      E4c.push(int(E4 * 1000000));
      len++;
    }
  }
  
    // If we are running... add the last nPoints to the graphing arrays
  if (running == true && graph == true && len >= nPoints) { 

    //Draw the plot its self
    plot.beginDraw();
    //plot.drawBox();
    plot.drawXAxis();
    plot.drawYAxis();
    plot.drawLines();
    plot.drawGridLines(GPlot.HORIZONTAL);
    plot.drawLegend(legends, leg1, leg2);
    plot.endDraw();
    
    for (int i = 0; i < nPoints; i++) {
        plot.addPoint(i, E1c.get(i));
        plot.getLayer("E3").addPoint(i, E3c.get(i));
        plot.getLayer("E4").addPoint(i, E4c.get(i));
      }
  }
}

Thanks quark and Kf,
Twain

2 Likes