Parcourir la source

* Optimization to prevent garbage generation by replacing Arrays.sort() with SortUtil.msort()
* Replaced "evil" code from SortUtil.msort() with "good" code


git-svn-id: https://jmonkeyengine.googlecode.com/svn/trunk@7662 75d07b2b-3a1a-0410-a2c5-0572b91ccdca

sha..rd il y a 14 ans
Parent
commit
88a5109865

+ 13 - 2
engine/src/core/com/jme3/renderer/queue/GeometryList.java

@@ -34,6 +34,7 @@ package com.jme3.renderer.queue;
 
 
 import com.jme3.renderer.Camera;
 import com.jme3.renderer.Camera;
 import com.jme3.scene.Geometry;
 import com.jme3.scene.Geometry;
+import com.jme3.util.SortUtil;
 import java.util.Arrays;
 import java.util.Arrays;
 
 
 /**
 /**
@@ -48,12 +49,14 @@ public class GeometryList {
     private static final int DEFAULT_SIZE = 32;
     private static final int DEFAULT_SIZE = 32;
 
 
     private Geometry[] geometries;
     private Geometry[] geometries;
+    private Geometry[] geometries2;
     private int size;
     private int size;
     private GeometryComparator comparator;
     private GeometryComparator comparator;
 
 
     public GeometryList(GeometryComparator comparator) {
     public GeometryList(GeometryComparator comparator) {
         size = 0;
         size = 0;
         geometries = new Geometry[DEFAULT_SIZE];
         geometries = new Geometry[DEFAULT_SIZE];
+        geometries2 = new Geometry[DEFAULT_SIZE];
         this.comparator = comparator;
         this.comparator = comparator;
     }
     }
 
 
@@ -80,6 +83,8 @@ public class GeometryList {
             Geometry[] temp = new Geometry[size * 2];
             Geometry[] temp = new Geometry[size * 2];
             System.arraycopy(geometries, 0, temp, 0, size);
             System.arraycopy(geometries, 0, temp, 0, size);
             geometries = temp; // original list replaced by double-size list
             geometries = temp; // original list replaced by double-size list
+            
+            geometries2 = new Geometry[size * 2];
         }
         }
         geometries[size++] = g;
         geometries[size++] = g;
     }
     }
@@ -101,8 +106,14 @@ public class GeometryList {
     public void sort() {
     public void sort() {
         if (size > 1) {
         if (size > 1) {
             // sort the spatial list using the comparator
             // sort the spatial list using the comparator
-            Arrays.sort(geometries, 0, size, comparator);
-//            Arrays.sort(geometries, comparator);
+            
+//            SortUtil.qsort(geometries, 0, size, comparator);
+//            Arrays.sort(geometries, 0, size, comparator);            
+            
+            System.arraycopy(geometries, 0, geometries2, 0, size);
+            SortUtil.msort(geometries2, geometries, 0, size-1, comparator);
+            
+
         }
         }
     }
     }
 }
 }

+ 169 - 108
engine/src/core/com/jme3/util/SortUtil.java

@@ -29,7 +29,6 @@
  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
  */
-
 package com.jme3.util;
 package com.jme3.util;
 
 
 import java.util.Arrays;
 import java.util.Arrays;
@@ -39,58 +38,133 @@ import java.util.Comparator;
  * Quick and merge sort implementations that create no garbage, unlike {@link
  * Quick and merge sort implementations that create no garbage, unlike {@link
  * Arrays#sort}. The merge sort is stable, the quick sort is not.
  * Arrays#sort}. The merge sort is stable, the quick sort is not.
  */
  */
-public class SortUtil
-{
-    public static void gsort(Object[] a, Comparator comp){
-        int p = 0;
-        int l = a.length;
-        while (p < l){
-            int pm1 = p-1;
-            if (p == 0 || comp.compare(a[p], a[pm1]) >= 0){
-                p++;
+public class SortUtil {
+
+    /** 
+     * The size at or below which we will use insertion sort because it's
+     * probably faster. 
+     */
+    private static final int INSERTION_SORT_THRESHOLD = 7;
+    
+    
+    /**
+ procedure optimizedGnomeSort(a[])
+    pos := 1
+    last := 0
+    while pos < length(a)
+        if (a[pos] >= a[pos-1])
+            if (last != 0)
+                pos := last
+                last := 0
+            end if
+            pos := pos + 1
+        else
+            swap a[pos] and a[pos-1]
+            if (pos > 1)
+                if (last == 0)
+                    last := pos
+                end if
+                pos := pos - 1
+            else
+                pos := pos + 1
+            end if
+        end if
+    end while
+end procedure
+     */
+    
+    public static void gsort(Object[] a, Comparator comp) {
+        int pos = 1;
+        int last = 0;
+        int length = a.length;
+        
+        while (pos < length){
+            if ( comp.compare(a[pos], a[pos-1]) >= 0 ){
+                if (last != 0){
+                    pos = last;
+                    last = 0;
+                }
+                pos ++;
             }else{
             }else{
-                Object t = a[p];
-                a[p] = a[pm1];
-                a[pm1] = t;
-                p--;
+                Object tmp = a[pos];
+                a[pos] = a[pos-1];
+                a[pos-1] = tmp;
+                
+                if (pos > 1){
+                    if (last == 0){
+                        last = pos;
+                    }
+                    pos --;
+                }else{
+                    pos ++;
+                }
             }
             }
         }
         }
+        
+//        int p = 0;
+//        int l = a.length;
+//        while (p < l) {
+//            int pm1 = p - 1;
+//            if (p == 0 || comp.compare(a[p], a[pm1]) >= 0) {
+//                p++;
+//            } else {
+//                Object t = a[p];
+//                a[p] = a[pm1];
+//                a[pm1] = t;
+//                p--;
+//            }
+//        }
     }
     }
 
 
-    private static void test(Float[] original, Float[] sorted, Comparator<Float> ic){
-        for (int i = 0; i < 1000000; i++){
+    private static void test(Float[] original, Float[] sorted, Comparator<Float> ic) {
+        long time, dt;
+        
+        time = System.nanoTime();
+        for (int i = 0; i < 1000000; i++) {
             System.arraycopy(original, 0, sorted, 0, original.length);
             System.arraycopy(original, 0, sorted, 0, original.length);
             gsort(sorted, ic);
             gsort(sorted, ic);
         }
         }
+        dt = System.nanoTime() - time;
+        System.out.println("GSort " + (dt/1000000.0) + " ms");
 
 
-        for (int i = 0; i < 1000000; i++){
+        time = System.nanoTime();
+        for (int i = 0; i < 1000000; i++) {
             System.arraycopy(original, 0, sorted, 0, original.length);
             System.arraycopy(original, 0, sorted, 0, original.length);
             qsort(sorted, ic);
             qsort(sorted, ic);
         }
         }
+        dt = System.nanoTime() - time;
+        System.out.println("QSort " + (dt/1000000.0) + " ms");
 
 
-        for (int i = 0; i < 1000000; i++){
+        time = System.nanoTime();
+        for (int i = 0; i < 1000000; i++) {
             System.arraycopy(original, 0, sorted, 0, original.length);
             System.arraycopy(original, 0, sorted, 0, original.length);
             msort(original, sorted, ic);
             msort(original, sorted, ic);
         }
         }
-   
-        for (int i = 0; i < 1000000; i++){
+        dt = System.nanoTime() - time;
+        System.out.println("MSort " + (dt/1000000.0) + " ms");
+
+        time = System.nanoTime();
+        for (int i = 0; i < 1000000; i++) {
             System.arraycopy(original, 0, sorted, 0, original.length);
             System.arraycopy(original, 0, sorted, 0, original.length);
             Arrays.sort(sorted, ic);
             Arrays.sort(sorted, ic);
         }
         }
+        dt = System.nanoTime() - time;
+        System.out.println("ASort " + (dt/1000000.0) + " ms");
     }
     }
 
 
-    public static void main(String[] args){
+    public static void main(String[] args) {
         Comparator<Float> ic = new Comparator<Float>() {
         Comparator<Float> ic = new Comparator<Float>() {
+
             public int compare(Float o1, Float o2) {
             public int compare(Float o1, Float o2) {
                 return (int) (o1 - o2);
                 return (int) (o1 - o2);
             }
             }
         };
         };
-        Float[] original = new Float[]{ 2f, 1f, 5f, 3f, 4f, 6f, 8f, 9f,
-                                        11f, 10f, 12f, 13f, 14f, 15f, 7f, 19f, 20f, 18f, 16f, 17f,
-                                        21f, 23f, 22f, 24f, 25f, 27f, 26f, 29f, 28f, 30f, 31f};
-        Float[] sorted   = new Float[original.length];
+        Float[] original = new Float[]{2f, 1f, 5f, 3f, 4f, 6f, 8f, 9f,
+            11f, 10f, 12f, 13f, 14f, 15f, 7f, 19f, 20f, 18f, 16f, 17f,
+            21f, 23f, 22f, 24f, 25f, 27f, 26f, 29f, 28f, 30f, 31f};
+        Float[] sorted = new Float[original.length];
 
 
-        while (true){
+        while (true) {
             test(original, sorted, ic);
             test(original, sorted, ic);
         }
         }
     }
     }
@@ -98,9 +172,8 @@ public class SortUtil
     /**
     /**
      * Quick sorts the supplied array using the specified comparator.
      * Quick sorts the supplied array using the specified comparator.
      */
      */
-    public static void qsort (Object[] a, Comparator comp)
-    {
-        qsort(a, 0, a.length-1, comp);
+    public static void qsort(Object[] a, Comparator comp) {
+        qsort(a, 0, a.length - 1, comp);
     }
     }
 
 
     /**
     /**
@@ -110,8 +183,7 @@ public class SortUtil
      * @param hi0 the index of the highest element to include in the sort.
      * @param hi0 the index of the highest element to include in the sort.
      */
      */
     @SuppressWarnings("unchecked")
     @SuppressWarnings("unchecked")
-    public static void qsort (Object[] a, int lo0, int hi0, Comparator comp)
-    {
+    public static void qsort(Object[] a, int lo0, int hi0, Comparator comp) {
         // bail out if we're already done
         // bail out if we're already done
         if (hi0 <= lo0) {
         if (hi0 <= lo0) {
             return;
             return;
@@ -122,16 +194,18 @@ public class SortUtil
         if (hi0 - lo0 == 1) {
         if (hi0 - lo0 == 1) {
             // if they're not already sorted, swap them
             // if they're not already sorted, swap them
             if (comp.compare(a[hi0], a[lo0]) < 0) {
             if (comp.compare(a[hi0], a[lo0]) < 0) {
-                t = a[lo0]; a[lo0] = a[hi0]; a[hi0] = t;
+                t = a[lo0];
+                a[lo0] = a[hi0];
+                a[hi0] = t;
             }
             }
             return;
             return;
         }
         }
 
 
         // the middle element in the array is our partitioning element
         // the middle element in the array is our partitioning element
-        Object mid = a[(lo0 + hi0)/2];
+        Object mid = a[(lo0 + hi0) / 2];
 
 
         // set up our partitioning boundaries
         // set up our partitioning boundaries
-        int lo = lo0-1, hi = hi0+1;
+        int lo = lo0 - 1, hi = hi0 + 1;
 
 
         // loop through the array until indices cross
         // loop through the array until indices cross
         for (;;) {
         for (;;) {
@@ -145,7 +219,9 @@ public class SortUtil
 
 
             // swap the two elements or bail out of the loop
             // swap the two elements or bail out of the loop
             if (hi > lo) {
             if (hi > lo) {
-                t = a[lo]; a[lo] = a[hi]; a[hi] = t;
+                t = a[lo];
+                a[lo] = a[hi];
+                a[hi] = t;
             } else {
             } else {
                 break;
                 break;
             }
             }
@@ -153,19 +229,18 @@ public class SortUtil
 
 
         // if the right index has not reached the left side of array
         // if the right index has not reached the left side of array
         // must now sort the left partition
         // must now sort the left partition
-        if (lo0 < lo-1) {
-            qsort(a, lo0, lo-1, comp);
+        if (lo0 < lo - 1) {
+            qsort(a, lo0, lo - 1, comp);
         }
         }
 
 
         // if the left index has not reached the right side of array
         // if the left index has not reached the right side of array
         // must now sort the right partition
         // must now sort the right partition
-        if (hi+1 < hi0) {
-            qsort(a, hi+1, hi0, comp);
+        if (hi + 1 < hi0) {
+            qsort(a, hi + 1, hi0, comp);
         }
         }
     }
     }
 
 
-    public static void qsort (int[] a, int lo0, int hi0, Comparator comp)
-    {
+    public static void qsort(int[] a, int lo0, int hi0, Comparator comp) {
         // bail out if we're already done
         // bail out if we're already done
         if (hi0 <= lo0) {
         if (hi0 <= lo0) {
             return;
             return;
@@ -176,16 +251,18 @@ public class SortUtil
         if (hi0 - lo0 == 1) {
         if (hi0 - lo0 == 1) {
             // if they're not already sorted, swap them
             // if they're not already sorted, swap them
             if (comp.compare(a[hi0], a[lo0]) < 0) {
             if (comp.compare(a[hi0], a[lo0]) < 0) {
-                t = a[lo0]; a[lo0] = a[hi0]; a[hi0] = t;
+                t = a[lo0];
+                a[lo0] = a[hi0];
+                a[hi0] = t;
             }
             }
             return;
             return;
         }
         }
 
 
         // the middle element in the array is our partitioning element
         // the middle element in the array is our partitioning element
-        int mid = a[(lo0 + hi0)/2];
+        int mid = a[(lo0 + hi0) / 2];
 
 
         // set up our partitioning boundaries
         // set up our partitioning boundaries
-        int lo = lo0-1, hi = hi0+1;
+        int lo = lo0 - 1, hi = hi0 + 1;
 
 
         // loop through the array until indices cross
         // loop through the array until indices cross
         for (;;) {
         for (;;) {
@@ -199,7 +276,9 @@ public class SortUtil
 
 
             // swap the two elements or bail out of the loop
             // swap the two elements or bail out of the loop
             if (hi > lo) {
             if (hi > lo) {
-                t = a[lo]; a[lo] = a[hi]; a[hi] = t;
+                t = a[lo];
+                a[lo] = a[hi];
+                a[hi] = t;
             } else {
             } else {
                 break;
                 break;
             }
             }
@@ -207,85 +286,67 @@ public class SortUtil
 
 
         // if the right index has not reached the left side of array
         // if the right index has not reached the left side of array
         // must now sort the left partition
         // must now sort the left partition
-        if (lo0 < lo-1) {
-            qsort(a, lo0, lo-1, comp);
+        if (lo0 < lo - 1) {
+            qsort(a, lo0, lo - 1, comp);
         }
         }
 
 
         // if the left index has not reached the right side of array
         // if the left index has not reached the right side of array
         // must now sort the right partition
         // must now sort the right partition
-        if (hi+1 < hi0) {
-            qsort(a, hi+1, hi0, comp);
+        if (hi + 1 < hi0) {
+            qsort(a, hi + 1, hi0, comp);
         }
         }
     }
     }
     
     
     /**
     /**
-     * Merge sorts the supplied array using the specified comparator.
-     *
-     * @param src contains the elements to be sorted.
-     * @param dest must contain the same values as the src array.
+     * Merge sort
      */
      */
-    public static void msort (Object[] src, Object[] dest, Comparator comp)
-    {
-        msort(src, dest, 0, src.length, 0, comp);
+    public static void msort(Object[] src, Object[] dest, Comparator comp){
+        msort(src, dest, 0, src.length - 1, comp);
     }
     }
-
+    
     /**
     /**
-     * Merge sorts the supplied array using the specified comparator.
-     *
-     * @param src contains the elements to be sorted.
-     * @param dest must contain the same values as the src array.
+     * Merge sort
+     * 
+     * @param src Source array
+     * @param dest Destination array
+     * @param low Index of beginning element
+     * @param high Index of end element
+     * @param comp Comparator
      */
      */
-    public static void msort (Object[] src, Object[] dest, int low, int high,
-                              Comparator comp)
-    {
-        msort(src, dest, low, high, 0, comp);
+    public static void msort(Object[] src, Object[] dest, int low, int high,
+            Comparator comp) {
+        if(low < high) {
+            int center = (low + high) / 2;
+            msort(src, dest, low, center, comp);
+            msort(src, dest, center + 1, high, comp);
+            merge(src, dest, low, center + 1, high, comp);
+        }
     }
     }
-
-    /** Implements the actual merge sort. */
-    @SuppressWarnings("unchecked")
-    protected static void msort (Object[] src, Object[] dest, int low,
-                                 int high, int offset, Comparator comp)
-    {
-	// use an insertion sort on small arrays
-	int length = high - low;
-	if (length < INSERTION_SORT_THRESHOLD) {
-	    for (int ii = low; ii < high; ii++) {
-		for (int jj = ii;
-                     jj > low && comp.compare(dest[jj-1], dest[jj]) > 0; jj--) {
-                    Object temp = dest[jj];
-                    dest[jj] = dest[jj-1];
-                    dest[jj-1] = temp;
-                }
+    
+    private static void merge(Object[] src, Object[] dest,
+            int low, int middle, int high, Comparator comp) {
+        int leftEnd = middle - 1;
+        int pos = low;
+        int numElements = high - low + 1;
+
+        while (low <= leftEnd && middle <= high) {
+            if (comp.compare(src[low], src[middle]) <= 0) {
+                dest[pos++] = src[low++];
+            } else {
+                dest[pos++] = src[middle++];
             }
             }
-	    return;
-	}
-
-        // recursively sort each half of dest into src
-        int destLow = low, destHigh = high;
-        low += offset;
-        high += offset;
-        int mid = (low + high) >> 1;
-        msort(dest, src, low, mid, -offset, comp);
-        msort(dest, src, mid, high, -offset, comp);
-
-        // if the list is already sorted, just copy from src to dest; this
-        // optimization results in faster sorts for nearly ordered lists
-        if (comp.compare(src[mid-1], src[mid]) <= 0) {
-            System.arraycopy(src, low, dest, destLow, length);
-            return;
         }
         }
 
 
-        // merge the sorted halves (now in src) into dest
-        for (int ii = destLow, pp = low, qq = mid; ii < destHigh; ii++) {
-            if (qq >= high || pp < mid && comp.compare(src[pp], src[qq]) <= 0) {
-                dest[ii] = src[pp++];
-            } else {
-                dest[ii] = src[qq++];
-            }
+        while (low <= leftEnd) {
+            dest[pos++] = src[low++];
         }
         }
-    }
 
 
-    /** The size at or below which we will use insertion sort because it's
-     * probably faster. */
-    private static final int INSERTION_SORT_THRESHOLD = 7;
+        while (middle <= high) {
+            dest[pos++] = src[middle++];
+        }
+
+        for (int i = 0; i < numElements; i++, high--) {
+            src[high] = dest[high];
+        }
+    }
 }
 }