Saturday 16 February 2013

Sonic Field Memory Manager

My Mac using an external hard drive for swap space
during a large render

Sonic Field uses a lot of memory. Simple approaches to memory management and swapping data to disk reach a point where they were not good enough for me late last year - now a completely new system is in place.

The old system relied on operators in a patch telling Sonic Field when to swap audio signals out to disk. This was a pain to use and meant that some opportunities for swapping were missed. More complex patches which use more resources meant that this simple approach was not longer cutting it for Sonic Field. Unfortunately, automating something like memory management is very challenging. In some ways, more so in a Java based system than in a more traditional C++ based system because of the automated memory system of the JVM.

Now SFData objects (those which store audio signals) are made available for swapping out to disk as soon as they emerge from a processor. The memory manager is hooked into the main interpretor loop of SFPL:

    /*
     * (non-Javadoc)
     * @see com.nerdscentral.sfpl.SFPL_Runnable#Invoke(java.lang.Object, com.nerdscentral.sfpl.SFPL_Context)
     */
    @Override
    public Object Invoke(final Object input, final SFPL_Context context) throws SFPL_RuntimeException
    {
        Object ret = input;
        int i = 0;
        // This implementation might seem a bit clunky but it works out
        // a bit faster than using a ForEach over the array its self
        // context_ = context;
        long[] counter = new long[this.chainEnd + 1];
        try
        {
            for (i = 0; i <= this.chainEnd; ++i)
            {
                long t0 = System.nanoTime();
                ret = this.interpArray_[i].Interpret(ret, context);
                if (ret instanceof SFData)
                {
                    ret = SFTempDataFile.registerForSwap((SFData) ret);
                }
                long t1 = System.nanoTime();
                counter[i] += (t1 - t0);
            }
        }
        catch (final SFPL_StopException e)
        {
            if (e.rethrow())
            {
                throw e;
            }
            return e.getOperand();
        }
        catch (final Throwable e)
        {
            final Object op = ret == null ? Messages.getString("cSFPL_Runner.0") : ret;   //$NON-NLS-1$
            throw new SFPL_RuntimeException(this.objChain.get(i).obj, op, this.objChain.get(i).line, this.objChain.get(i).colm,
                            this.objChain.get(i).file, e);
        }
        for (i = 0; i <= this.chainEnd; ++i)
        {
            timer.addNanoCount(this.interpArray_[i].Word(), counter[i]);
        }
        return ret;
    }

When the memory manager detects that the JVM (Java Virtual Machine) is running low on memory, it starts to write the SFData objects' audio data to disk. 

The up side is that this approach allows Sonic Field to perform very much bigger calculations. The down side is that some tweaking of launch parameters is required by the user. I hope to make the default/automatic parameters good enough for nearly all conditions, but that will take a bit more work.

No comments:

Post a Comment