changeset 548:1469caaa8e67

* Finer locking in fft caches; fix displayed bin ranges in spectrogram
author Chris Cannam
date Thu, 05 Feb 2009 12:05:28 +0000
parents 806e3c72b5df
children 388afa99d537
files base/ResizeableBitset.h data/fft/FFTDataServer.cpp data/fft/FFTDataServer.h data/fft/FFTMemoryCache.cpp data/fft/FFTMemoryCache.h data/fileio/MatrixFile.cpp data/model/Dense3DModelPeakCache.cpp
diffstat 7 files changed, 43 insertions(+), 20 deletions(-) [+]
line wrap: on
line diff
--- a/base/ResizeableBitset.h	Wed Feb 04 20:39:11 2009 +0000
+++ b/base/ResizeableBitset.h	Thu Feb 05 12:05:28 2009 +0000
@@ -40,13 +40,19 @@
         delete m_bits;
     }
     
-    void resize(size_t bits) { // losing all data
-        if (!m_bits || bits < m_bits->size()) {
+    void resize(size_t size) { // retaining existing data; not thread safe
+        size_t bytes = (size >> 3) + 1;
+        if (m_bits && bytes == m_bits->size()) return;
+        std::vector<uint8_t> *newbits = new std::vector<uint8_t>(bytes);
+        newbits->assign(bytes, 0);
+        if (m_bits) {
+            for (size_t i = 0; i < bytes && i < m_bits->size(); ++i) {
+                (*newbits)[i] = (*m_bits)[i];
+            }
             delete m_bits;
-            m_bits = new std::vector<uint8_t>;
         }
-        m_bits->assign((bits >> 3) + 1, 0);
-        m_size = bits;
+        m_bits = newbits;
+        m_size = size;
     }
     
     bool get(size_t column) const {
--- a/data/fft/FFTDataServer.cpp	Wed Feb 04 20:39:11 2009 +0000
+++ b/data/fft/FFTDataServer.cpp	Thu Feb 05 12:05:28 2009 +0000
@@ -738,13 +738,25 @@
 bool
 FFTDataServer::makeCache(int c)
 {
-    QWriteLocker locker(&m_cacheVectorLock);
+    // Creating the cache could take a significant amount of time.  We
+    // don't want to block readers on m_cacheVectorLock while this is
+    // happening, but we do want to block any further calls to
+    // makeCache.  So we use this lock solely to serialise this
+    // particular function -- it isn't used anywhere else.
 
+    QMutexLocker locker(&m_cacheCreationMutex);
+
+    m_cacheVectorLock.lockForRead();
     if (m_caches[c]) {
         // someone else must have created the cache between our
-        // testing for it and taking the write lock
+        // testing for it and taking the mutex
+        m_cacheVectorLock.unlock();
         return true;
     }
+    m_cacheVectorLock.unlock();
+
+    // Now m_cacheCreationMutex is held, but m_cacheVectorLock is not
+    // -- readers can proceed, but callers to this function will block
 
     CacheBlock *cb = new CacheBlock;
 
@@ -811,8 +823,12 @@
         }
     }
 
+    m_cacheVectorLock.lockForWrite();
+
     m_caches[c] = cb;
 
+    m_cacheVectorLock.unlock();
+
     return success;
 }
  
--- a/data/fft/FFTDataServer.h	Wed Feb 04 20:39:11 2009 +0000
+++ b/data/fft/FFTDataServer.h	Thu Feb 05 12:05:28 2009 +0000
@@ -163,6 +163,7 @@
     typedef std::vector<CacheBlock *> CacheVector;
     CacheVector m_caches;
     QReadWriteLock m_cacheVectorLock; // locks cache lookup, not use
+    QMutex m_cacheCreationMutex; // solely to serialise makeCache() calls
 
     FFTCacheReader *getCacheReader(size_t x, size_t &col) {
         Profiler profiler("FFTDataServer::getCacheReader");
@@ -217,7 +218,7 @@
 
     bool haveCache(size_t x) {
         int c = x >> m_cacheWidthPower;
-        return (m_caches[c] != 0);
+        return (m_caches.at(c) != 0);
     }
     
     bool makeCache(int c);
--- a/data/fft/FFTMemoryCache.cpp	Wed Feb 04 20:39:11 2009 +0000
+++ b/data/fft/FFTMemoryCache.cpp	Thu Feb 05 12:05:28 2009 +0000
@@ -148,9 +148,9 @@
         }
     }
 
-    m_colsetMutex.lock();
+    m_colsetLock.lockForWrite();
     m_colset.set(x);
-    m_colsetMutex.unlock();
+    m_colsetLock.unlock();
 }
 
 void
@@ -188,9 +188,9 @@
 
     if (m_storageType == FFTCache::Rectangular) {
         m_factor[x] = max;
-        m_colsetMutex.lock();
+        m_colsetLock.lockForWrite();
         m_colset.set(x);
-        m_colsetMutex.unlock();
+        m_colsetLock.unlock();
     } else {
         setColumnAt(x, reals, imags, max);
     }
--- a/data/fft/FFTMemoryCache.h	Wed Feb 04 20:39:11 2009 +0000
+++ b/data/fft/FFTMemoryCache.h	Thu Feb 05 12:05:28 2009 +0000
@@ -22,7 +22,7 @@
 #include "base/ResizeableBitset.h"
 #include "base/Profiler.h"
 
-#include <QMutex>
+#include <QReadWriteLock>
 
 /**
  * In-memory FFT cache.  For this we want to cache magnitude with
@@ -120,9 +120,9 @@
     }
 
     bool haveSetColumnAt(size_t x) const {
-        m_colsetMutex.lock();
+        m_colsetLock.lockForRead();
         bool have = m_colset.get(x);
-        m_colsetMutex.unlock();
+        m_colsetLock.unlock();
         return have;
     }
 
@@ -149,7 +149,7 @@
     float *m_factor;
     FFTCache::StorageType m_storageType;
     ResizeableBitset m_colset;
-    mutable QMutex m_colsetMutex;
+    mutable QReadWriteLock m_colsetLock;
 
     void initialise();
 
--- a/data/fileio/MatrixFile.cpp	Wed Feb 04 20:39:11 2009 +0000
+++ b/data/fileio/MatrixFile.cpp	Thu Feb 05 12:05:28 2009 +0000
@@ -68,7 +68,7 @@
     std::cerr << "MatrixFile::MatrixFile(" << fileBase.toStdString() << ", " << int(mode) << ", " << cellSize << ", " << width << ", " << height << ")" << std::endl;
 #endif
 
-    QMutexLocker locker(&m_createMutex);
+    m_createMutex.lock();
 
     QDir tempDir(TempDirectory::getInstance()->getPath());
     QString fileName(tempDir.filePath(QString("%1.mfc").arg(fileBase)));
@@ -113,6 +113,8 @@
         throw FailedToOpenFile(fileName);
     }
 
+    m_createMutex.unlock();
+
 #ifdef DEBUG_MATRIX_FILE
     std::cerr << "MatrixFile(" << this << ")::MatrixFile: fd is " << m_fd << std::endl;
 #endif
--- a/data/model/Dense3DModelPeakCache.cpp	Wed Feb 04 20:39:11 2009 +0000
+++ b/data/model/Dense3DModelPeakCache.cpp	Thu Feb 05 12:05:28 2009 +0000
@@ -79,9 +79,7 @@
         // may since have been filled, so reset it
         m_coverage.reset(m_coverage.size()-1);
     }
-    if (getWidth() > m_coverage.size()) {
-        m_coverage.resize(getWidth()); // clears all bits, which is OK with us
-    }
+    m_coverage.resize(getWidth()); // retaining data
 }
 
 void