Bladeren bron

Speed tests and optimisation

Billy Barrow 1 jaar geleden
bovenliggende
commit
1746ffce50

+ 1 - 1
src/lib/Collections/BinaryData.vala

@@ -24,7 +24,7 @@ namespace Invercargill {
         }
 
         public BinaryData.from_enumerable(Enumerable<uint8> data) {
-            chunks = Invercargill.single(data.to_series());
+            chunks = Invercargill.single(data.to_vector());
             endianness = Endianness.Native;
         }
 

+ 9 - 0
src/lib/Collections/Fifo.vala

@@ -84,6 +84,15 @@ namespace Invercargill {
                 () => get_next());
         }
 
+        ~Fifo() {
+            var n = first_item;
+            while(n != null) {
+                var c = n;
+                n = n.next_item;
+                c.next_item = null;
+            }
+        }
+
         private class FifoItem<T> {
             public T item;
             public FifoItem<T>? next_item;

+ 20 - 9
src/lib/Collections/Series.vala

@@ -29,15 +29,7 @@ namespace Invercargill {
         public Series() {}
 
         public override Tracker<T> get_tracker() {
-            var current = root;
-
-            return new LambdaTracker<T>(
-                () => current != null,
-                () => {
-                    var val = current.value;
-                    current = current.next;
-                    return val;
-                });
+            return new SeriesTracker<T>(root);
         }
 
         public override T[] to_array () {
@@ -72,6 +64,25 @@ namespace Invercargill {
             return n_items;
         }
 
+        private class SeriesTracker<T> : Tracker<T> {
+
+            private SeriesItem<T>? current;
+
+            public SeriesTracker(SeriesItem<T>? root) {
+                current = root;
+            }
+
+            public override bool has_next() {
+                return current != null;
+            }
+            public override T get_next() {
+                var value = current.value;
+                current = current.next;
+                return value;
+            }
+
+        }
+
     }
 
 }

+ 47 - 19
src/lib/Collections/Vector.vala

@@ -4,32 +4,26 @@ namespace Invercargill {
 
         private T[] array;
         private int n_items = 0;
+        private SafeReadFunc<T> safe_read;
+        private SafeWriteFunc<T> safe_write;
 
         private const int INITIAL_SIZE = 2;
 
         public Vector() {
             array = new T[INITIAL_SIZE];
+            safe_read = get_safe_read_function_for<T>();
+            safe_write = get_safe_write_function_for<T>();
         }
 
         public override Tracker<T> get_tracker() {
-            var i = 0;
-            return new Generator<T>(() => {
-                lock(array) {
-                    if(i < n_items) {
-                        var item = safely_read_array<T>(array, i);
-                        i++;
-                        return GeneratorResult<T>.item(item);
-                    }
-                    return GeneratorResult<T>.end();
-                }
-            }).get_tracker();
+            return new VectorTracker<T>(this);
         }
 
         public override T[] to_array () {
             lock(array) {
                 var a2 = new T[n_items];
                 for(var i = 0; i < n_items; i++) {
-                    safely_assign_to_array(a2, i, safely_read_array<T>(array, i));
+                    safe_write(a2, i, safe_read(array, i));
                 }
                 return a2;
             }
@@ -38,7 +32,7 @@ namespace Invercargill {
         public void add(T item) {
             lock(array) {
                 ensure_room(1);
-                safely_assign_to_array<T>(array, n_items, item);
+                safe_write(array, n_items, item);
                 n_items++;
             }
         }
@@ -53,7 +47,7 @@ namespace Invercargill {
                     e = new IndexError.INDEX_EXCEEDS_UPPER_BOUNDS(@"Tried to access index $(index) on a vector with $(n_items) item(s)");
                 }
                 else {
-                    return safely_read_array<T>(array, index);
+                    return safe_read(array, index);
                 }
             }
             throw e;
@@ -64,7 +58,7 @@ namespace Invercargill {
                 if(index < 0 || index >= n_items) {
                     return null;
                 }
-                return safely_read_array<T>(array, index);
+                return safe_read(array, index);
             }
         }
 
@@ -78,7 +72,7 @@ namespace Invercargill {
                     e = new IndexError.INDEX_EXCEEDS_UPPER_BOUNDS(@"Tried to set index $(index) on a vector with $(n_items) item(s)");
                 }
                 else {
-                    safely_assign_to_array<T>(array, index, value);
+                    safe_write(array, index, value);
                     return;
                 }
             }
@@ -123,7 +117,7 @@ namespace Invercargill {
                 else {
                     for(int i = index; i < n_items; i++) {
                         if(i+1 < n_items) {
-                            safely_assign_to_array<T>(array, i, safely_read_array<T>(array, i+1));
+                            safe_write(array, i, safe_read(array, i+1));
                             continue;
                         }
                         array[i] = null;
@@ -145,7 +139,7 @@ namespace Invercargill {
                     e = new SequenceError.NO_ELEMENTS("The sequence contains no elements");
                 }
                 else {
-                    return safely_read_array<T>(array, n_items -1);
+                    return safe_read(array, n_items -1);
                 }
             }
             throw e;
@@ -161,9 +155,43 @@ namespace Invercargill {
                     return null;
                 }
                 else {
-                    return safely_read_array<T>(array, n_items -1);
+                    return safe_read(array, n_items -1);
+                }
+            }
+        }
+
+        private class VectorTracker<T> : Tracker<T> {
+
+            private T? next_item = null;
+            private bool got_next = false;
+            private int index = 0;
+            private Vector<T> vector;
+
+            public VectorTracker(Vector<T> vec) {
+                vector = vec;
+            }
+
+            public override bool has_next() {
+                if(got_next) {
+                    return true;
+                }
+                try {
+                    next_item = vector.get(index);
+                    got_next = true;
+                    return true;
                 }
+                catch(IndexError e) {
+                    return false;
+                }
+            }
+            public override T get_next() {
+                var item = next_item;
+                next_item = null;
+                got_next = false;
+                index++;
+                return item;
             }
+
         }
     }
 

+ 154 - 0
src/lib/Safety.vala

@@ -1,6 +1,9 @@
 
 namespace Invercargill {
 
+    internal delegate T SafeReadFunc<T>(T[] array, int index);
+    internal delegate void SafeWriteFunc<T>(T[] array, int index, T value);
+
     internal T safely_read_array<T> (T[] array, int index) {
         var t = typeof (T);
         if (t == typeof (bool)) {
@@ -81,4 +84,155 @@ namespace Invercargill {
         }
     }
 
+
+    internal bool safely_read_bool_from_array(bool[] array, int index) {
+        return ((bool[])array)[index];
+    }
+    internal char safely_read_char_from_array(char[] array, int index) {
+        return ((char[])array)[index];
+    }
+    internal uchar safely_read_uchar_from_array(uchar[] array, int index) {
+        return ((uchar[])array)[index];
+    }
+    internal int safely_read_int_from_array(int[] array, int index) {
+        return ((int[])array)[index];
+    }
+    internal uint safely_read_uint_from_array(uint[] array, int index) {
+        return ((uint[])array)[index];
+    }
+    internal int64 safely_read_int64_from_array(int64[] array, int index) {
+        return ((int64[])array)[index];
+    }
+    internal uint64 safely_read_uint64_from_array(uint64[] array, int index) {
+        return ((uint64[])array)[index];
+    }
+    internal long safely_read_long_from_array(long[] array, int index) {
+        return ((long[])array)[index];
+    }
+    internal ulong safely_read_ulong_from_array(ulong[] array, int index) {
+        return ((ulong[])array)[index];
+    }
+    internal float safely_read_float_from_array(float[] array, int index) {
+        return ((float?[])array)[index];
+    }
+    internal double safely_read_double_from_array(double[] array, int index) {
+        return ((double?[])array)[index];
+    }
+    internal T read_from_array<T>(T[] array, int index) {
+        return array[index];
+    }
+
+    internal void safely_assign_bool_to_array(bool[] array, int index, bool value) {
+        ((bool[])array)[index] = (bool)value;
+    }
+    internal void safely_assign_char_to_array(char[] array, int index, char value) {
+        ((char[])array)[index] = (char) value;
+    }
+    internal void safely_assign_uchar_to_array(uchar[] array, int index, uchar value) {
+        ((uchar[])array)[index] = (uchar)value;
+    }
+    internal void safely_assign_int_to_array(int[] array, int index, int value) {
+        ((int[])array)[index] = (int)value;
+    }
+    internal void safely_assign_uint_to_array(uint[] array, int index, uint value) {
+        ((uint[])array)[index] = (uint)value;
+    }
+    internal void safely_assign_int64_to_array(int64[] array, int index, int64 value) {
+        ((int64[])array)[index] = (int64)value;
+    }
+    internal void safely_assign_uint64_to_array(uint64[] array, int index, uint64 value) {
+        ((uint64[])array)[index] = (uint64)value;
+    }
+    internal void safely_assign_long_to_array(long[] array, int index, long value) {
+        ((long[])array)[index] = (long)value;
+    }
+    internal void safely_assign_ulong_to_array(ulong[] array, int index, ulong value) {
+        ((ulong[])array)[index] = (ulong)value;
+    }
+    internal void safely_assign_float_to_array(float[] array, int index, float value) {
+        ((float?[])array)[index] = (float?)value;
+    }
+    internal void safely_assign_double_to_array(double[] array, int index, double value) {
+        ((double?[])array)[index] = (double?)value;
+    }
+    internal void assign_to_array<T>(T[] array, int index, T value) {
+        array[index] = value;
+    }
+
+    internal SafeReadFunc<T> get_safe_read_function_for<T>() {
+        var t = typeof (T);
+        if (t == typeof (bool)) {
+            return (SafeReadFunc<T>)safely_read_bool_from_array;
+        }
+        else if (t == typeof (char)) {
+            return (SafeReadFunc<T>)safely_read_char_from_array;
+        }
+        else if (t == typeof (uchar)) {
+            return (SafeReadFunc<T>)safely_read_uchar_from_array;
+        }
+        else if (t == typeof (int) || t.is_enum () || t.is_flags ()) {
+            return (SafeReadFunc<T>)safely_read_int_from_array;
+        }
+        else if (t == typeof (uint)) {
+            return (SafeReadFunc<T>)safely_read_uint_from_array;
+        }
+        else if (t == typeof (int64)) {
+            return (SafeReadFunc<T>)safely_read_int64_from_array;
+        }
+        else if (t == typeof (uint64)) {
+            return (SafeReadFunc<T>)safely_read_uint64_from_array;
+        }
+        else if (t == typeof (long)) {
+            return (SafeReadFunc<T>)safely_read_long_from_array;
+        }
+        else if (t == typeof (ulong)) {
+            return (SafeReadFunc<T>)safely_read_ulong_from_array;
+        }
+        else if (t == typeof (float)) {
+            return (SafeReadFunc<T>)safely_read_float_from_array;
+        }
+        else if (t == typeof (double)) {
+            return (SafeReadFunc<T>)safely_read_double_from_array;
+        }
+        return (SafeReadFunc<T>)read_from_array<T>;
+    }
+
+    internal SafeWriteFunc<T> get_safe_write_function_for<T>() {
+        var t = typeof (T);
+        if (t == typeof (bool)) {
+            return (SafeWriteFunc<T>)safely_assign_bool_to_array;
+        }
+        else if (t == typeof (char)) {
+            return (SafeWriteFunc<T>)safely_assign_char_to_array;
+        }
+        else if (t == typeof (uchar)) {
+            return (SafeWriteFunc<T>)safely_assign_uchar_to_array;
+        }
+        else if (t == typeof (int) || t.is_enum () || t.is_flags ()) {
+            return (SafeWriteFunc<T>)safely_assign_int_to_array;
+        }
+        else if (t == typeof (uint)) {
+            return (SafeWriteFunc<T>)safely_assign_uint_to_array;
+        }
+        else if (t == typeof (int64)) {
+            return (SafeWriteFunc<T>)safely_assign_int64_to_array;
+        }
+        else if (t == typeof (uint64)) {
+            return (SafeWriteFunc<T>)safely_assign_uint64_to_array;
+        }
+        else if (t == typeof (long)) {
+            return (SafeWriteFunc<T>)safely_assign_long_to_array;
+        }
+        else if (t == typeof (ulong)) {
+            return (SafeWriteFunc<T>)safely_assign_ulong_to_array;
+        }
+        else if (t == typeof (float)) {
+            return (SafeWriteFunc<T>)safely_assign_float_to_array;
+        }
+        else if (t == typeof (double)) {
+            return (SafeWriteFunc<T>)safely_assign_double_to_array;
+        }
+        return (SafeWriteFunc<T>)assign_to_array<T>;
+    }
+
 }

+ 6 - 0
src/tests/Speed/Fifo.vala

@@ -0,0 +1,6 @@
+using Invercargill;
+
+void fifo_speed_test() {
+    var fifo = new Fifo<int>();
+    speed_test_runner_int(fifo, i => fifo.push(i), i => { i.iterate(j => fifo.push(j)); fifo.complete(); });
+}

+ 6 - 0
src/tests/Speed/Series.vala

@@ -0,0 +1,6 @@
+using Invercargill;
+
+void series_speed_test() {
+    var series = new Series<int>();
+    speed_test_runner_int(series, i => series.add(i), i => series.add_all(i));
+}

+ 73 - 0
src/tests/Speed/SpeedTest.vala

@@ -0,0 +1,73 @@
+
+using Invercargill;
+
+delegate void AddDelegate<T>(T item);
+delegate void BulkAddDelegate<T>(Invercargill.Enumerable<T> items);
+
+void speed_test_runner_int(Enumerable<int> e, AddDelegate<int> add, BulkAddDelegate<int> bulk) {
+    print(@"\nSpeed test for $(e.get_type().name()):\n");
+
+    int individual_writes = 10000000;
+    run_speed_test(@"$individual_writes individual writes", () => {
+        for(int i = 0; i < individual_writes; i++) {
+            add(i);
+        }
+    });
+
+
+    int bulk_writes = 10000;
+    int batch_size = 1000;
+    run_speed_test(@"$bulk_writes bulk writes of $batch_size items", () => {
+        for(int i = 0; i < bulk_writes; i++) {
+            bulk(range(0, batch_size));
+        }
+    });
+
+
+    //  timer.reset();
+    //  timer.start();
+    //  var count = e.count();
+    //  timer.stop();
+    //  print(@"\tGot count of items in enumerable ($count) in $(timer.elapsed()) seconds\n");
+    int individual_reads = 10000000;
+    run_speed_test(@"Iterate over first $individual_reads items", () => {
+        var count = 0;
+        var last = 0;
+        foreach (var item in e.take(individual_reads)) {
+            count++;
+            last = item;
+        }
+    });
+
+    if(e.get_type() == typeof(Fifo)) {
+        print("\tSkipping remaining tests for Fifo.\n");
+        return;
+    }
+    
+    run_speed_test(@"Iterate over all items", () => {
+        var count = 0;
+        var last = 0;
+        foreach (var item in e) {
+            count++;
+            last = item;
+        }
+    });
+}
+
+delegate void SpeedTestFunc();
+void run_speed_test(string label, SpeedTestFunc func) {
+    print(@"\n\tRunning $label\n");
+    var times = 0.0;
+    for(int i = 0; i < 5; i++) {
+        var timer = new Timer();
+        timer.start();
+        func();
+        timer.stop();
+        var time = timer.elapsed();
+        times += time;
+        print(@"\t\tFinished run $(i+1)/5 of $label in $(time) seconds\n");
+
+    }
+
+    print(@"\tAverage: $(times/5) seconds\n");
+}

+ 6 - 0
src/tests/Speed/Vector.vala

@@ -0,0 +1,6 @@
+using Invercargill;
+
+void vector_speed_test() {
+    var vec = new Vector<int>();
+    speed_test_runner_int(vec, i => vec.add(i), i => vec.add_all(i));
+}

+ 4 - 0
src/tests/TestRunner.vala

@@ -18,5 +18,9 @@ public static int main(string[] args) {
 
     Test.run();
 
+    series_speed_test();
+    vector_speed_test();
+    fifo_speed_test();
+
     return 0;
 }

+ 6 - 1
src/tests/meson.build

@@ -15,4 +15,9 @@ sources += files('Integration/Vector.vala')
 sources += files('Integration/Series.vala')
 sources += files('Integration/Arrays.vala')
 
-executable('invercargill-test-suite', sources, dependencies: dependencies, install: true)
+sources += files('Speed/SpeedTest.vala')
+sources += files('Speed/Series.vala')
+sources += files('Speed/Vector.vala')
+sources += files('Speed/Fifo.vala')
+
+executable('invercargill-test-suite', sources, dependencies: dependencies, install: true)