public static void DemoOutVsReturn()
        {
            Benchmarker.Benchmark(() =>
            {
                StopwatchWrapper.Time(() =>
                {
                }, out var sw1);
            }, "Out parameter", _count);

            Benchmarker.Benchmark(() =>
            {
                var sw2 = StopwatchWrapper.Time(() =>
                {
                });
            }, "Return", _count);

            Console.WriteLine();
        }
Exemple #2
0
        public static void InjectingTestScheduler_AndManipulatingVirtualTime_HappensInstantly()
        {
            Benchmarker.Benchmark(() =>
            {
                var expectedValues = new long[] { 0, 1, 2, 3, 4 };
                var actualValues   = new List <long>();
                var scheduler      = new TestScheduler();

                var subscription = Observable
                                   .Interval(TimeSpan.FromSeconds(1), scheduler)
                                   .Take(5)
                                   .Subscribe(actualValues.Add);
                scheduler.Start();

                CollectionAssert.AreEqual(expectedValues, actualValues);
                Console.WriteLine("Collection was as expected.");
            });
        }
        public static void Count()
        {
            List <int> list = DataGenerator.GetRandomIntArray(10).ToList();
            int        c    = 0;

            Benchmarker.Benchmark(() =>
            {
                //With extension method (the wrong way):
                c = list.Count();
            }, "Using extension method Count()", _count);

            Benchmarker.Benchmark(() =>
            {
                //TODO 1.10: With property (the right way):
                c = list.Count();
            }, "Using property Count", _count);

            Console.WriteLine();
        }
        public static void ExecuteSubstringVsAppendOverload(string s)
        {
            var builder = new StringBuilder();

            Benchmarker.Benchmark(() =>
            {
                builder.Clear();
                string temp = s.Substring(5, 5);
                builder.Append(temp);
            }, "Substring append", _count);

            Benchmarker.Benchmark(() =>
            {
                builder.Clear();
                //TODO 1.2: use append overload
                builder.Append(s);
            }, "Append overload", _count);

            Console.WriteLine();
        }
Exemple #5
0
        public static void DemoLookupTableToLower()
        {
            string _lookupStringL = "--------------------------------------&-()*+,-./----------:;<=>?@abcdefghijklmnopqrstuvwxyz[-]^_`abcdefghijklmnopqrstuvwxyz{|}~-";
            char   y = 'Y';
            char   result;

            Benchmarker.Benchmark(() =>
            {
                result = char.ToLower(y);
            }, "Char.ToLower()", _count);

            Benchmarker.Benchmark(() =>
            {
                result = _lookupStringL[y];
            }, "Char to lower with lookup table", _count);

            Console.WriteLine();

            //A lookup table is a lot faster than the regular ToLower(), but using this alternative could cause localization issues
        }
Exemple #6
0
        public static void DemoMemoization()
        {
            List <string> s      = DataGenerator.GetRandomStringArray(10).ToList();
            string        result = string.Empty;
            Dictionary <string, string> _upperCaseTempDictionary = new Dictionary <string, string>();

            Benchmarker.Benchmark(() =>
            {
                foreach (var item in s)
                {
                    result = item.ToUpper();
                }
            }, "ToUpper()", _count);

            Benchmarker.Benchmark(() =>
            {
                foreach (var item in s)
                {
                    if (_upperCaseTempDictionary.TryGetValue(item, out string lookupValue))
                    {
                        result = lookupValue;
                        continue;
                    }
                    lookupValue = item.ToUpper();
                    _upperCaseTempDictionary[item] = lookupValue;
                }
            }, "ToUpper() with lookup dictionary (memoization)", _count);

            /*
             * Memoization is a way of caching used to optimize a function.
             * Known results are stored in memory, so the computation only runs once
             *
             * NOTE: the heavier a computation, the more useful this gets.
             * Don't forget that Dictionaries will become slower as they increase in size!
             * The following example would cause a performance hit when using a very big stringarray
             *
             * Alternative: inject IMemoryCache
             */

            Console.WriteLine();
        }
        public static void DemoRecursiveInline()
        {
            Benchmarker.Benchmark(() =>
            {
                List<int> list = new List<int>();
                ExecuteRecursiveMethod(list, 0);
            }, "Recursive", _count);

            Benchmarker.Benchmark(() =>
            {
                List<int> list = new List<int>();
                if (list.Count < 10)
                {
                    list.Add(0);
                    ExecuteRecursiveMethod(list, 0 + 1);
                }
            }, "Recursive inline", _count);

            Console.WriteLine();
            //Summary: deeper call stack = less performant
        }
Exemple #8
0
        public static void DemoJaggedTemporalLocality()
        {
            int height      = 50;
            int width       = 50;
            var jaggedArray = DataGenerator.GetJaggedArray(height, width);
            int result;

            Benchmarker.Benchmark(() =>
            {
                for (int i = 0; i < height; i++)
                {
                    for (int j = 0; j < width; j++)
                    {
                        result = jaggedArray[j][i];
                    }
                }
            }, "Low temporal locality", _count);

            Benchmarker.Benchmark(() =>
            {
                for (int i = 0; i < height; i++)
                {
                    for (int j = 0; j < width; j++)
                    {
                        result = jaggedArray[i][j];
                    }
                }
            }, "High temporal locality", _count);

            Console.WriteLine();

            /*
             * https://stackoverflow.com/questions/763262/how-does-one-write-code-that-best-utilizes-the-cpu-cache-to-improve-performance
             * The reason this is cache inefficient is because modern CPUs will load the cache line with "near" memory addresses
             * from main memory when you access a single memory address.
             * We are iterating through the "j"(outer) rows in the array in the inner loop,
             * so for each trip through the inner loop,
             * the cache line will cause to be flushed and loaded with a line of addresses that are near to the[j][i] entry
             */
        }
        public static void DetermineStringBuilderPerformanceVsConcat(string s, int cnt)
        {
            var capacity = cnt * s.Length;

            Console.WriteLine("String count: " + cnt);

            Benchmarker.Benchmark(() =>
            {
                var str = string.Empty;
                for (int i = 1; i < cnt; i++)
                {
                    str += s;
                }
            }, "String Concatenation", 1, cnt);

            Benchmarker.Benchmark(() =>
            {
                var builder = new StringBuilder();
                for (int i = 1; i < cnt; i++)
                {
                    builder.Append(s);
                }
                var str = builder.ToString();
            }, "Default StringBuilder", 1, cnt);

            Benchmarker.Benchmark(() =>
            {
                //TODO 1.1: add stringbuilder capacity
                var builder = new StringBuilder();
                for (int i = 1; i < cnt; i++)
                {
                    builder.Append(s);
                }
                var str = builder.ToString();
            }, "StringBuilder with fixed capacity", 1, cnt);

            Console.WriteLine();
        }
        public static void ShowStringBuilderConcatenationPerformance()
        {
            string[] stringArray = DataGenerator.GetRandomStringArray(5);

            Benchmarker.Benchmark(() =>
            {
                StringBuilder builder = _builder;
                builder.Clear();
                foreach (string value in stringArray)
                {
                    builder.Append($"ABC {_count}"
                                   + "DEF"
                                   + string.Concat("GHI", "XYZ")
                                   + value);
                }
                var str = builder.ToString();
            }, "With concats in append", _count);

            string a = string.Empty;

            Benchmarker.Benchmark(() =>
            {
                StringBuilder builder = _builder;
                builder.Clear();
                foreach (string value in stringArray)
                {
                    a = $"ABC {_count}"
                        + "DEF"
                        + string.Concat("GHI", "XYZ")
                        + value;
                    builder.Append(a);
                }
                var str = builder.ToString();
            }, "Without concats in appends", _count);

            Console.WriteLine();
        }
Exemple #11
0
        public static void DemoTryGetValueVsContainsKey()
        {
            var counts = new Dictionary <string, int> {
                { "key", DataGenerator.GetRandomInt() }
            };
            int result;

            Benchmarker.Benchmark(() =>
            {
                if (counts.ContainsKey("key"))
                {
                    result = counts["key"];
                }
            }, "ContainsKey()", _count);

            Benchmarker.Benchmark(() =>
            {
                if (counts.TryGetValue("key", out result))
                {
                }
            }, "TryGetValue()", _count);

            //Summary: use TryGetValue over ContainsKey, since ContainsKey causes an unnecessary lookup
        }
Exemple #12
0
        public static void DemoJaggedArray()
        {
            int width  = 50;
            int height = 50;
            int result;

            // 2D array.
            Benchmarker.Benchmark(() =>
            {
                DataGenerator.Get2DArray(height, width);
            }, "2D array creation", _count);


            // Jagged array.
            Benchmarker.Benchmark(() =>
            {
                DataGenerator.GetJaggedArray(height, width);
            }, "Jagged array creation", _count);

            var twoDimensionalArray = DataGenerator.Get2DArray(height, width);
            var jaggedArray         = DataGenerator.GetJaggedArray(height, width);

            // 2D array.
            Benchmarker.Benchmark(() =>
            {
                for (int j = 0; j < height; j++)
                {
                    for (int a = 0; a < width; a++)
                    {
                        result = twoDimensionalArray[j, a];
                    }
                }
            }, "2D array element access", _count);

            // Jagged array.
            Benchmarker.Benchmark(() =>
            {
                for (int j = 0; j < height; j++)
                {
                    for (int a = 0; a < width; a++)
                    {
                        result = jaggedArray[a][j];
                    }
                }
            }, "Jagged array element access with low temporal locality", _count);

            // Jagged array.
            Benchmarker.Benchmark(() =>
            {
                for (int j = 0; j < height; j++)
                {
                    for (int a = 0; a < width; a++)
                    {
                        result = jaggedArray[j][a];
                    }
                }
            }, "Jagged array element access with high temporal locality", _count);

            /*
             * Summary: 2D arrays are faster to allocate, but a lot slower to access than jagged arrays.
             * Since element access count is usually a lot greater than array allocation count (1),
             * using jagged arrays should still result in faster code, but be careful with memory usage
             *
             * Jagged array allocation slowdown explained:
             *  - 2D array only needs 1 allocation
             *  - Jagged array needs length * width + 1 allocations
             *  => this means garbage collection will have to do a lot more work when using jagged arrays
             *
             *  Jagged array element access with imperformant index ordering => See DemoJaggedTemporalLocality explanation
             *
             * NOTE: jagged arrays don't necessarily have to be allocated at the start, u could do this lazily!
             *
             */
            Console.WriteLine();
        }
Exemple #13
0
        public static void DemoArrayFlattening()
        {
            var height = DataGenerator.GetRandomInt(5, 5);
            var width  = DataGenerator.GetRandomInt(5, 5);
            int result;

            int[,] twoDimensional = new int[height, width];
            int[] oneDimensional = new int[width * height];

            //2D

            //Assign values
            twoDimensional[0, 1] = 4;
            twoDimensional[1, 2] = 5;
            twoDimensional[2, 3] = 6;
            twoDimensional[3, 4] = 7;

            //Display array
            for (int i = 0; i < height; i++)
            {
                for (int a = 0; a < width; a++)
                {
                    Console.Write(twoDimensional[i, a]);
                }
                Console.WriteLine();
            }
            Console.WriteLine();

            //1D

            //Assign values
            oneDimensional[1]             = 4;
            oneDimensional[1 * width + 2] = 5;
            oneDimensional[2 * width + 3] = 6;
            oneDimensional[3 * width + 4] = 7;

            //Display array
            for (int i = 0; i < height; i++)
            {
                for (int a = 0; a < width; a++)
                {
                    Console.Write(oneDimensional[i * width + a]);
                }
                Console.WriteLine();
            }
            Console.WriteLine();


            Benchmarker.Benchmark(() =>
            {
                twoDimensional[0, 1] = 4;
                twoDimensional[1, 2] = 5;
                twoDimensional[2, 3] = 6;
                twoDimensional[3, 4] = 7;

                for (int j = 0; j < height; j++)
                {
                    for (int a = 0; a < width; a++)
                    {
                        result = twoDimensional[j, a];
                    }
                }
            }, "2D array (assign & read)", _count);

            Benchmarker.Benchmark(() =>
            {
                oneDimensional[1]             = 4;
                oneDimensional[1 * width + 2] = 5;
                oneDimensional[2 * width + 3] = 6;
                oneDimensional[3 * width + 4] = 7;

                for (int j = 0; j < height; j++)
                {
                    for (int a = 0; a < width; a++)
                    {
                        result = oneDimensional[j * width + a];
                    }
                }
            }, "1D array (assign & read)", _count);

            Console.WriteLine();
        }
        public static void CompareDataTypes()
        {
            const int nrOfAppends = 100;

            Console.WriteLine("Int vs. char: ");

            Benchmarker.Benchmark(() =>
            {
                StringBuilder s = new StringBuilder(1000);
                for (int v = 0; v < nrOfAppends; v++)
                {
                    s.Append(1);
                }
            }, "Int", _count, _count * nrOfAppends);

            Benchmarker.Benchmark(() =>
            {
                StringBuilder s = new StringBuilder(1000);
                for (int v = 0; v < nrOfAppends; v++)
                {
                    s.Append('1');
                }
            }, "Char", _count, _count * nrOfAppends);

            //Char is faster (string is an array of chars)

            Console.WriteLine();

            Console.WriteLine("Bool vs. string: ");

            Benchmarker.Benchmark(() =>
            {
                StringBuilder s = new StringBuilder(4000);
                for (int v = 0; v < nrOfAppends; v++)
                {
                    s.Append(true);
                }
            }, "Bool", _count, _count * nrOfAppends);

            Benchmarker.Benchmark(() =>
            {
                StringBuilder s = new StringBuilder(4000);
                for (int v = 0; v < nrOfAppends; v++)
                {
                    s.Append("True");
                }
            }, "String", _count, _count * nrOfAppends);

            //String is faster (bool is a value type, and has to be converted to a string, which is a reference type
            //=> boxing occurs => performance hit)

            Console.WriteLine();

            Console.WriteLine("String vs. char: ");

            Benchmarker.Benchmark(() =>
            {
                StringBuilder s = new StringBuilder(1000);
                for (int v = 0; v < nrOfAppends; v++)
                {
                    s.Append("a");
                }
            }, "String", _count, _count * nrOfAppends);

            Benchmarker.Benchmark(() =>
            {
                StringBuilder s = new StringBuilder(1000);
                for (int v = 0; v < nrOfAppends; v++)
                {
                    s.Append('a');
                }
            }, "Char", _count, _count * nrOfAppends);

            //Char is faster (string is a char array + char is a value type and string is a reference type)
            Console.WriteLine();
        }
        public static void DemoClassVsStruct()
        {
            string str = DataGenerator.GetRandomString();
            int    i   = DataGenerator.GetRandomInt();

            Console.WriteLine("Initialization:");

            Benchmarker.Benchmark(() =>
            {
                var a = new SomeClassWithStrings
                {
                    A = str
                };
            }, "Class with string", _count);

            Benchmarker.Benchmark(() =>
            {
                SomeStructWithStrings a = new SomeStructWithStrings
                {
                    A = str
                };
            }, "Struct with string", _count);

            Benchmarker.Benchmark(() =>
            {
                var a = new SomeClassWithInts
                {
                    A = i
                };
            }, "Class with int", _count);

            Benchmarker.Benchmark(() =>
            {
                SomeStructWithInts a = new SomeStructWithInts
                {
                    A = i
                };
            }, "Struct with int", _count);

            Console.WriteLine();


            Console.WriteLine("As a method parameter:");

            var pair1 = new KeyValuePair <string, SomeClassWithStrings>("key", new SomeClassWithStrings());
            var pair2 = new KeyValuePair <string, SomeStructWithStrings>("key", new SomeStructWithStrings());

            Benchmarker.Benchmark(() =>
            {
                var a = pair2.Value;
            }, "Struct as parameter", _count);

            Benchmarker.Benchmark(() =>
            {
                var a = pair1.Value;
            }, "Class as parameter", _count);

            /*
             * Summary: Allocating structs is generally faster than allocating classes,
             * however it's not recommended to use structs with a lot of fields,
             * since the struct and all of it's fields will be copied onto the function stack when using structs as a parameter
             */
        }
Exemple #16
0
        public static void DemoCommonSenseIfOrdering()
        {
            int count          = 9999;
            int amountOfDigits = 0;

            Benchmarker.Benchmark(() =>
            {
                for (int c = 0; c < count; c++)
                {
                    if (c < 10)
                    {
                        amountOfDigits = 1;
                    }
                    else if (c < 100)
                    {
                        amountOfDigits = 2;
                    }
                    else if (c < 1000)
                    {
                        amountOfDigits = 3;
                    }
                    else
                    {
                        amountOfDigits = 4;
                    }
                }
            }, "Regular if");

            Benchmarker.Benchmark(() =>
            {
                for (int c = 0; c < count; c++)
                {
                    //TODO 1.27: reorder if statement so amountOfDigits = 4 is in the first if statement
                    if (c < 10)
                    {
                        amountOfDigits = 1;
                    }
                    else if (c < 100)
                    {
                        amountOfDigits = 2;
                    }
                    else if (c < 1000)
                    {
                        amountOfDigits = 3;
                    }
                    else
                    {
                        amountOfDigits = 4;
                    }
                }
            }, "Reordered if");

            Console.WriteLine();

            /*
             * Summary:
             * Since our count is 9999, the else statement in the 1st example would result true more frequently than the other cases
             * In the 2nd example, our first if statement will evaluate to true the most (9000 of our 9999 items are greater than 999)
             * Reordening if statements so more frequent cases are at the top op the if-else statement improves performance, since less
             * if statements have to be evaluated.
             */
        }
Exemple #17
0
        public static void DemoIfVsSwitch()
        {
            int testValue1 = 100;

            Benchmarker.Benchmark(() =>
            {
                if (testValue1 == 0)
                {
                }
                else if (testValue1 == 1)
                {
                }
                else if (testValue1 == 2)
                {
                }
                else if (testValue1 == 3)
                {
                }
                else if (testValue1 == 4)
                {
                }
                else if (testValue1 == 5)
                {
                }
                else if (testValue1 == 6)
                {
                }
                else
                {
                }
            }, "If-else chain of 7 statements", _count);

            Benchmarker.Benchmark(() =>
            {
                switch (testValue1)
                {
                case 0:
                    break;

                case 1:
                    break;

                case 2:
                    break;

                case 3:
                    break;

                case 4:
                    break;

                case 5:
                    break;

                case 6:
                    break;

                default:
                    break;
                }
            }, "Switch 7 cases", _count);

            Benchmarker.Benchmark(() =>
            {
                switch (testValue1)
                {
                case 0:
                    break;

                case 1:
                    break;

                default:
                    break;
                }
            }, "Switch 3 cases", _count);

            Benchmarker.Benchmark(() =>
            {
                if (testValue1 == 0)
                {
                }
                else if (testValue1 == 1)
                {
                }
                else
                {
                }
            }, "If-else chain of 3 statements", _count);

            Console.WriteLine();

            /*
             * Summary:Switch statements are recommended for 7 cases & more
             * However, if the input is almost always a specific value, then using an if-statement to test for that value may be faster.
             */
        }