summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorSven Gothel <[email protected]>2010-10-14 18:39:42 +0200
committerSven Gothel <[email protected]>2010-10-14 18:39:42 +0200
commit6ced17f0325d5719e992b246ffd156e5b39694b4 (patch)
treec8618ebe347466e26c5ac8feb818b6844761121e /src
parent29999cf3b7616c8ab58f4483c672e30076fbb3e4 (diff)
Fix: Memory consumption
Observing memory consumption showed: 1 - 'traceLock' debug stack traces (GLContextLock) 2 - massive Iterator usage (1) is fixed, ie only enabled in DEBUG mode, like we have done in RecursiveLock before (2) Using an Iterator on ArrayLists with a low element count < 100, as it is usual in our use cases, is observed not to be faster than accessing the elements via an index (-> TestIteratorIndexCORE.java ). On the contrary, the index implementation was a bit faster. Further more, these Iterators were massively used on the fly during animation, hence their memory managment even impacts fluent processing/animation. Recoded all animation related (display, surfaceUpdated, ..) loops using an index.
Diffstat (limited to 'src')
-rw-r--r--src/jogl/classes/com/jogamp/opengl/impl/GLContextLock.java19
-rw-r--r--src/jogl/classes/com/jogamp/opengl/impl/GLDrawableHelper.java51
-rw-r--r--src/jogl/classes/com/jogamp/opengl/util/AWTAnimatorImpl.java43
-rw-r--r--src/jogl/classes/com/jogamp/opengl/util/AnimatorBase.java36
-rw-r--r--src/jogl/classes/com/jogamp/opengl/util/AnimatorImpl.java28
-rw-r--r--src/junit/com/jogamp/test/junit/core/TestIteratorIndexCORE.java128
6 files changed, 241 insertions, 64 deletions
diff --git a/src/jogl/classes/com/jogamp/opengl/impl/GLContextLock.java b/src/jogl/classes/com/jogamp/opengl/impl/GLContextLock.java
index 565ec967e..ea78f5209 100644
--- a/src/jogl/classes/com/jogamp/opengl/impl/GLContextLock.java
+++ b/src/jogl/classes/com/jogamp/opengl/impl/GLContextLock.java
@@ -50,11 +50,13 @@ import javax.media.opengl.*;
be raised. */
public class GLContextLock {
+ protected static final boolean DEBUG = GLContextImpl.DEBUG;
+
static class SyncData {
boolean failFastMode = true;
Thread owner = null;
int waiters = 0;
- Exception lockedStack = null;
+ Exception lockedStack = null; // only enabled if DEBUG
}
private SyncData sdata = new SyncData(); // synchronized (flow/mem) mutable access
@@ -66,12 +68,16 @@ public class GLContextLock {
Thread current = Thread.currentThread();
if (sdata.owner == null) {
sdata.owner = current;
- sdata.lockedStack = new Exception("Previously made current (1) by "+sdata.owner+", lock: "+this);
+ if(DEBUG) {
+ sdata.lockedStack = new Exception("Error: Previously made current (1) by "+sdata.owner+", lock: "+this);
+ }
} else if (sdata.owner != current) {
while (sdata.owner != null) {
if (sdata.failFastMode) {
- sdata.lockedStack.printStackTrace();
- throw new GLException("Attempt to make context current on thread " + current +
+ if(null!=sdata.lockedStack) {
+ sdata.lockedStack.printStackTrace();
+ }
+ throw new GLException("Error: Attempt to make context current on thread " + current +
" which is already current on thread " + sdata.owner);
} else {
try {
@@ -85,7 +91,9 @@ public class GLContextLock {
}
}
sdata.owner = current;
- sdata.lockedStack = new Exception("Previously made current (2) by "+sdata.owner+", lock: "+this);
+ if(DEBUG) {
+ sdata.lockedStack = new Exception("Previously made current (2) by "+sdata.owner+", lock: "+this);
+ }
} else {
throw new GLException("Attempt to make the same context current twice on thread " + current);
}
@@ -139,6 +147,7 @@ public class GLContextLock {
}
}
+ /** holding the owners stack trace when lock is acquired and DEBUG is true */
public final Exception getLockedStack() {
synchronized(sdata) {
return sdata.lockedStack;
diff --git a/src/jogl/classes/com/jogamp/opengl/impl/GLDrawableHelper.java b/src/jogl/classes/com/jogamp/opengl/impl/GLDrawableHelper.java
index 53fc34181..4ad0dd4c3 100644
--- a/src/jogl/classes/com/jogamp/opengl/impl/GLDrawableHelper.java
+++ b/src/jogl/classes/com/jogamp/opengl/impl/GLDrawableHelper.java
@@ -50,15 +50,29 @@ public class GLDrawableHelper {
protected static final boolean DEBUG = GLDrawableImpl.DEBUG;
private static final boolean VERBOSE = Debug.verbose();
private Object listenersLock = new Object();
- private List listeners = new ArrayList();
- private volatile boolean listenersIter = false; // avoid java.util.ConcurrentModificationException
- private Set listenersToBeInit = new HashSet();
- private boolean autoSwapBufferMode = true;
+ private List listeners;
+ private volatile boolean listenersIter; // avoid java.util.ConcurrentModificationException
+ private Set listenersToBeInit;
+ private boolean autoSwapBufferMode;
private Object glRunnablesLock = new Object();
- private ArrayList glRunnables = new ArrayList(); // one shot GL tasks
- private GLAnimatorControl animatorCtrl = null; // default
+ private ArrayList glRunnables;
+ private GLAnimatorControl animatorCtrl;
public GLDrawableHelper() {
+ reset();
+ }
+
+ public void reset() {
+ synchronized(listenersLock) {
+ listeners = new ArrayList();
+ listenersIter = false;
+ listenersToBeInit = new HashSet();
+ }
+ autoSwapBufferMode = true;
+ synchronized(glRunnablesLock) {
+ glRunnables = new ArrayList();
+ }
+ animatorCtrl = null;
}
public String toString() {
@@ -67,8 +81,8 @@ public class GLDrawableHelper {
synchronized(listenersLock) {
sb.append("GLEventListeners num "+listeners.size()+" [");
listenersIter = true;
- for (Iterator iter = listeners.iterator(); iter.hasNext(); ) {
- Object l = iter.next();
+ for (int i=0; i < listeners.size(); i++) {
+ Object l = listeners.get(i);
sb.append(l);
sb.append("[init ");
sb.append( !listenersToBeInit.contains(l) );
@@ -120,8 +134,8 @@ public class GLDrawableHelper {
public void dispose(GLAutoDrawable drawable) {
synchronized(listenersLock) {
listenersIter = true;
- for (Iterator iter = listeners.iterator(); iter.hasNext(); ) {
- GLEventListener listener = (GLEventListener) iter.next() ;
+ for (int i=0; i < listeners.size(); i++) {
+ GLEventListener listener = (GLEventListener) listeners.get(i) ;
listener.dispose(drawable);
listenersToBeInit.add(listener);
}
@@ -143,8 +157,8 @@ public class GLDrawableHelper {
public void init(GLAutoDrawable drawable) {
synchronized(listenersLock) {
listenersIter = true;
- for (Iterator iter = listeners.iterator(); iter.hasNext(); ) {
- GLEventListener listener = (GLEventListener) iter.next() ;
+ for (int i=0; i < listeners.size(); i++) {
+ GLEventListener listener = (GLEventListener) listeners.get(i) ;
if ( ! init( listener, drawable, false ) ) {
throw new GLException("GLEventListener "+listener+" already initialized: "+drawable);
}
@@ -156,8 +170,8 @@ public class GLDrawableHelper {
public void display(GLAutoDrawable drawable) {
synchronized(listenersLock) {
listenersIter = true;
- for (Iterator iter = listeners.iterator(); iter.hasNext(); ) {
- GLEventListener listener = (GLEventListener) iter.next() ;
+ for (int i=0; i < listeners.size(); i++) {
+ GLEventListener listener = (GLEventListener) listeners.get(i) ;
// GLEventListener may need to be init,
// in case this one is added after the realization of the GLAutoDrawable
init( listener, drawable, true ) ;
@@ -179,9 +193,8 @@ public class GLDrawableHelper {
public void reshape(GLAutoDrawable drawable, int x, int y, int width, int height) {
synchronized(listenersLock) {
listenersIter = true;
- int i=0;
- for (Iterator iter = listeners.iterator(); iter.hasNext(); i++) {
- reshape((GLEventListener) iter.next(), drawable, x, y, width, height, 0==i);
+ for (int i=0; i < listeners.size(); i++) {
+ reshape((GLEventListener) listeners.get(i), drawable, x, y, width, height, 0==i);
}
listenersIter = false;
}
@@ -198,8 +211,8 @@ public class GLDrawableHelper {
}
}
if(null!=_glRunnables) {
- for (Iterator iter = _glRunnables.iterator(); iter.hasNext(); ) {
- ((GLRunnable) iter.next()).run(drawable);
+ for (int i=0; i < _glRunnables.size(); i++) {
+ ((GLRunnable) _glRunnables.get(i)).run(drawable);
}
}
}
diff --git a/src/jogl/classes/com/jogamp/opengl/util/AWTAnimatorImpl.java b/src/jogl/classes/com/jogamp/opengl/util/AWTAnimatorImpl.java
index e3aff61c6..9dd58bb57 100644
--- a/src/jogl/classes/com/jogamp/opengl/util/AWTAnimatorImpl.java
+++ b/src/jogl/classes/com/jogamp/opengl/util/AWTAnimatorImpl.java
@@ -55,29 +55,36 @@ class AWTAnimatorImpl extends AnimatorImpl {
public void display(AnimatorBase animator,
boolean ignoreExceptions,
boolean printExceptions) {
- Iterator iter = animator.drawableIterator();
- while (animator.isAnimating() && !animator.getShouldStop() && !animator.getShouldPause() && iter.hasNext()) {
- GLAutoDrawable drawable = (GLAutoDrawable) iter.next();
- if (drawable instanceof JComponent) {
- // Lightweight components need a more efficient drawing
- // scheme than simply forcing repainting of each one in
- // turn since drawing one can force another one to be
- // drawn in turn
- lightweights.add(drawable);
- } else {
- try {
- drawable.display();
- } catch (RuntimeException e) {
- if (ignoreExceptions) {
- if (printExceptions) {
- e.printStackTrace();
+ List drawables = animator.acquireDrawables();
+ try {
+ for (int i=0;
+ animator.isAnimating() && !animator.getShouldStop() && !animator.getShouldPause() && i<drawables.size();
+ i++) {
+ GLAutoDrawable drawable = (GLAutoDrawable) drawables.get(i);
+ if (drawable instanceof JComponent) {
+ // Lightweight components need a more efficient drawing
+ // scheme than simply forcing repainting of each one in
+ // turn since drawing one can force another one to be
+ // drawn in turn
+ lightweights.add(drawable);
+ } else {
+ try {
+ drawable.display();
+ } catch (RuntimeException e) {
+ if (ignoreExceptions) {
+ if (printExceptions) {
+ e.printStackTrace();
+ }
+ } else {
+ throw(e);
}
- } else {
- throw(e);
}
}
}
+ } finally {
+ animator.releaseDrawables();
}
+
if (lightweights.size() > 0) {
try {
SwingUtilities.invokeAndWait(drawWithRepaintManagerRunnable);
diff --git a/src/jogl/classes/com/jogamp/opengl/util/AnimatorBase.java b/src/jogl/classes/com/jogamp/opengl/util/AnimatorBase.java
index a54f6be57..24eee1875 100644
--- a/src/jogl/classes/com/jogamp/opengl/util/AnimatorBase.java
+++ b/src/jogl/classes/com/jogamp/opengl/util/AnimatorBase.java
@@ -28,9 +28,11 @@
package com.jogamp.opengl.util;
+import com.jogamp.common.util.locks.RecursiveLock;
import com.jogamp.opengl.impl.Debug;
import java.util.ArrayList;
import java.util.Iterator;
+import java.util.List;
import javax.media.opengl.GLAnimatorControl;
import javax.media.opengl.GLAutoDrawable;
import javax.media.opengl.GLProfile;
@@ -43,7 +45,8 @@ public abstract class AnimatorBase implements GLAnimatorControl {
private static int animatorCount = 0;
- protected volatile ArrayList/*<GLAutoDrawable>*/ drawables = new ArrayList();
+ protected ArrayList/*<GLAutoDrawable>*/ drawables = new ArrayList();
+ protected RecursiveLock drawablesLock = new RecursiveLock();
protected AnimatorImpl impl;
protected String baseName;
protected Thread thread;
@@ -75,18 +78,24 @@ public abstract class AnimatorBase implements GLAnimatorControl {
protected abstract String getBaseName(String prefix);
public synchronized void add(GLAutoDrawable drawable) {
- ArrayList newList = (ArrayList) drawables.clone();
- newList.add(drawable);
- drawables = newList;
- drawable.setAnimator(this);
+ drawablesLock.lock();
+ try {
+ drawables.add(drawable);
+ drawable.setAnimator(this);
+ } finally {
+ drawablesLock.unlock();
+ }
notifyAll();
}
public synchronized void remove(GLAutoDrawable drawable) {
- ArrayList newList = (ArrayList) drawables.clone();
- newList.remove(drawable);
- drawables = newList;
- drawable.setAnimator(null);
+ drawablesLock.lock();
+ try {
+ drawables.remove(drawable);
+ drawable.setAnimator(null);
+ } finally {
+ drawablesLock.unlock();
+ }
notifyAll();
}
@@ -101,8 +110,13 @@ public abstract class AnimatorBase implements GLAnimatorControl {
totalFrames++;
}
- public Iterator drawableIterator() {
- return drawables.iterator();
+ public List acquireDrawables() {
+ drawablesLock.lock();
+ return drawables;
+ }
+
+ public void releaseDrawables() {
+ drawablesLock.unlock();
}
public long getCurrentTime() {
diff --git a/src/jogl/classes/com/jogamp/opengl/util/AnimatorImpl.java b/src/jogl/classes/com/jogamp/opengl/util/AnimatorImpl.java
index e4bf8d711..8f2715e0a 100644
--- a/src/jogl/classes/com/jogamp/opengl/util/AnimatorImpl.java
+++ b/src/jogl/classes/com/jogamp/opengl/util/AnimatorImpl.java
@@ -44,20 +44,26 @@ class AnimatorImpl {
public void display(AnimatorBase animator,
boolean ignoreExceptions,
boolean printExceptions) {
- Iterator iter = animator.drawableIterator();
- while (animator.isAnimating() && !animator.getShouldStop() && !animator.getShouldPause() && iter.hasNext()) {
- GLAutoDrawable drawable = (GLAutoDrawable) iter.next();
- try {
- drawable.display();
- } catch (RuntimeException e) {
- if (ignoreExceptions) {
- if (printExceptions) {
- e.printStackTrace();
+ List drawables = animator.acquireDrawables();
+ try {
+ for (int i=0;
+ animator.isAnimating() && !animator.getShouldStop() && !animator.getShouldPause() && i<drawables.size();
+ i++) {
+ GLAutoDrawable drawable = (GLAutoDrawable) drawables.get(i);
+ try {
+ drawable.display();
+ } catch (RuntimeException e) {
+ if (ignoreExceptions) {
+ if (printExceptions) {
+ e.printStackTrace();
+ }
+ } else {
+ throw(e);
}
- } else {
- throw(e);
}
}
+ } finally {
+ animator.releaseDrawables();
}
}
diff --git a/src/junit/com/jogamp/test/junit/core/TestIteratorIndexCORE.java b/src/junit/com/jogamp/test/junit/core/TestIteratorIndexCORE.java
new file mode 100644
index 000000000..0ed102e40
--- /dev/null
+++ b/src/junit/com/jogamp/test/junit/core/TestIteratorIndexCORE.java
@@ -0,0 +1,128 @@
+/**
+ * Copyright 2010 JogAmp Community. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this list of
+ * conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those of the
+ * authors and should not be interpreted as representing official policies, either expressed
+ * or implied, of JogAmp Community.
+ */
+
+package com.jogamp.test.junit.core;
+
+import com.jogamp.test.junit.util.UITestCase;
+
+import java.util.*;
+import java.io.IOException;
+
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.AfterClass;
+import org.junit.Test;
+
+public class TestIteratorIndexCORE extends UITestCase {
+
+ static int elems = 10;
+ static int loop = 9999999;
+
+ public void populate(List l, int len) {
+ while(len>0) {
+ l.add(new Integer(len--));
+ }
+ }
+
+ @Test
+ public void test01ArrayListIterator() {
+ int sum=0;
+ ArrayList l = new ArrayList();
+ populate(l, elems);
+
+ for(int j=loop; j>0; j--) {
+ for(Iterator iter = l.iterator(); iter.hasNext(); ) {
+ Integer i = (Integer)iter.next();
+ sum+=i.intValue();
+ }
+ }
+ System.err.println("test01-arraylist-iterator sum: "+sum);
+ }
+
+ @Test
+ public void test0ArrayListIndex() {
+ int sum=0;
+ ArrayList l = new ArrayList();
+ populate(l, elems);
+
+ for(int j=loop; j>0; j--) {
+ for(int k = 0; k < l.size(); k++) {
+ Integer i = (Integer)l.get(k);
+ sum+=i.intValue();
+ }
+ }
+ System.err.println("test01-arraylist-index sum: "+sum);
+ }
+
+ @Test
+ public void test01LinkedListListIterator() {
+ int sum=0;
+ LinkedList l = new LinkedList();
+ populate(l, elems);
+
+ for(int j=loop; j>0; j--) {
+ for(Iterator iter = l.iterator(); iter.hasNext(); ) {
+ Integer i = (Integer)iter.next();
+ sum+=i.intValue();
+ }
+ }
+ System.err.println("test01-linkedlist-iterator sum: "+sum);
+ }
+
+ @Test
+ public void test01LinkedListListIndex() {
+ int sum=0;
+ LinkedList l = new LinkedList();
+ populate(l, elems);
+
+ for(int j=loop; j>0; j--) {
+ for(int k = 0; k < l.size(); k++) {
+ Integer i = (Integer)l.get(k);
+ sum+=i.intValue();
+ }
+ }
+ System.err.println("test01-linkedlist-index sum: "+sum);
+ }
+
+ public static void main(String args[]) throws IOException {
+ String tstname = TestIteratorIndexCORE.class.getName();
+ org.apache.tools.ant.taskdefs.optional.junit.JUnitTestRunner.main(new String[] {
+ tstname,
+ "filtertrace=true",
+ "haltOnError=false",
+ "haltOnFailure=false",
+ "showoutput=true",
+ "outputtoformatters=true",
+ "logfailedtests=true",
+ "logtestlistenerevents=true",
+ "formatter=org.apache.tools.ant.taskdefs.optional.junit.PlainJUnitResultFormatter",
+ "formatter=org.apache.tools.ant.taskdefs.optional.junit.XMLJUnitResultFormatter,TEST-"+tstname+".xml" } );
+ }
+
+}