Skip to content

Commit

Permalink
Merge pull request #120 from computablee/bug-fixes
Browse files Browse the repository at this point in the history
Add error checking to ForCollapse
  • Loading branch information
computablee authored Nov 21, 2023
2 parents b5b6921 + 7ed086a commit 32ecdc2
Show file tree
Hide file tree
Showing 4 changed files with 80 additions and 5 deletions.
22 changes: 22 additions & 0 deletions DotMP-Tests/ParallelTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1451,6 +1451,18 @@ public void Absent_params_shouldnt_except()
Assert.Null(exception);
}

/// <summary>
/// Verifies that for loops which overflow internal indices should throw an exception.
/// </summary>
[Fact]
public void Overflow_for_should_except()
{
Assert.Throws<DotMP.Exceptions.TooManyIterationsException>(() =>
{
DotMP.Parallel.ParallelForCollapse((0, 256), (0, 256), (0, 256), (0, 256), (i, j, k, l) => { });
});
}

/// <summary>
/// Verifies that invalid parameters throw exceptions.
/// </summary>
Expand All @@ -1467,6 +1479,16 @@ public void Invalid_params_should_except()
DotMP.Parallel.ParallelFor(-1, 10, i => { });
});

Assert.Throws<DotMP.Exceptions.InvalidArgumentsException>(() =>
{
DotMP.Parallel.ParallelForCollapse((10, 20), (-1, 10), (i, j) => { });
});

Assert.Throws<DotMP.Exceptions.InvalidArgumentsException>(() =>
{
DotMP.Parallel.ParallelForCollapse((10, 5), (0, 20), (i, j) => { });
});

Assert.Throws<DotMP.Exceptions.InvalidArgumentsException>(() =>
{
DotMP.Parallel.ParallelFor(10, -5, i => { });
Expand Down
43 changes: 38 additions & 5 deletions DotMP/Wrappers.cs → DotMP/Chunk.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,18 @@
* This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser
* General Public License as published by the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the
* implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
* License for more details.
*
* You should have received a copy of the GNU Lesser General Public License along with this library; if not,
* write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/

using System;
using System.Linq;
using System.Runtime.CompilerServices;
using DotMP.Exceptions;

/* jscpd:ignore-start */
namespace DotMP
Expand Down Expand Up @@ -179,7 +179,41 @@ private enum ActionSelector
/// <summary>
/// Represents the ranges of collapsed loops for future unflattening.
/// </summary>
private ValueTuple<int, int>[] ranges;
private ValueTuple<int, int>[] ranges_prv;

/// <summary>
/// Represents the ranges of collapsed loops for unflattening, ensuring that loops do not have too many iterations.
/// </summary>
private ValueTuple<int, int>[] ranges
{
get => ranges_prv;
set
{
int total_iters = 1;

try
{
foreach ((int start, int end) in value)
{
if (end < start)
throw new InvalidArgumentsException(string.Format("Start of loop ({0}) must be less than end of loop ({1}).", start, end));

if (start < 0 || end < 0)
throw new InvalidArgumentsException(string.Format("Start ({0}) and end ({1}) of loop must both be positive integers.", start, end));

total_iters = checked(total_iters * (end - start));
}
}
catch (OverflowException)
{
throw new TooManyIterationsException(string.Format("Parallel-for loop has too many iterations (exceeds {0}).", int.MaxValue));
}
finally
{
ranges_prv = value;
}
}
}

/// <summary>
/// Array representing the starting indices.
Expand Down Expand Up @@ -420,7 +454,6 @@ private void ComputeIndicesN(int curr_iter, int[] indices)

/// <summary>
/// Executes a chunk using the action selected by ForAction.selector
/// TODO: Optimize this whole function.
/// </summary>
/// <param name="curr_iter">A reference to the current iteration.</param>
/// <param name="start">The start of the chunk, inclusive.</param>
Expand Down
12 changes: 12 additions & 0 deletions DotMP/Exceptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -65,4 +65,16 @@ public class InvalidArgumentsException : Exception
/// <param name="msg">The message to associate with the exception.</param>
public InvalidArgumentsException(string msg) : base(msg) { }
}

/// <summary>
/// Exception thrown if a for loop has too many iterations and would cause the schedulers to fail.
/// </summary>
public class TooManyIterationsException : Exception
{
/// <summary>
/// Constructor with a message.
/// </summary>
/// <param name="msg">The message to associate with the exception.</param>
public TooManyIterationsException(string msg) : base(msg) { }
}
}
8 changes: 8 additions & 0 deletions DotMP/Parallel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,7 @@ public static void For(int start, int end, Action<int> action, IScheduler schedu
/// <exception cref="NotInParallelRegionException">Thrown when not in a parallel region.</exception>
/// <exception cref="CannotPerformNestedWorksharingException">Thrown when nested inside another worksharing region.</exception>
/// <exception cref="InvalidArgumentsException">Thrown if any provided arguments are invalid.</exception>
/// <exception cref="TooManyIterationsException">Thrown if there are too many iterations to handle.</exception>
public static void ForCollapse((int, int) firstRange, (int, int) secondRange, Action<int, int> action, IScheduler schedule = null, uint? chunk_size = null)
{
ForAction<object> forAction = new ForAction<object>(action, new (int, int)[] { firstRange, secondRange });
Expand Down Expand Up @@ -231,6 +232,7 @@ public static void ForCollapse((int, int) firstRange, (int, int) secondRange, Ac
/// <exception cref="NotInParallelRegionException">Thrown when not in a parallel region.</exception>
/// <exception cref="CannotPerformNestedWorksharingException">Thrown when nested inside another worksharing region.</exception>
/// <exception cref="InvalidArgumentsException">Thrown if any provided arguments are invalid.</exception>
/// <exception cref="TooManyIterationsException">Thrown if there are too many iterations to handle.</exception>
public static void ForCollapse((int, int) firstRange, (int, int) secondRange, (int, int) thirdRange, Action<int, int, int> action, IScheduler schedule = null, uint? chunk_size = null)
{
ForAction<object> forAction = new ForAction<object>(action, new (int, int)[] { firstRange, secondRange, thirdRange });
Expand Down Expand Up @@ -260,6 +262,7 @@ public static void ForCollapse((int, int) firstRange, (int, int) secondRange, (i
/// <exception cref="NotInParallelRegionException">Thrown when not in a parallel region.</exception>
/// <exception cref="CannotPerformNestedWorksharingException">Thrown when nested inside another worksharing region.</exception>
/// <exception cref="InvalidArgumentsException">Thrown if any provided arguments are invalid.</exception>
/// <exception cref="TooManyIterationsException">Thrown if there are too many iterations to handle.</exception>
public static void ForCollapse((int, int) firstRange, (int, int) secondRange, (int, int) thirdRange, (int, int) fourthRange, Action<int, int, int, int> action, IScheduler schedule = null, uint? chunk_size = null)
{
ForAction<object> forAction = new ForAction<object>(action, new (int, int)[] { firstRange, secondRange, thirdRange, fourthRange });
Expand Down Expand Up @@ -287,6 +290,7 @@ public static void ForCollapse((int, int) firstRange, (int, int) secondRange, (i
/// <exception cref="NotInParallelRegionException">Thrown when not in a parallel region.</exception>
/// <exception cref="CannotPerformNestedWorksharingException">Thrown when nested inside another worksharing region.</exception>
/// <exception cref="InvalidArgumentsException">Thrown if any provided arguments are invalid.</exception>
/// <exception cref="TooManyIterationsException">Thrown if there are too many iterations to handle.</exception>
public static void ForCollapse((int, int)[] ranges, Action<int[]> action, IScheduler schedule = null, uint? chunk_size = null)
{
ForAction<object> forAction = new ForAction<object>(action, ranges);
Expand Down Expand Up @@ -394,6 +398,7 @@ public static void ForReduction<T>(int start, int end, Operations op, ref T redu
/// <exception cref="NotInParallelRegionException">Thrown when not in a parallel region.</exception>
/// <exception cref="CannotPerformNestedWorksharingException">Thrown when nested inside another worksharing region.</exception>
/// <exception cref="InvalidArgumentsException">Thrown if any provided arguments are invalid.</exception>
/// <exception cref="TooManyIterationsException">Thrown if there are too many iterations to handle.</exception>
public static void ForReductionCollapse<T>((int, int) firstRange, (int, int) secondRange, Operations op, ref T reduce_to, ActionRef2<T> action, IScheduler schedule = null, uint? chunk_size = null)
{
ForAction<T> forAction = new ForAction<T>(action, new (int, int)[] { firstRange, secondRange });
Expand Down Expand Up @@ -426,6 +431,7 @@ public static void ForReductionCollapse<T>((int, int) firstRange, (int, int) sec
/// <exception cref="NotInParallelRegionException">Thrown when not in a parallel region.</exception>
/// <exception cref="CannotPerformNestedWorksharingException">Thrown when nested inside another worksharing region.</exception>
/// <exception cref="InvalidArgumentsException">Thrown if any provided arguments are invalid.</exception>
/// <exception cref="TooManyIterationsException">Thrown if there are too many iterations to handle.</exception>
public static void ForReductionCollapse<T>((int, int) firstRange, (int, int) secondRange, (int, int) thirdRange, Operations op, ref T reduce_to, ActionRef3<T> action, IScheduler schedule = null, uint? chunk_size = null)
{
ForAction<T> forAction = new ForAction<T>(action, new (int, int)[] { firstRange, secondRange, thirdRange });
Expand Down Expand Up @@ -460,6 +466,7 @@ public static void ForReductionCollapse<T>((int, int) firstRange, (int, int) sec
/// <exception cref="NotInParallelRegionException">Thrown when not in a parallel region.</exception>
/// <exception cref="CannotPerformNestedWorksharingException">Thrown when nested inside another worksharing region.</exception>
/// <exception cref="InvalidArgumentsException">Thrown if any provided arguments are invalid.</exception>
/// <exception cref="TooManyIterationsException">Thrown if there are too many iterations to handle.</exception>
public static void ForReductionCollapse<T>((int, int) firstRange, (int, int) secondRange, (int, int) thirdRange, (int, int) fourthRange, Operations op, ref T reduce_to, ActionRef4<T> action, IScheduler schedule = null, uint? chunk_size = null)
{
ForAction<T> forAction = new ForAction<T>(action, new (int, int)[] { firstRange, secondRange, thirdRange, fourthRange });
Expand Down Expand Up @@ -492,6 +499,7 @@ public static void ForReductionCollapse<T>((int, int) firstRange, (int, int) sec
/// <exception cref="NotInParallelRegionException">Thrown when not in a parallel region.</exception>
/// <exception cref="CannotPerformNestedWorksharingException">Thrown when nested inside another worksharing region.</exception>
/// <exception cref="InvalidArgumentsException">Thrown if any provided arguments are invalid.</exception>
/// <exception cref="TooManyIterationsException">Thrown if there are too many iterations to handle.</exception>
public static void ForReductionCollapse<T>((int, int)[] ranges, Operations op, ref T reduce_to, ActionRefN<T> action, IScheduler schedule = null, uint? chunk_size = null)
{
ForAction<T> forAction = new ForAction<T>(action, ranges);
Expand Down

0 comments on commit 32ecdc2

Please sign in to comment.