Mercurial > hg > svcore
diff data/fft/FFTDataServer.cpp @ 408:115f60df1e4d
* Speed up spectrogram painting by releasing mutex in FFTDataServer
while calculating data prior to writing it, and by adding whole-column
value query methods to FFT objects
* Add paint cache to Thumbwheel -- repaints of this widget were slowing
down the whole spectrogram repaint
* More uses of MutexLocker (named and with debug) and more profile
points
* Make startup much quicker some of the time, with OSC server in place
author | Chris Cannam |
---|---|
date | Thu, 08 May 2008 14:46:22 +0000 |
parents | 7aa1de571880 |
children | 52303ec15cd2 |
line wrap: on
line diff
--- a/data/fft/FFTDataServer.cpp Tue Apr 29 15:34:17 2008 +0000 +++ b/data/fft/FFTDataServer.cpp Thu May 08 14:46:22 2008 +0000 @@ -62,7 +62,7 @@ FFTDataServer *server = 0; - MutexLocker locker(&m_serverMapMutex, "FFTDataServer::m_serverMapMutex[getInstance]"); + MutexLocker locker(&m_serverMapMutex, "FFTDataServer::getInstance::m_serverMapMutex"); if ((server = findServer(n))) { return server; @@ -139,7 +139,7 @@ // or 1536, the model doesn't support this). { - MutexLocker locker(&m_serverMapMutex, "FFTDataServer::m_serverMapMutex[getFuzzyInstance]"); + MutexLocker locker(&m_serverMapMutex, "FFTDataServer::getFuzzyInstance::m_serverMapMutex"); ServerMap::iterator best = m_servers.end(); int bestdist = -1; @@ -258,7 +258,7 @@ FFTDataServer::claimInstance(FFTDataServer *server, bool needLock) { MutexLocker locker(needLock ? &m_serverMapMutex : 0, - "FFTDataServer::m_serverMapMutex[claimInstance]"); + "FFTDataServer::claimInstance::m_serverMapMutex"); #ifdef DEBUG_FFT_SERVER std::cerr << "FFTDataServer::claimInstance(" << server << ")" << std::endl; @@ -303,7 +303,7 @@ FFTDataServer::releaseInstance(FFTDataServer *server, bool needLock) { MutexLocker locker(needLock ? &m_serverMapMutex : 0, - "FFTDataServer::m_serverMapMutex[releaseInstance]"); + "FFTDataServer::releaseInstance::m_serverMapMutex"); #ifdef DEBUG_FFT_SERVER std::cerr << "FFTDataServer::releaseInstance(" << server << ")" << std::endl; @@ -431,7 +431,7 @@ FFTDataServer::modelAboutToBeDeleted(Model *model) { MutexLocker locker(&m_serverMapMutex, - "FFTDataServer::m_serverMapMutex[modelAboutToBeDeleted]"); + "FFTDataServer::modelAboutToBeDeleted::m_serverMapMutex"); #ifdef DEBUG_FFT_SERVER std::cerr << "FFTDataServer::modelAboutToBeDeleted(" << model << ")" @@ -598,7 +598,7 @@ } MutexLocker locker(&m_writeMutex, - "FFTDataServer::m_writeMutex[~FFTDataServer]"); + "FFTDataServer::~FFTDataServer::m_writeMutex"); for (CacheVector::iterator i = m_caches.begin(); i != m_caches.end(); ++i) { @@ -634,7 +634,7 @@ Profiler profiler("FFTDataServer::suspend", false); MutexLocker locker(&m_writeMutex, - "FFTDataServer::m_writeMutex[suspend]"); + "FFTDataServer::suspend::m_writeMutex"); m_suspended = true; for (CacheVector::iterator i = m_caches.begin(); i != m_caches.end(); ++i) { if (*i) (*i)->suspend(); @@ -740,7 +740,7 @@ #endif MutexLocker locker(&m_writeMutex, - "FFTDataServer::m_writeMutex[getCacheAux]"); + "FFTDataServer::getCacheAux::m_writeMutex"); if (m_lastUsedCache == -1) { m_fillThread->start(); @@ -875,15 +875,51 @@ if (!cache) return 0; if (!cache->haveSetColumnAt(col)) { + Profiler profiler("FFTDataServer::getMagnitudeAt: filling"); #ifdef DEBUG_FFT_SERVER std::cerr << "FFTDataServer::getMagnitudeAt: calling fillColumn(" << x << ")" << std::endl; #endif - fillColumn(x); + // hold mutex so that write thread doesn't mess with class + // member data in fillColumn + MutexLocker locker(&m_writeMutex, + "FFTDataServer::getMagnitudeAt: m_writeMutex"); + fillColumn(x, true); } return cache->getMagnitudeAt(col, y); } +bool +FFTDataServer::getMagnitudesAt(size_t x, float *values, size_t minbin, size_t count, size_t step) +{ + Profiler profiler("FFTDataServer::getMagnitudesAt", false); + + if (x >= m_width) return false; + + if (minbin >= m_height) minbin = m_height - 1; + if (count == 0) count = (m_height - minbin) / step; + else if (minbin + count * step > m_height) { + count = (m_height - minbin) / step; + } + + size_t col; + FFTCache *cache = getCache(x, col); + if (!cache) return false; + + if (!cache->haveSetColumnAt(col)) { + Profiler profiler("FFTDataServer::getMagnitudesAt: filling"); + MutexLocker locker(&m_writeMutex, + "FFTDataServer::getMagnitudesAt: m_writeMutex"); + fillColumn(x, true); + } + + for (size_t i = 0; i < count; ++i) { + values[i] = cache->getMagnitudeAt(col, i * step + minbin); + } + + return true; +} + float FFTDataServer::getNormalizedMagnitudeAt(size_t x, size_t y) { @@ -896,11 +932,47 @@ if (!cache) return 0; if (!cache->haveSetColumnAt(col)) { - fillColumn(x); + Profiler profiler("FFTDataServer::getNormalizedMagnitudeAt: filling"); + // hold mutex so that write thread doesn't mess with class + // member data in fillColumn + MutexLocker locker(&m_writeMutex, + "FFTDataServer::getNormalizedMagnitudeAt: m_writeMutex"); + fillColumn(x, true); } return cache->getNormalizedMagnitudeAt(col, y); } +bool +FFTDataServer::getNormalizedMagnitudesAt(size_t x, float *values, size_t minbin, size_t count, size_t step) +{ + Profiler profiler("FFTDataServer::getNormalizedMagnitudesAt", false); + + if (x >= m_width) return false; + + if (minbin >= m_height) minbin = m_height - 1; + if (count == 0) count = (m_height - minbin) / step; + else if (minbin + count * step > m_height) { + count = (m_height - minbin) / step; + } + + size_t col; + FFTCache *cache = getCache(x, col); + if (!cache) return false; + + if (!cache->haveSetColumnAt(col)) { + Profiler profiler("FFTDataServer::getNormalizedMagnitudesAt: filling"); + MutexLocker locker(&m_writeMutex, + "FFTDataServer::getNormalizedMagnitudesAt: m_writeMutex"); + fillColumn(x, true); + } + + for (size_t i = 0; i < count; ++i) { + values[i] = cache->getNormalizedMagnitudeAt(col, i * step + minbin); + } + + return true; +} + float FFTDataServer::getMaximumMagnitudeAt(size_t x) { @@ -913,7 +985,12 @@ if (!cache) return 0; if (!cache->haveSetColumnAt(col)) { - fillColumn(x); + Profiler profiler("FFTDataServer::getMaximumMagnitudeAt: filling"); + // hold mutex so that write thread doesn't mess with class + // member data in fillColumn + MutexLocker locker(&m_writeMutex, + "FFTDataServer::getMaximumMagnitudeAt: m_writeMutex"); + fillColumn(x, true); } return cache->getMaximumMagnitudeAt(col); } @@ -930,11 +1007,47 @@ if (!cache) return 0; if (!cache->haveSetColumnAt(col)) { - fillColumn(x); + Profiler profiler("FFTDataServer::getPhaseAt: filling"); + // hold mutex so that write thread doesn't mess with class + // member data in fillColumn + MutexLocker locker(&m_writeMutex, + "FFTDataServer::getPhaseAt: m_writeMutex"); + fillColumn(x, true); } return cache->getPhaseAt(col, y); } +bool +FFTDataServer::getPhasesAt(size_t x, float *values, size_t minbin, size_t count, size_t step) +{ + Profiler profiler("FFTDataServer::getPhasesAt", false); + + if (x >= m_width) return false; + + if (minbin >= m_height) minbin = m_height - 1; + if (count == 0) count = (m_height - minbin) / step; + else if (minbin + count * step > m_height) { + count = (m_height - minbin) / step; + } + + size_t col; + FFTCache *cache = getCache(x, col); + if (!cache) return false; + + if (!cache->haveSetColumnAt(col)) { + Profiler profiler("FFTDataServer::getPhasesAt: filling"); + MutexLocker locker(&m_writeMutex, + "FFTDataServer::getPhasesAt: m_writeMutex"); + fillColumn(x, true); + } + + for (size_t i = 0; i < count; ++i) { + values[i] = cache->getPhaseAt(col, i * step + minbin); + } + + return true; +} + void FFTDataServer::getValuesAt(size_t x, size_t y, float &real, float &imaginary) { @@ -956,10 +1069,15 @@ } if (!cache->haveSetColumnAt(col)) { + Profiler profiler("FFTDataServer::getValuesAt: filling"); #ifdef DEBUG_FFT_SERVER std::cerr << "FFTDataServer::getValuesAt(" << x << ", " << y << "): filling" << std::endl; #endif - fillColumn(x); + // hold mutex so that write thread doesn't mess with class + // member data in fillColumn + MutexLocker locker(&m_writeMutex, + "FFTDataServer::getValuesAt: m_writeMutex"); + fillColumn(x, true); } cache->getValuesAt(col, y, real, imaginary); @@ -991,7 +1109,7 @@ } void -FFTDataServer::fillColumn(size_t x) +FFTDataServer::fillColumn(size_t x, bool lockHeld) { Profiler profiler("FFTDataServer::fillColumn", false); @@ -1022,28 +1140,37 @@ FFTCache *cache = getCache(x, col); if (!cache) return; - MutexLocker locker(&m_writeMutex, - "FFTDataServer::m_writeMutex[fillColumn]"); + { + MutexLocker locker(lockHeld ? 0 : &m_writeMutex, + "FFTDataServer::fillColumn::m_writeMutex [1]"); - if (cache->haveSetColumnAt(col)) return; + if (cache->haveSetColumnAt(col)) return; + } + + int winsize = m_windowSize; + int fftsize = m_fftSize; + int hs = fftsize/2; + + int pfx = 0; + int off = (fftsize - winsize) / 2; int startFrame = m_windowIncrement * x; int endFrame = startFrame + m_windowSize; - startFrame -= int(m_windowSize) / 2; - endFrame -= int(m_windowSize) / 2; - size_t pfx = 0; + startFrame -= winsize / 2; + endFrame -= winsize / 2; - size_t off = (m_fftSize - m_windowSize) / 2; + for (int i = 0; i < off; ++i) { + m_fftInput[i] = 0.0; + } - for (size_t i = 0; i < off; ++i) { - m_fftInput[i] = 0.0; - m_fftInput[m_fftSize - i - 1] = 0.0; + for (int i = 0; i < off; ++i) { + m_fftInput[fftsize - i - 1] = 0.0; } if (startFrame < 0) { - pfx = size_t(-startFrame); - for (size_t i = 0; i < pfx; ++i) { + pfx = -startFrame; + for (int i = 0; i < pfx; ++i) { m_fftInput[off + i] = 0.0; } } @@ -1057,13 +1184,13 @@ << " from channel " << m_channel << std::endl; #endif - size_t count = 0; + int count = 0; if (endFrame > startFrame + pfx) count = endFrame - (startFrame + pfx); - size_t got = m_model->getData(m_channel, startFrame + pfx, - count, m_fftInput + off + pfx); + int got = m_model->getData(m_channel, startFrame + pfx, + count, m_fftInput + off + pfx); - while (got + pfx < m_windowSize) { + while (got + pfx < winsize) { m_fftInput[off + got + pfx] = 0.0; ++got; } @@ -1071,7 +1198,7 @@ if (m_channel == -1) { int channels = m_model->getChannelCount(); if (channels > 1) { - for (size_t i = 0; i < m_windowSize; ++i) { + for (int i = 0; i < winsize; ++i) { m_fftInput[off + i] /= channels; } } @@ -1079,25 +1206,60 @@ m_windower.cut(m_fftInput + off); - for (size_t i = 0; i < m_fftSize/2; ++i) { + for (int i = 0; i < hs; ++i) { fftsample temp = m_fftInput[i]; - m_fftInput[i] = m_fftInput[i + m_fftSize/2]; - m_fftInput[i + m_fftSize/2] = temp; + m_fftInput[i] = m_fftInput[i + hs]; + m_fftInput[i + hs] = temp; } fftf_execute(m_fftPlan); - fftsample factor = 0.0; + // If our cache uses polar storage, it's more friendly for us to + // do the conversion before taking the write mutex - for (size_t i = 0; i <= m_fftSize/2; ++i) { + float factor = 0.f; - m_workbuffer[i] = m_fftOutput[i][0]; - m_workbuffer[i + m_fftSize/2 + 1] = m_fftOutput[i][1]; + if (cache->getStorageType() == FFTCache::Compact || + cache->getStorageType() == FFTCache::Polar) { + + for (int i = 0; i <= hs; ++i) { + fftsample real = m_fftOutput[i][0]; + fftsample imag = m_fftOutput[i][1]; + float mag = sqrtf(real * real + imag * imag); + m_workbuffer[i] = mag; + m_workbuffer[i + hs + 1] = atan2f(imag, real); + if (mag > factor) factor = mag; + } + + } else { + + for (int i = 0; i <= hs; ++i) { + m_workbuffer[i] = m_fftOutput[i][0]; + m_workbuffer[i + hs + 1] = m_fftOutput[i][1]; + } } - cache->setColumnAt(col, - m_workbuffer, - m_workbuffer + m_fftSize/2+1); + Profiler subprof("FFTDataServer::fillColumn: set to cache"); + + { + MutexLocker locker(lockHeld ? 0 : &m_writeMutex, + "FFTDataServer::fillColumn: m_writeMutex [2]"); + + if (cache->getStorageType() == FFTCache::Compact || + cache->getStorageType() == FFTCache::Polar) { + + cache->setColumnAt(col, + m_workbuffer, + m_workbuffer + hs + 1, + factor); + + } else { + + cache->setColumnAt(col, + m_workbuffer, + m_workbuffer + hs + 1); + } + } if (m_suspended) { // std::cerr << "FFTDataServer::fillColumn(" << x << "): calling resume" << std::endl; @@ -1174,7 +1336,8 @@ for (size_t f = m_fillFrom; f < end; f += m_server.m_windowIncrement) { - m_server.fillColumn(int((f - start) / m_server.m_windowIncrement)); + m_server.fillColumn(int((f - start) / m_server.m_windowIncrement), + false); if (m_server.m_exiting) return; @@ -1184,7 +1347,7 @@ #endif { MutexLocker locker(&m_server.m_writeMutex, - "FFTDataServer::m_writeMutex[run/1]"); + "FFTDataServer::run::m_writeMutex [1]"); m_server.m_condition.wait(&m_server.m_writeMutex, 10000); } #ifdef DEBUG_FFT_SERVER @@ -1214,7 +1377,8 @@ for (size_t f = start; f < remainingEnd; f += m_server.m_windowIncrement) { - m_server.fillColumn(int((f - start) / m_server.m_windowIncrement)); + m_server.fillColumn(int((f - start) / m_server.m_windowIncrement), + false); if (m_server.m_exiting) return; @@ -1224,7 +1388,7 @@ #endif { MutexLocker locker(&m_server.m_writeMutex, - "FFTDataServer::m_writeMutex[run/2]"); + "FFTDataServer::run::m_writeMutex [2]"); m_server.m_condition.wait(&m_server.m_writeMutex, 10000); } if (m_server.m_exiting) return;