mirror of
https://github.com/DSheirer/sdrtrunk.git
synced 2026-11-12 08:37:25 -05:00
[WIP] Implements reusable sample buffers across all components. This
produces a significant reduction in memory usage, especially for tuners like the airspy and hackrf that produce 10/20 MSPS sample rates. This is observed to be around 66% reduction in peak memory usage and provides a more stable memory utilization across time reducing stress on the garbage collector. Use of these reusable memory buffers will be pushed further down into the processing chain modules to ensure we keep new object creation to the lowest levels possible.
This commit is contained in:
@@ -26,7 +26,8 @@ import io.github.dsheirer.dsp.filter.smoothing.SmoothingFilter.SmoothingType;
|
||||
import io.github.dsheirer.module.ProcessingChain;
|
||||
import io.github.dsheirer.sample.Listener;
|
||||
import io.github.dsheirer.sample.SampleType;
|
||||
import io.github.dsheirer.sample.complex.ComplexBuffer;
|
||||
import io.github.dsheirer.sample.complex.reusable.ReusableBufferQueue;
|
||||
import io.github.dsheirer.sample.complex.reusable.ReusableComplexBuffer;
|
||||
import io.github.dsheirer.sample.real.RealBuffer;
|
||||
import io.github.dsheirer.settings.ColorSetting.ColorSettingName;
|
||||
import io.github.dsheirer.settings.ColorSettingMenuItem;
|
||||
@@ -68,6 +69,7 @@ public class ChannelSpectrumPanel extends JPanel implements ChannelEventListener
|
||||
private JLayeredPane mLayeredPane;
|
||||
private SpectrumPanel mSpectrumPanel;
|
||||
private ChannelOverlayPanel mOverlayPanel;
|
||||
private ReusableBufferQueue mReusableBufferQueue = new ReusableBufferQueue();
|
||||
|
||||
private Channel mCurrentChannel;
|
||||
|
||||
@@ -274,7 +276,9 @@ public class ChannelSpectrumPanel extends JPanel implements ChannelEventListener
|
||||
|
||||
//Hack: we're placing real samples in a complex buffer that the DFT
|
||||
//processor is expecting.
|
||||
mDFTProcessor.receive(new ComplexBuffer(decimated.getSamples()));
|
||||
ReusableComplexBuffer reusableComplexBuffer = mReusableBufferQueue.getBuffer(decimated.getSamples().length);
|
||||
reusableComplexBuffer.reloadFrom(decimated.getSamples(), System.currentTimeMillis());
|
||||
mDFTProcessor.receive(reusableComplexBuffer.incrementUserCount());
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -20,7 +20,7 @@ import io.github.dsheirer.dsp.filter.Window.WindowType;
|
||||
import io.github.dsheirer.properties.SystemProperties;
|
||||
import io.github.dsheirer.sample.Listener;
|
||||
import io.github.dsheirer.sample.SampleType;
|
||||
import io.github.dsheirer.sample.complex.ComplexBuffer;
|
||||
import io.github.dsheirer.sample.complex.reusable.ReusableComplexBuffer;
|
||||
import io.github.dsheirer.sample.real.IOverflowListener;
|
||||
import io.github.dsheirer.source.ISourceEventProcessor;
|
||||
import io.github.dsheirer.source.SourceEvent;
|
||||
@@ -41,7 +41,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
||||
* Processes both complex samples or float samples and dispatches a float array of DFT results, using configurable fft
|
||||
* size and output dispatch timelines.
|
||||
*/
|
||||
public class DFTProcessor implements Listener<ComplexBuffer>, ISourceEventProcessor, IDFTWidthChangeProcessor
|
||||
public class DFTProcessor implements Listener<ReusableComplexBuffer>, ISourceEventProcessor, IDFTWidthChangeProcessor
|
||||
{
|
||||
private static final Logger mLog = LoggerFactory.getLogger(DFTProcessor.class);
|
||||
private static final int BUFFER_QUEUE_MAX_SIZE = 12;
|
||||
@@ -192,13 +192,18 @@ public class DFTProcessor implements Listener<ComplexBuffer>, ISourceEventProces
|
||||
* Places the sample into a transfer queue for future processing.
|
||||
*/
|
||||
@Override
|
||||
public void receive(ComplexBuffer sampleBuffer)
|
||||
public void receive(ReusableComplexBuffer sampleBuffer)
|
||||
{
|
||||
mOverflowableBufferStream.offer(sampleBuffer);
|
||||
}
|
||||
|
||||
private void calculate()
|
||||
{
|
||||
//We always send the previous calculated samples - this should improve the screen rendering since the frame
|
||||
//rate will always occur on an even rhythm. Any delays caused by processing will be absorbed and not impact
|
||||
//the screen rendering.
|
||||
dispatch(mPreviousSamples);
|
||||
|
||||
try
|
||||
{
|
||||
if(mFrameFlushCount > 0)
|
||||
@@ -220,14 +225,12 @@ public class DFTProcessor implements Listener<ComplexBuffer>, ISourceEventProces
|
||||
mFFT.complexForward(samples);
|
||||
}
|
||||
|
||||
dispatch(samples);
|
||||
|
||||
mPreviousSamples = samples;
|
||||
}
|
||||
catch(IOException ioe)
|
||||
{
|
||||
//No new data, dispatch the previous samples again
|
||||
dispatch(mPreviousSamples);
|
||||
//no-op
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -16,8 +16,8 @@
|
||||
package io.github.dsheirer.spectrum;
|
||||
|
||||
|
||||
import io.github.dsheirer.sample.Buffer;
|
||||
import io.github.dsheirer.sample.OverflowableTransferQueue;
|
||||
import io.github.dsheirer.sample.complex.reusable.ReusableComplexBuffer;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
@@ -25,20 +25,20 @@ import java.io.IOException;
|
||||
import java.nio.FloatBuffer;
|
||||
import java.util.LinkedList;
|
||||
|
||||
public class OverflowableBufferStream extends OverflowableTransferQueue<Buffer>
|
||||
public class OverflowableBufferStream extends OverflowableTransferQueue<ReusableComplexBuffer>
|
||||
{
|
||||
private static final Logger mLog = LoggerFactory.getLogger(OverflowableBufferStream.class);
|
||||
|
||||
private int mFlushCount = 0;
|
||||
private Buffer mCurrentBuffer;
|
||||
private ReusableComplexBuffer mCurrentBuffer;
|
||||
private int mCurrentBufferPointer = 0;
|
||||
private FloatBuffer mFloatBuffer;
|
||||
private LinkedList<Buffer> mBufferList = new LinkedList<>();
|
||||
private LinkedList<ReusableComplexBuffer> mBufferList = new LinkedList<>();
|
||||
private int mBufferFetchLimit;
|
||||
|
||||
/**
|
||||
* Stream for receiving Buffers from a producer thread and providing access to a consumer thread to read the
|
||||
* sample data. Extends the overflowable transfer queue to define maximum and reset thresholds to ensure the
|
||||
* Stream for receiving reusable buffers from a producer thread and providing access to a consumer thread to read
|
||||
* the sample data. Extends the overflowable transfer queue to define maximum and reset thresholds to ensure the
|
||||
* queue doesn't grow too large.
|
||||
*
|
||||
* This stream is designed for consistent sample size requests each time the get() samples method is invoked, such
|
||||
@@ -55,7 +55,7 @@ public class OverflowableBufferStream extends OverflowableTransferQueue<Buffer>
|
||||
{
|
||||
super(maxSize, resetThreshold);
|
||||
mFloatBuffer = FloatBuffer.allocate(arraySize);
|
||||
mBufferFetchLimit = maxSize = resetThreshold;
|
||||
mBufferFetchLimit = maxSize - resetThreshold;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -181,7 +181,13 @@ public class OverflowableBufferStream extends OverflowableTransferQueue<Buffer>
|
||||
*/
|
||||
private void getNextBuffer() throws IOException
|
||||
{
|
||||
mCurrentBuffer = null;
|
||||
if(mCurrentBuffer != null)
|
||||
{
|
||||
//Decrement the user count to let the originator know we're done with their buffer
|
||||
mCurrentBuffer.decrementUserCount();
|
||||
mCurrentBuffer = null;
|
||||
}
|
||||
|
||||
mCurrentBufferPointer = 0;
|
||||
|
||||
if(mBufferList.isEmpty())
|
||||
@@ -196,7 +202,28 @@ public class OverflowableBufferStream extends OverflowableTransferQueue<Buffer>
|
||||
|
||||
if(mCurrentBuffer == null)
|
||||
{
|
||||
throw new IOException("Buffer queue is (currently) empty");
|
||||
throw new IOException("Reusable complex buffer queue is (currently) empty");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears all elements from the queue and resets the internal counter to 0
|
||||
*/
|
||||
@Override
|
||||
public void clear()
|
||||
{
|
||||
synchronized(mQueue)
|
||||
{
|
||||
ReusableComplexBuffer buffer = mQueue.poll();
|
||||
|
||||
while(buffer != null)
|
||||
{
|
||||
buffer.decrementUserCount();
|
||||
buffer = mQueue.poll();
|
||||
}
|
||||
|
||||
mCounter.set(0);
|
||||
mOverflow.set(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,7 +26,7 @@ import io.github.dsheirer.module.decode.DecoderType;
|
||||
import io.github.dsheirer.properties.SystemProperties;
|
||||
import io.github.dsheirer.sample.Listener;
|
||||
import io.github.dsheirer.sample.SampleType;
|
||||
import io.github.dsheirer.sample.complex.ComplexBuffer;
|
||||
import io.github.dsheirer.sample.complex.reusable.ReusableComplexBuffer;
|
||||
import io.github.dsheirer.settings.ColorSetting.ColorSettingName;
|
||||
import io.github.dsheirer.settings.ColorSettingMenuItem;
|
||||
import io.github.dsheirer.settings.SettingsManager;
|
||||
@@ -75,7 +75,8 @@ import java.text.DecimalFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Hashtable;
|
||||
|
||||
public class SpectralDisplayPanel extends JPanel implements Listener<ComplexBuffer>, ISourceEventProcessor, IDFTWidthChangeProcessor
|
||||
public class SpectralDisplayPanel extends JPanel implements Listener<ReusableComplexBuffer>, ISourceEventProcessor,
|
||||
IDFTWidthChangeProcessor
|
||||
{
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@@ -412,9 +413,10 @@ public class SpectralDisplayPanel extends JPanel implements Listener<ComplexBuff
|
||||
* Complex sample buffer receive method
|
||||
*/
|
||||
@Override
|
||||
public void receive(ComplexBuffer sampleBuffer)
|
||||
public void receive(ReusableComplexBuffer reusableComplexBuffer)
|
||||
{
|
||||
mDFTProcessor.receive(sampleBuffer);
|
||||
mDFTProcessor.receive(reusableComplexBuffer.incrementUserCount());
|
||||
reusableComplexBuffer.decrementUserCount();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -435,7 +437,7 @@ public class SpectralDisplayPanel extends JPanel implements Listener<ComplexBuff
|
||||
mTuner.getTunerController().addListener(this);
|
||||
|
||||
//Register the dft processor to receive samples from the tuner
|
||||
mTuner.getTunerController().addComplexBufferListener(mDFTProcessor);
|
||||
mTuner.getTunerController().addBufferListener(mDFTProcessor);
|
||||
|
||||
mSpectrumPanel.setSampleSize(mTuner.getSampleSize());
|
||||
|
||||
@@ -458,7 +460,7 @@ public class SpectralDisplayPanel extends JPanel implements Listener<ComplexBuff
|
||||
mTuner.getTunerController().removeListener(this);
|
||||
|
||||
//Deregister the dft processor from receiving samples
|
||||
mTuner.getTunerController().removeComplexBufferListener(mDFTProcessor);
|
||||
mTuner.getTunerController().removeBufferListener(mDFTProcessor);
|
||||
mTuner = null;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user