LMMS Memory Manager

This commit is contained in:
Vesa
2014-08-22 20:52:30 +03:00
parent 6f963159df
commit 9c25be1bde
25 changed files with 415 additions and 33 deletions

210
src/core/MemoryManager.cpp Normal file
View File

@@ -0,0 +1,210 @@
/*
* MemoryManager.cpp - A lightweight, generic memory manager for LMMS
*
* Copyright (c) 2014 Vesa Kivimäki
* Copyright (c) 2007-2014 Tobias Doerffel <tobydox/at/users.sourceforge.net>
*
* This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.net
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This program 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
* General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this program (see COPYING); if not, write to the
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301 USA.
*
*/
#include "MemoryManager.h"
#include <QtGlobal>
MemoryPoolVector MemoryManager::s_memoryPools;
QMutex MemoryManager::s_poolMutex;
PointerInfoMap MemoryManager::s_pointerInfo;
QMutex MemoryManager::s_pointerMutex;
bool MemoryManager::init()
{
// construct first MemoryPool and allocate memory
MemoryPool m ( MM_INITIAL_CHUNKS );
m.m_pool = MemoryHelper::alignedMalloc( MM_INITIAL_CHUNKS * MM_CHUNK_SIZE );
s_memoryPools.append( m );
return true;
}
void * MemoryManager::alloc( size_t size )
{
int requiredChunks = size / MM_CHUNK_SIZE + ( size % MM_CHUNK_SIZE > 0 ? 1 : 0 );
MemoryPool * mp = NULL;
void * ptr = NULL;
MemoryPoolVector::iterator it = s_memoryPools.begin();
s_poolMutex.lock();
while( it != s_memoryPools.end() && !ptr )
{
ptr = ( *it ).getChunks( requiredChunks );
if( ptr )
{
mp = &( *it );
}
}
s_poolMutex.unlock();
if( ptr )
{
s_pointerMutex.lock();
PtrInfo p;
p.chunks = requiredChunks;
p.memPool = mp;
s_pointerInfo[ptr] = p;
s_pointerMutex.unlock();
return ptr;
}
// can't find enough chunks in existing pools, so
// create a new pool that is guaranteed to have enough chunks
int moreChunks = qMax( requiredChunks, MM_INCREMENT_CHUNKS );
int i = MemoryManager::extend( moreChunks );
mp = &s_memoryPools[i];
ptr = s_memoryPools[i].getChunks( requiredChunks );
if( ptr )
{
s_pointerMutex.lock();
PtrInfo p;
p.chunks = requiredChunks;
p.memPool = mp;
s_pointerInfo[ptr] = p;
s_pointerMutex.unlock();
return ptr;
}
// still no luck? something is horribly wrong
qFatal( "MemoryManager.cpp: Couldn't allocate memory: %d chunks asked", requiredChunks );
return NULL;
}
void MemoryManager::free( void * ptr )
{
if( ptr == NULL ) return; // let's not try to deallocate null pointers, ok?
// fetch info on the ptr and remove
s_pointerMutex.lock();
if( ! s_pointerInfo.contains( ptr ) ) // if we have no info on ptr, fail loudly
{
qFatal( "MemoryManager.cpp: Couldn't find pointer info for pointer: %d", (int)ptr );
}
PtrInfo p = s_pointerInfo[ptr];
s_pointerInfo.remove( ptr );
s_pointerMutex.unlock();
p.memPool->releaseChunks( ptr, p.chunks );
}
int MemoryManager::extend( int chunks )
{
MemoryPool m ( chunks );
m.m_pool = MemoryHelper::alignedMalloc( chunks * MM_CHUNK_SIZE );
s_poolMutex.lock();
s_memoryPools.append( m );
int i = s_memoryPools.size() - 1;
s_poolMutex.unlock();
return i;
}
void MemoryManager::cleanup()
{
for( MemoryPoolVector::iterator it = s_memoryPools.begin(); it != s_memoryPools.end(); ++it )
{
MemoryHelper::alignedFree( ( *it ).m_pool );
MemoryHelper::alignedFree( ( *it ).m_free );
}
}
void * MemoryPool::getChunks( int chunksNeeded )
{
if( chunksNeeded > m_chunks ) // not enough chunks in this pool?
{
return NULL;
}
m_mutex.lock();
// now find out if we have a long enough sequence of chunks in this pool
char last = 0;
int n = 0;
int index = -1;
bool found = false;
for( int i = 0; i < m_chunks; ++i )
{
if( m_free[i] )
{
if( !last )
{
index = i;
}
++n;
if( n >= chunksNeeded )
{
found = true;
break;
}
}
else
{
n = 0;
}
last = m_free[i];
}
if( found ) // if enough chunks found, return pointer to chunks
{
// set chunk flags to false so we know the chunks are in use
for( int i = 0; i < chunksNeeded; ++i )
{
m_free[ index + i ] = 0;
}
m_mutex.unlock();
return (char*)m_pool + ( index * MM_CHUNK_SIZE );
}
m_mutex.unlock();
return NULL; // out of stock, come again tomorrow!
}
void MemoryPool::releaseChunks( void * ptr, int chunks )
{
m_mutex.lock();
int start = ( (int)ptr - (int)m_pool ) / MM_CHUNK_SIZE;
if( start < 0 )
{
qFatal( "MemoryManager: error at releaseChunks() - corrupt pointer info?" );
}
memset( &m_free[ start ], 1, chunks );
m_mutex.unlock();
}

View File

@@ -61,6 +61,7 @@
#include "templates.h"
#include "FileDialog.h"
#include "MemoryManager.h"
SampleBuffer::SampleBuffer( const QString & _audio_file,
@@ -106,7 +107,7 @@ SampleBuffer::SampleBuffer( const sampleFrame * _data, const f_cnt_t _frames ) :
{
if( _frames > 0 )
{
m_origData = new sampleFrame[_frames];
m_origData = MM_ALLOC( sampleFrame, _frames );
memcpy( m_origData, _data, _frames * BYTES_PER_FRAME );
m_origFrames = _frames;
}
@@ -133,7 +134,7 @@ SampleBuffer::SampleBuffer( const f_cnt_t _frames ) :
{
if( _frames > 0 )
{
m_origData = new sampleFrame[_frames];
m_origData = MM_ALLOC( sampleFrame, _frames );
memset( m_origData, 0, _frames * BYTES_PER_FRAME );
m_origFrames = _frames;
}
@@ -145,8 +146,8 @@ SampleBuffer::SampleBuffer( const f_cnt_t _frames ) :
SampleBuffer::~SampleBuffer()
{
delete[] m_origData;
delete[] m_data;
MM_FREE( m_origData );
MM_FREE( m_data );
}
@@ -160,14 +161,14 @@ void SampleBuffer::update( bool _keep_settings )
if( lock )
{
engine::mixer()->lock();
delete[] m_data;
MM_FREE( m_data );
}
if( m_audioFile.isEmpty() && m_origData != NULL && m_origFrames > 0 )
{
// TODO: reverse- and amplification-property is not covered
// by following code...
m_data = new sampleFrame[m_origFrames];
m_data = MM_ALLOC( sampleFrame, m_origFrames );
memcpy( m_data, m_origData, m_origFrames * BYTES_PER_FRAME );
if( _keep_settings == false )
{
@@ -232,7 +233,7 @@ void SampleBuffer::update( bool _keep_settings )
{
// sample couldn't be decoded, create buffer containing
// one sample-frame
m_data = new sampleFrame[1];
m_data = MM_ALLOC( sampleFrame, 1 );
memset( m_data, 0, sizeof( *m_data ) );
m_frames = 1;
m_loopStartFrame = m_startFrame = 0;
@@ -252,7 +253,7 @@ void SampleBuffer::update( bool _keep_settings )
{
// neither an audio-file nor a buffer to copy from, so create
// buffer containing one sample-frame
m_data = new sampleFrame[1];
m_data = MM_ALLOC( sampleFrame, 1 );
memset( m_data, 0, sizeof( *m_data ) );
m_frames = 1;
m_loopStartFrame = m_startFrame = 0;
@@ -273,7 +274,7 @@ void SampleBuffer::convertIntToFloat ( int_sample_t * & _ibuf, f_cnt_t _frames,
// following code transforms int-samples into
// float-samples and does amplifying & reversing
const float fac = 1 / OUTPUT_SAMPLE_MULTIPLIER;
m_data = new sampleFrame[_frames];
m_data = MM_ALLOC( sampleFrame, _frames );
const int ch = ( _channels > 1 ) ? 1 : 0;
// if reversing is on, we also reverse when
@@ -313,7 +314,7 @@ void SampleBuffer::directFloatWrite ( sample_t * & _fbuf, f_cnt_t _frames, int _
{
m_data = new sampleFrame[_frames];
m_data = MM_ALLOC( sampleFrame, _frames );
const int ch = ( _channels > 1 ) ? 1 : 0;
// if reversing is on, we also reverse when
@@ -356,9 +357,9 @@ void SampleBuffer::normalizeSampleRate( const sample_rate_t _src_sr,
{
SampleBuffer * resampled = resample( this, _src_sr,
engine::mixer()->baseSampleRate() );
delete[] m_data;
MM_FREE( m_data );
m_frames = resampled->frames();
m_data = new sampleFrame[m_frames];
m_data = MM_ALLOC( sampleFrame, m_frames );
memcpy( m_data, resampled->data(), m_frames *
sizeof( sampleFrame ) );
delete resampled;
@@ -1336,15 +1337,15 @@ void SampleBuffer::loadFromBase64( const QString & _data )
printf("%d\n", (int) orig_data.size() );
m_origFrames = orig_data.size() / sizeof( sampleFrame );
delete[] m_origData;
m_origData = new sampleFrame[m_origFrames];
MM_FREE( m_origData );
m_origData = MM_ALLOC( sampleFrame, m_origFrames );
memcpy( m_origData, orig_data.data(), orig_data.size() );
#else /* LMMS_HAVE_FLAC_STREAM_DECODER_H */
m_origFrames = dsize / sizeof( sampleFrame );
delete[] m_origData;
m_origData = new sampleFrame[m_origFrames];
MM_FREE( m_origData );
m_origData = MM_ALLOC( sampleFrame, m_origFrames );
memcpy( m_origData, dst, dsize );
#endif

View File

@@ -64,6 +64,7 @@
#include <unistd.h>
#endif
#include "MemoryManager.h"
#include "ConfigManager.h"
#include "embed.h"
#include "engine.h"
@@ -97,6 +98,9 @@ inline void loadTranslation( const QString & _tname,
int main( int argc, char * * argv )
{
// initialize memory manager
MemoryManager::init();
// intialize RNG
srand( getpid() + time( 0 ) );
@@ -529,6 +533,10 @@ int main( int argc, char * * argv )
const int ret = app->exec();
delete app;
// cleanup memory manager
MemoryManager::cleanup();
return( ret );
}