-
Notifications
You must be signed in to change notification settings - Fork 51
Use Span<T> to reduce memory pressure #36
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
Conversation
…on of arrays and with that reducing pressure on LOH and GC. - Adding dependency on System.Memory to use spans in netstandard2.0 - Using ArrayBuffer to rent temporary arrays for intermediate calculations - Adding unit tests
Hi @ladeak, thank you very much for this PR! I want to review this topic a little more thoroughly so it may take me a few days before I'm able to merge it, but I greatly appreciate this contribution. Note that implementing |
One thing to consider is to multitarget netstandard2.0 and net5.0 (net6 in a few weeks). In net5.0 the nuget package is part of the appframework, so we would not need to list it explicitly. |
Since the non-span RFFT calls the span RFFT let's not test them separately
previously prevented by NuGet bug NuGet/Home#10791
try to get around current NuGet bug NuGet/Home#10791
The intent of this method is to create and return a new array. I don't think span is doing us any favors here.
Hey @ladeak, I finally got some time to go through this thoroughly. Thanks for this PR! I removed span support for I'm a little concerned about the try statements with no exception handling. What errors are they supposed to be catching? |
I updated this to use multi-targeting with conditional package dependencies 😎 <TargetFrameworks>netstandard2.0;net5.0;</TargetFrameworks> <ItemGroup Condition="'$(TargetFramework)' == 'netstandard2.0'">
<PackageReference Include="System.ValueTuple" Version="4.5.0" />
<PackageReference Include="System.Memory" Version="4.5.4" />
</ItemGroup> |
I removed them and it builds and tests pass so I'm interested in your thoughts on this. If the PR looks good let me know and I'll merge and push it to NuGet 👍 🚀 |
This comment has been minimized.
This comment has been minimized.
Multitargeting looks reasonable.
The benefit of having try-finally statements is that in case of an exception, the rented array is still returned to the pool. Without exception block, the exception will be handled just the same way as without the try-finally block. So without a try-finally block if exceptions are thrown, we would likely decrease efficiency, as the pool needs to create new instances when it runs out pooled items. I am just searching for sample examples mentioning this pattern without much success, but see the pattern in .net bcl itself example1, example2. I planned to use // For audio we typically want the FFT amplitude (in dB)
fftPower = FftSharp.Transform.FFTpower(fftBuffer);
// Create an array of frequencies for each point of the FFT
fftFreq = FftSharp.Transform.FFTfreq(_sampleRate, fftPower.Length); But thinking out this loud, my sampleRate does not change during the app lifecycle, and the input |
This reverts commit 451fff4.
Exception Handling
I agree we should prevent that memory leak, but I don't love wrapping I added a catch statement that re-throws the exception. I think this allows the user to optionally wrap the call in their own try
{
var buffer = temp.AsSpan(0, input.Length);
MakeComplex(buffer, input);
FFT(buffer);
buffer.Slice(0, destination.Length).CopyTo(destination);
}
catch (Exception ex)
{
throw new Exception("Could not calculate FFT", ex);
}
finally
{
ArrayPool<Complex>.Shared.Return(temp);
} FFTfreq()
Exactly. Frequency for each RFFT point is just an evenly-spaced range between 0 and the Nyquist frequency (half the sample rate). This function doesn't have to be called more than once as long as your sample rate and FFT size doesn't change. A lot of the logic here is for managing the mirror case, but the idea is the same. You should be able to just generate this once. FftSharp/src/FftSharp/Transform.cs Lines 106 to 136 in 6e65e4c
Modern Demo
This is an excellent suggestion! I'll take care of this #38 and upgrade the ScottPlot as well Thanks again for your help on this! Let me know if this all sounds good to you and if so I'll merge it and push it to NuGet 👍 🚀 |
Thank you for the confirmation on On the exceptions I still have some mixed feelings, but I think all solutions will work. In all cases the user of the library still gets an exception if something goes wrong. |
That's fair! My preference would be for the app to halt if the FFT fails. Complex[] buffer = { /* complex rocket data */ }
FFT(buffer); // modifies the buffer in-place If I'm going to determine how much rocket fuel I need to get back home from the moon using FFT (go with it, lol) my preference is to have a big-bang exception that halts the program if the calculation fails. Leaving the buffer filled with incomplete or erroneous data without any warning in the case of a failure seems dangerous 😅 Thanks again for all your help on this! I revamped the demo app in response to your feedback (it's now .NET 5) |
This way a user may pre-allocate a buffer for calling the
FFTpower
andFFTfreq
and then reuse those arrays later, during the lifetime of the application.