2007-03-20 Juan Cristóbal Olivares <juancri@gmail.com>
authorMiguel de Icaza <miguel@gnome.org>
Tue, 20 Mar 2007 15:39:19 +0000 (15:39 -0000)
committerMiguel de Icaza <miguel@gnome.org>
Tue, 20 Mar 2007 15:39:19 +0000 (15:39 -0000)
        * List.cs (FindAll): Optimize FindAll using a bitmask to
        * determine
        the number of positive matches, this increases the performance
in
        all cases below 10,000,000 elements extensively:

        100 elements:
        old method:             00:00:00.0126610 (26x)
        stackalloc bit method:  00:00:00.0004750 (1x)
        array bit method:       00:00:00.0010700 (2x)
        heap bit method:        00:00:00.0038830 (8x)

        1,000 elements:
        old method:             00:00:00.0139250 (24x)
        stackalloc bit method:  00:00:00.0005670 (1x)
        array bit method:       00:00:00.0010890 (2x)
        heap bit method:        00:00:00.0034920 (6x)

        10,000 elements:
        old method:             00:00:00.0136110 (12x)
        stackalloc bit method:  00:00:00.0011240 (1x)
        array bit method:       00:00:00.0016450 (1.4x)
        heap bit method:        00:00:00.0043110 (3x)

        50,000 elements:
        old method:             00:00:00.0175970 (3x)
        stackalloc bit method:  00:00:00.0085630 (1.5x)
        array bit method:       00:00:00.0055010 (1x)
        heap bit method:        00:00:00.0099590 (1.8x)

        100,000 elements:
        old method:             00:00:00.0210330 (2x)
        array bit method:       00:00:00.0100430 (1x)
        heap bit method:        00:00:00.0154150 (1.5x)

        1,000,000 elements:
        old method:             00:00:00.1243730 (1.2x)
        array bit method:       00:00:00.0973110 (1x)
        heap bit method:        00:00:00.1285650 (1.3x)

        10,000,000 elements:
        old method:             00:00:00.9252570 (1x)
        array bit method:       00:00:00.9632300 ( 1.05x)
        heap bit method:        00:00:01.1098490 (1.20x)

svn path=/trunk/mcs/; revision=74694

mcs/class/corlib/System.Collections.Generic/ChangeLog
mcs/class/corlib/System.Collections.Generic/List.cs
mcs/class/corlib/Test/System.Collections.Generic/ListTest.cs
mcs/class/corlib/Test/run_test.sh

index 457d194da954a8af28d3f2564feaf8737694687d..fc21f36e66eae3f6ed5bd65beb9dec2fb8ecba57 100644 (file)
@@ -1,3 +1,48 @@
+2007-03-20  Juan Cristóbal Olivares <juancri@gmail.com>
+
+       * List.cs (FindAll): Optimize FindAll using a bitmask to determine
+       the number of positive matches, this increases the performance in
+       all cases below 10,000,000 elements extensively:
+
+       100 elements:
+       old method:             00:00:00.0126610 (26x)
+       stackalloc bit method:  00:00:00.0004750 (1x)
+       array bit method:       00:00:00.0010700 (2x)
+       heap bit method:        00:00:00.0038830 (8x)
+
+       1,000 elements:
+       old method:             00:00:00.0139250 (24x)
+       stackalloc bit method:  00:00:00.0005670 (1x)
+       array bit method:       00:00:00.0010890 (2x)
+       heap bit method:        00:00:00.0034920 (6x)
+
+       10,000 elements:
+       old method:             00:00:00.0136110 (12x)
+       stackalloc bit method:  00:00:00.0011240 (1x)
+       array bit method:       00:00:00.0016450 (1.4x)
+       heap bit method:        00:00:00.0043110 (3x)
+
+       50,000 elements:
+       old method:             00:00:00.0175970 (3x)
+       stackalloc bit method:  00:00:00.0085630 (1.5x)
+       array bit method:       00:00:00.0055010 (1x)
+       heap bit method:        00:00:00.0099590 (1.8x)
+
+       100,000 elements:
+       old method:             00:00:00.0210330 (2x)
+       array bit method:       00:00:00.0100430 (1x)
+       heap bit method:        00:00:00.0154150 (1.5x)
+
+       1,000,000 elements:
+       old method:             00:00:00.1243730 (1.2x)
+       array bit method:       00:00:00.0973110 (1x)
+       heap bit method:        00:00:00.1285650 (1.3x)
+
+       10,000,000 elements:
+       old method:             00:00:00.9252570 (1x)
+       array bit method:       00:00:00.9632300 ( 1.05x)
+       heap bit method:        00:00:01.1098490 (1.20x)
+
 2007-03-08  David Mitchell <dmitchell@logos.com>
 
        * List.cs: Fix the case where List.set_Item(int index) throws
index a9d82d3539ec2f4c368cbbaddf9999ae85ac621c..633663949f694afd5d26e8d08d29a29c05870b20 100644 (file)
@@ -212,19 +212,68 @@ namespace System.Collections.Generic {
                                throw new ArgumentNullException ("match");
                }
                
-               // Maybe we could make this faster. For example, you could
-               // make a bit set with stackalloc for which elements to copy
-               // then you could size the array correctly.
                public List <T> FindAll (Predicate <T> match)
                {
-                       CheckMatch (match);
-                       List <T> f = new List <T> ();
-                       
-                       foreach (T t in this)
-                               if (match (t))
-                                       f.Add (t);
+                       this.CheckMatch (match);
+                       if (this._size <= 0x10000) // <= 8 * 1024 * 8 (8k in stack)
+                               return this.FindAllStackBits (match);
+                       else 
+                               return this.FindAllList (match);
+               }
+               
+               private List <T> FindAllStackBits (Predicate <T> match)
+               {
+                       unsafe
+                       {
+                               uint *bits = stackalloc uint [(this._size / 32) + 1];
+                               uint *ptr = bits;
+                               int found = 0;
+                               uint bitmask = 0x80000000;
+                               
+                               for (int i = 0; i < this._size; i++)
+                               {
+                                       if (match (this._items [i]))
+                                       {
+                                               (*ptr) = (*ptr) | bitmask;
+                                               found++;
+                                       }
+                                       
+                                       bitmask = bitmask >> 1;
+                                       if (bitmask == 0)
+                                       {
+                                               ptr++;
+                                               bitmask = 0x80000000;
+                                       }
+                               }
+                               
+                               List <T> results = new List <T> (found);
+                               bitmask = 0x80000000;
+                               ptr = bits;
+                               for (int i = 0; i < this._size; i++)
+                               {
+                                       if (((*ptr) & bitmask) == bitmask)
+                                               results.Add (this._items [i]);
+                                       
+                                       bitmask = bitmask >> 1;
+                                       if (bitmask == 0)
+                                       {
+                                               ptr++;
+                                               bitmask = 0x80000000;
+                                       }
+                               }
+                               
+                               return results;
+                       }
+               }
+               
+               private List <T> FindAllList (Predicate <T> match)
+               {
+                       List <T> results = new List <T> ();
+                       for (int i = 0; i < this._size; i++)
+                               if (match (this._items [i]))
+                                       results.Add (this._items [i]);
                        
-                       return f;
+                       return results;
                }
                
                public int FindIndex (Predicate <T> match)
index a6951d9fe6ccb24f640e32c37a3d7ee92dff03ea..87d70e068e41273fe6fa384bc3a4b37de83ffe35 100644 (file)
@@ -467,7 +467,7 @@ namespace MonoTests.System.Collections.Generic {
                }
 
                [Test]
-               public void FindAllTest ()
+               public void FindAllSmallTest ()
                {
                        List <int> findings = _list1.FindAll (FindMultipleOfFour);
                        Assert.AreEqual (4, findings.Count);
@@ -480,6 +480,42 @@ namespace MonoTests.System.Collections.Generic {
                        Assert.IsNotNull (findings);
                        Assert.AreEqual (0, findings.Count);
                }
+               
+               [Test]
+               public void FindAllMediumTest ()
+               {
+                       List <int> integers = new List <int> (10000);
+                       for (int i = 1; i <= 10000; i++)
+                               integers.Add (i);
+                       
+                       List <int> results = integers.FindAll (FindMultipleOfFour);
+                       
+                       Assert.IsNotNull (results);
+                       Assert.AreEqual (2500, results.Count);
+                       
+                       results = integers.FindAll (FindMultipleOfTwelve);
+                       
+                       Assert.IsNotNull (results);
+                       Assert.AreEqual (833, results.Count);
+               }
+               
+               [Test]
+               public void FindAllLargeTest ()
+               {
+                       List <int> integers = new List <int> (70000);
+                       for (int i = 1; i <= 80000; i++)
+                               integers.Add (i);
+                       
+                       List <int> results = integers.FindAll (FindMultipleOfFour);
+                       
+                       Assert.IsNotNull (results);
+                       Assert.AreEqual (20000, results.Count);
+                       
+                       results = integers.FindAll (FindMultipleOfTwelve);
+                       
+                       Assert.IsNotNull (results);
+                       Assert.AreEqual (6666, results.Count);
+               }
 
                [Test, ExpectedException (typeof (ArgumentNullException))]
                public void FindAllNullTest ()
index 083073f63986651080df3c10158dd7da2611300e..4a5fd5e7b7987e49703eb9b769d0454ec535fa49 100755 (executable)
@@ -12,7 +12,7 @@ if [ $# -eq 0 ]; then
 fi
 
 topdir=../../..
-NUNITCONSOLE=$topdir/nunit20/nunit-console.exe
+NUNITCONSOLE=$topdir/class/lib/net_2_0/nunit-console.exe
 MONO_PATH=$topdir/nunit20:$topdir/class/lib:.
 
 for i in $@; do