private static int[] CreateOrderByInput(int dataSize, DataDistributionType type) { int[] data = new int[dataSize]; switch (type) { case DataDistributionType.AlreadyAscending: for (int i = 0; i < data.Length; i++) { data[i] = i; } break; case DataDistributionType.AlreadyDescending: for (int i = 0; i < data.Length; i++) { data[i] = dataSize - i; } break; case DataDistributionType.Random: //Random rand = new Random(); for (int i = 0; i < data.Length; i++) { data[i] = ValueHelper.Next(); } break; } return(data); }
//----------------------------------------------------------------------------------- // Exercises basic OrderBy behavior by sorting a fixed set of integers. This always // uses asynchronous channels internally, i.e. by pipelining. // private static void RunOrderByTest2Core(int dataSize, bool descending, DataDistributionType type) { int[] data = CreateOrderByInput(dataSize, type); ParallelQuery <int> q; if (descending) { q = data.AsParallel().OrderByDescending <int, int>( delegate(int x) { return(x); }); } else { q = data.AsParallel().OrderBy <int, int>( delegate(int x) { return(x); }); } int prev = descending ? int.MaxValue : int.MinValue; foreach (int x in q) { if (descending ? x > prev : x < prev) { string method = string.Format("RunOrderByTest2(dataSize = {0}, descending = {1}, type = {2}) - asynchronous/pipeline:", dataSize, descending, type); Assert.True(false, string.Format(method + " > **ERROR** {0} came before {1} -- but isn't what we expected", prev, x));; } prev = x; } }
//----------------------------------------------------------------------------------- // Exercises basic OrderBy behavior by sorting a fixed set of integers. They are fed // in already ascending, already descending, and random order for 3 variants. // private static bool RunOrderByTest1(int dataSize, bool descending, DataDistributionType type, int loops) { TestHarness.TestLog("RunOrderByTest1(dataSize = {0}, descending = {1}, type = {2})", dataSize, descending, type); int[] data = CreateOrderByInput(dataSize, type); IEnumerable <int> seqQuery; ParallelQuery <int> parQuery; if (descending) { seqQuery = Enumerable.OrderByDescending <int, int>(data, delegate(int x) { return(x); }, System.Linq.Parallel.Util.GetDefaultComparer <int>()); parQuery = data.AsParallel <int>().OrderByDescending <int, int>( delegate(int x) { return(x); }, System.Linq.Parallel.Util.GetDefaultComparer <int>()); } else { seqQuery = Enumerable.OrderBy <int, int>(data, delegate(int x) { return(x); }, System.Linq.Parallel.Util.GetDefaultComparer <int>()); parQuery = data.AsParallel <int>().OrderBy <int, int>( delegate(int x) { return(x); }, System.Linq.Parallel.Util.GetDefaultComparer <int>()); } PerfHelpers.DrivePerfComparison( delegate { List <int> r = Enumerable.ToList <int>(seqQuery); }, delegate { List <int> r = parQuery.ToList <int>(); }, loops); return(true); }
//----------------------------------------------------------------------------------- // Exercises basic OrderBy behavior by sorting a fixed set of integers. This always // uses synchronous channels internally, i.e. by not pipelining. // private static void RunOrderByTest1Core(int dataSize, bool descending, DataDistributionType type) { int[] data = CreateOrderByInput(dataSize, type); ParallelQuery <int> q; if (descending) { q = data.AsParallel().OrderByDescending <int, int>( delegate(int x) { return(x); }); } else { q = data.AsParallel().OrderBy <int, int>( delegate(int x) { return(x); }); } // Force synchronous execution before validating results. List <int> r = q.ToList <int>(); int prev = descending ? int.MaxValue : int.MinValue; for (int i = 0; i < r.Count; i++) { int x = r[i]; if (descending ? x > prev : x < prev) { string method = string.Format("RunOrderByTest1(dataSize = {0}, descending = {1}, type = {2}) - synchronous/no pipeline:", dataSize, descending, type); Assert.True(false, string.Format(method + " > **ERROR** {0} came before {1} -- but isn't what we expected", prev, x)); } prev = x; } }
//----------------------------------------------------------------------------------- // Nested sorts. // private static void RunOrderByComposedWithOrderBy(int dataSize, bool descending, DataDistributionType type) { int[] data = CreateOrderByInput(dataSize, type); ParallelQuery <int> q; // Create the ORDERBY: if (!descending) { q = data.AsParallel().OrderByDescending <int, int>( delegate(int x) { return(x); }); } else { q = data.AsParallel().OrderBy <int, int>( delegate(int x) { return(x); }); } // Wrap with a WHERE: q = q.Where <int>(delegate(int x) { return((x % 2) == 0); }); // And wrap with another ORDERBY: if (descending) { q = q.OrderByDescending <int, int>(delegate(int x) { return(x); }); } else { q = q.OrderBy <int, int>(delegate(int x) { return(x); }); } // Force synchronous execution before validating results. List <int> results = q.ToList <int>(); int prev = descending ? int.MaxValue : int.MinValue; for (int i = 0; i < results.Count; i++) { int x = results[i]; if (descending ? x > prev : x < prev) { string method = string.Format("RunOrderByComposedWithOrderBy(dataSize = {0}, descending = {1}, type = {2}) - sequential/no pipeline", dataSize, descending, type); Assert.True(false, string.Format(method + " > **ERROR** {0} came before {1} -- but isn't what we expected", prev, x)); } prev = x; } }
//----------------------------------------------------------------------------------- // If sort is followed by another operator, we need to preserve key ordering all the // way back up to the merge. That is true even if some elements are missing in the // output data stream. This test tries to compose ORDERBY with WHERE and SELECT. // This test processes output sequentially (not pipelined). // // This is particularly interesting because the SELECT completely loses the original // type information in the tree, yet the merge is able to put things back in order. // private static void RunOrderByComposedWithWhereSelect1(int dataSize, bool descending, DataDistributionType type) { int[] data = CreateOrderByInput(dataSize, type); ParallelQuery <int> q0; // Create the ORDERBY: if (descending) { q0 = data.AsParallel().OrderByDescending <int, int>( delegate(int x) { return(x); }); } else { q0 = data.AsParallel().OrderBy <int, int>( delegate(int x) { return(x); }); } // Wrap with a WHERE: q0 = q0.Where <int>(delegate(int x) { return((x % 2) == 0); }); // Wrap with a SELECT: ParallelQuery <string> q1 = q0.Select <int, string>(delegate(int x) { return(x.ToString()); }); // Force synchronous execution before validating results. List <string> results = q1.ToList <string>(); int prev = descending ? int.MaxValue : int.MinValue; foreach (string xs in results) { int x = int.Parse(xs); if (descending ? x > prev : x < prev) { string method = string.Format("RunOrderByComposedWithWhereSelect1(dataSize = {0}, descending = {1}, type = {2}) - sequential/no pipeline", dataSize, descending, type); Assert.True(false, string.Format(method + " > **ERROR** {0} came before {1} -- but isn't what we expected", prev, x)); } prev = x; } }
private static void RunOrderByComposedWithJoinJoin(int outerSize, int innerSize, bool descending) { // Generate data in the reverse order in which it'll be sorted. DataDistributionType type = descending ? DataDistributionType.AlreadyAscending : DataDistributionType.AlreadyDescending; int[] left = CreateOrderByInput(outerSize, type); int[] right = CreateOrderByInput(innerSize, type); int min = outerSize >= innerSize ? innerSize : outerSize; int[] middle = new int[min]; if (descending) { for (int i = middle.Length; i > 0; i--) { middle[i - 1] = i; } } else { for (int i = 0; i < middle.Length; i++) { middle[i] = i; } } Func <int, int> identityKeySelector = delegate(int x) { return(x); }; // Create the sort object. ParallelQuery <int> sortedLeft; if (descending) { sortedLeft = left.AsParallel().OrderByDescending <int, int>(identityKeySelector); } else { sortedLeft = left.AsParallel().OrderBy <int, int>(identityKeySelector); } // and now the join... ParallelQuery <Pair <int, int> > innerJoin = sortedLeft.Join <int, int, int, Pair <int, int> >( right.AsParallel(), identityKeySelector, identityKeySelector, delegate(int x, int y) { return(new Pair <int, int>(x, y)); }); ParallelQuery <int> outerJoin = innerJoin.Join <Pair <int, int>, int, int, int>( middle.AsParallel(), delegate(Pair <int, int> p) { return(p.First); }, identityKeySelector, delegate(Pair <int, int> x, int y) { return(x.First); }); // Ensure pairs are of equal values, and that they are in ascending or descending order. int cnt = 0; int? last = null; string method = string.Format("RunOrderByComposedWithJoinJoin(outerSize = {0}, innerSize = {1}, descending = {2})", outerSize, innerSize, descending); foreach (int p in outerJoin) { cnt++; if (!((last == null || ((last.Value <= p && !descending) || (last.Value >= p && descending))))) { Assert.True(false, string.Format(method + " > *ERROR: sort order not correct: last = {0}, curr = {1}", last.Value, p)); } last = p; } }
//----------------------------------------------------------------------------------- // If sort is followed by another operator, we need to preserve key ordering all the // way back up to the merge. That is true even if some elements are missing in the // output data stream. This test tries to compose ORDERBY with WHERE. This test // processes output asynchronously via pipelining. // private static void RunOrderByComposedWithWhere2(int dataSize, bool descending, DataDistributionType type) { int[] data = CreateOrderByInput(dataSize, type); ParallelQuery <int> q; // Create the ORDERBY: if (descending) { q = data.AsParallel().OrderByDescending <int, int>( delegate(int x) { return(x); }); } else { q = data.AsParallel().OrderBy <int, int>( delegate(int x) { return(x); }); } // Wrap with a WHERE: q = q.Where <int>(delegate(int x) { return((x % 2) == 0); }); int prev = descending ? int.MaxValue : int.MinValue; foreach (int x in q) { if (descending ? x > prev : x < prev) { string method = string.Format("RunOrderByComposedWithWhere2(dataSize = {0}, descending = {1}, type = {2}) - async/pipeline", dataSize, descending, type); Assert.True(false, string.Format(method + " > **ERROR** {0} came before {1} -- but isn't what we expected", prev, x)); } prev = x; } }
private static void RunThenByComposedWithJoinJoin(int outerSize, int innerSize, bool descending) { // Generate data in the reverse order in which it'll be sorted. DataDistributionType type = descending ? DataDistributionType.AlreadyAscending : DataDistributionType.AlreadyDescending; int[] leftPartOne = CreateOrderByInput(outerSize, type); int[] leftPartTwo = CreateOrderByInput(outerSize, DataDistributionType.Random); Pair <int, int>[] left = new Pair <int, int> [outerSize]; for (int i = 0; i < outerSize; i++) { left[i] = new Pair <int, int>(leftPartOne[i] / 1024, leftPartTwo[i]); } int[] right = CreateOrderByInput(innerSize, type); int minValue = outerSize >= innerSize ? innerSize : outerSize; int[] middle = new int[minValue]; if (descending) { for (int i = middle.Length; i > 0; i--) { middle[i - 1] = i; } } else { for (int i = 0; i < middle.Length; i++) { middle[i] = i; } } Func <int, int> identityKeySelector = delegate(int x) { return(x); }; // Create the sort object. ParallelQuery <Pair <int, int> > sortedLeft; if (descending) { sortedLeft = left.AsParallel() .OrderByDescending <Pair <int, int>, int>(delegate(Pair <int, int> p) { return(p.First); }) .ThenByDescending <Pair <int, int>, int>(delegate(Pair <int, int> p) { return(p.Second); }); } else { sortedLeft = left.AsParallel() .OrderBy <Pair <int, int>, int>(delegate(Pair <int, int> p) { return(p.First); }) .ThenBy <Pair <int, int>, int>(delegate(Pair <int, int> p) { return(p.Second); }); } // and now the join... ParallelQuery <Pair <int, int> > innerJoin = sortedLeft.Join <Pair <int, int>, int, int, Pair <int, int> >( right.AsParallel(), delegate(Pair <int, int> p) { return(p.First); }, identityKeySelector, delegate(Pair <int, int> x, int y) { return(x); }); ParallelQuery <Pair <int, int> > outerJoin = innerJoin.Join <Pair <int, int>, int, int, Pair <int, int> >( middle.AsParallel(), delegate(Pair <int, int> p) { return(p.First); }, identityKeySelector, delegate(Pair <int, int> x, int y) { return(x); }); //Assert.True(false, string.Format(" > Invoking join of {0} outer elems with {1} inner elems", left.Length, right.Length)); // Ensure pairs are of equal values, and that they are in ascending or descending order. int cnt = 0, secondaryCnt = 0; Pair <int, int>?last = null; string methodName = string.Format("RunThenByComposedWithJoinJoin(outerSize = {0}, innerSize = {1}, descending = {2})", outerSize, innerSize, descending); foreach (Pair <int, int> p in outerJoin) { cnt++; if (!((last == null || ((last.Value.First <= p.First && !descending) || (last.Value.First >= p.First && descending))))) { Assert.True(false, string.Format(methodName + " > *ERROR: outer sort order not correct: last = {0}, curr = {1}", last.Value.First, p.First)); break; } if (last != null && last.Value.First == p.First) { secondaryCnt++; } if (!((last == null || (last.Value.First != p.First) || ((last.Value.Second <= p.Second && !descending) || (last.Value.Second >= p.Second && descending))))) { Assert.True(false, string.Format(methodName + " > *ERROR: inner sort order not correct: last = {0}, curr = {1}", last.Value.Second, p.Second)); } last = p; } }