Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Threading improvements #8

Merged
merged 13 commits into from
Sep 16, 2023
29 changes: 29 additions & 0 deletions .github/workflows/dotnet.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# This workflow will build a .NET project

name: .NET

on:
push:
branches: [ "master", "develop" ]
pull_request:
branches: [ "master" ]

jobs:
build:

runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v3
- name: Setup .NET
uses: actions/setup-dotnet@v3
with:
dotnet-version: 6.0.x
- name: Install FFTW
run: sudo apt-get install libfftw3-bin
- name: Restore dependencies
run: dotnet restore
- name: Build
run: dotnet build --no-restore
- name: Test
run: dotnet test --no-build --verbosity normal
107 changes: 78 additions & 29 deletions SharpFFTW.Tests/Double/TestManaged.cs
Original file line number Diff line number Diff line change
@@ -1,46 +1,34 @@

namespace SharpFFTW.Tests.Double
{
using NUnit.Framework;
using SharpFFTW;
using SharpFFTW.Double;
using System;
using System.Collections.Concurrent;
using System.Threading;
using System.Threading.Tasks;

/// <summary>
/// Test managed FFTW interface (1D).
/// </summary>
public class TestManaged
{
/// <summary>
/// Run examples.
/// </summary>
/// <param name="n">Logical size of the transform.</param>
public static void Run(int length)
[Test]
public void Test()
{
Console.WriteLine("Starting managed test with FFT size = " + length + " (Type: double)");
Console.WriteLine();

try
{
Example1(length);
Example2(length);
Example3(length);
}
catch (BadImageFormatException)
{
Util.Write("Couldn't load native FFTW image (Type: double)", false);
}
catch (Exception e)
{
Util.Write(e.Message, false);
}
const int SIZE = 8192;

Console.WriteLine();
Assert.True(Example1(SIZE));
Assert.True(Example2(SIZE));
Assert.True(Example3(SIZE));
Assert.True(Example4(2000, false));
}

/// <summary>
/// Complex to complex transform.
/// </summary>
static void Example1(int length)
bool Example1(int length)
{
Console.Write("Test 1: complex transform ... ");

Expand Down Expand Up @@ -69,13 +57,13 @@ static void Example1(int length)
input.CopyTo(data);

// Check and see how we did.
Util.CheckResults(length, length, data);
return Util.CheckResults(length, length, data);
}

/// <summary>
/// Real to complex transform.
/// </summary>
static void Example2(int length)
bool Example2(int length)
{
Console.Write("Test 2: real to complex transform ... ");

Expand Down Expand Up @@ -103,13 +91,13 @@ static void Example2(int length)
input.CopyTo(data);

// Check and see how we did.
Util.CheckResults(n, n, data);
return Util.CheckResults(n, n, data);
}

/// <summary>
/// Real to half-complex transform.
/// </summary>
static void Example3(int length)
bool Example3(int length)
{
Console.Write("Test 3: real to half-complex transform ... ");

Expand Down Expand Up @@ -137,7 +125,68 @@ static void Example3(int length)
input.CopyTo(data);

// Check and see how we did.
Util.CheckResults(n, n, data);
return Util.CheckResults(n, n, data);
}

/// <summary>
/// Parallel execution.
/// </summary>
bool Example4(int tasks, bool print)
{
Console.Write("Test 4: parallel real to complex transform ... ");

var plans = new ConcurrentDictionary<int, Tuple<RealArray, ComplexArray, Plan, Plan>>();

const int size = 4096;

var result = Parallel.For(0, tasks, (i, state) =>
{
int thread = Thread.CurrentThread.ManagedThreadId;

var (input, _, plan1, plan2) = plans.GetOrAdd(thread, (i) =>
{
var input = new RealArray(size);
var output = new ComplexArray(size / 2 + 1);

var plan1 = Plan.Create1(size, input, output, Options.Estimate);
var plan2 = Plan.Create1(size, output, input, Options.Estimate);

return new Tuple<RealArray, ComplexArray, Plan, Plan>(input, output, plan1, plan2);
});

var data = Util.GenerateSignal(size);

input.Set(data);

plan1.Execute();
plan2.Execute();

Array.Clear(data, 0, size);

input.CopyTo(data);

var success = Util.CheckResults(size, size, data);

if (print)
{
Console.WriteLine($"{i,5}: current thread = {thread}, success = {success}");
}

if (!success)
{
state.Break();
}
});

foreach (var (input, output, plan1, plan2) in plans.Values)
{
plan1.Dispose();
plan2.Dispose();
input.Dispose();
output.Dispose();
}

return result.IsCompleted;
}
}
}
42 changes: 15 additions & 27 deletions SharpFFTW.Tests/Double/TestNative.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@

namespace SharpFFTW.Tests.Double
{
using NUnit.Framework;
using SharpFFTW;
using SharpFFTW.Double;
using System;
Expand All @@ -11,33 +12,16 @@ namespace SharpFFTW.Tests.Double
/// </summary>
public class TestNative
{
/// <summary>
/// Run examples.
/// </summary>
/// <param name="length">Logical size of the transform.</param>
public static void Run(int length)
[Test]
public void Test()
{
Console.WriteLine("Starting native test with FFT size = " + length + " (Type: double)");
Console.WriteLine();

try
{
Example1(length);
Example2(length);
}
catch (BadImageFormatException)
{
Util.Write("Couldn't load native FFTW image (Type: double)", false);
}
catch (Exception e)
{
Util.Write(e.Message, false);
}

Console.WriteLine();
const int SIZE = 8192;

Assert.True(Example1(SIZE));
Assert.True(Example2(SIZE));
}

static void Example1(int length)
bool Example1(int length)
{
Console.Write("Test 1: complex transform ... ");

Expand Down Expand Up @@ -73,16 +57,18 @@ static void Example1(int length)
Marshal.Copy(pin, fin, 0, size);

// Check and see how we did.
Util.CheckResults(length, length, fin);
bool success = Util.CheckResults(length, length, fin);

// Don't forget to free the memory after finishing.
NativeMethods.fftw_free(pin);
NativeMethods.fftw_free(pout);
NativeMethods.fftw_destroy_plan(plan1);
NativeMethods.fftw_destroy_plan(plan2);

return success;
}

static void Example2(int length)
bool Example2(int length)
{
Console.Write("Test 2: complex transform ... ");

Expand Down Expand Up @@ -116,14 +102,16 @@ static void Example2(int length)
NativeMethods.fftw_execute(plan2);

// Check and see how we did.
Util.CheckResults(length, length, fin);
bool success = Util.CheckResults(length, length, fin);

// Don't forget to free the memory after finishing.
NativeMethods.fftw_destroy_plan(plan1);
NativeMethods.fftw_destroy_plan(plan2);

hin.Free();
hout.Free();

return success;
}
}
}
19 changes: 15 additions & 4 deletions SharpFFTW.Tests/Double/Util.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ public static double[] GenerateSignal(int n)
return data;
}

public static void CheckResults(int n, int scale, double[] data, double eps = 1e-3)
public static bool CheckResults(int n, int scale, double[] data, double eps = 1e-3)
{
for (int i = 0; i < n; i++)
{
Expand All @@ -26,14 +26,25 @@ public static void CheckResults(int n, int scale, double[] data, double eps = 1e
// Check against original value.
if (double.IsNaN(result) || Math.Abs(result - (i % 50)) > eps)
{
Write("failed", false);
return;
return false;
}
}

// Yeah, alright. So this was kind of a trivial test and of course
// it's gonna work. But still.
Write("ok", true);
return true;
}

public static void PrintResult(bool succsess)
{
if (succsess)
{
Write("ok", true);
}
else
{
Write("failed", false);
}
}

public static void Write(string message, bool ok)
Expand Down
21 changes: 0 additions & 21 deletions SharpFFTW.Tests/Program.cs

This file was deleted.

14 changes: 14 additions & 0 deletions SharpFFTW.Tests/Setup.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
using NUnit.Framework;

namespace SharpFFTW.Tests
{
[SetUpFixture]
public class Setup
{
[OneTimeSetUp]
public void GlobalSetup()
{
Library.SetImportResolver();
}
}
}
13 changes: 9 additions & 4 deletions SharpFFTW.Tests/SharpFFTW.Tests.csproj
Original file line number Diff line number Diff line change
@@ -1,17 +1,22 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>

<IsPackable>false</IsPackable>
<IsTestProject>true</IsTestProject>

<Platforms>AnyCPU;x64</Platforms>

<OutputType>Exe</OutputType>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.7.2" />
<PackageReference Include="NUnit" Version="3.13.3" />
<PackageReference Include="NUnit3TestAdapter" Version="4.5.0" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\SharpFFTW\SharpFFTW.csproj" />
</ItemGroup>

</Project>
</Project>
Loading