Mercurial > hg > svcore
comparison data/fft/FFTDataServer.h @ 537:3cc4b7cd2aa5
* Merge from one-fftdataserver-per-fftmodel branch. This bit of
reworking (which is not described very accurately by the title of
the branch) turns the MatrixFile object into something that either
reads or writes, but not both, and separates the FFT file cache
reader and writer implementations separately. This allows the
FFT data server to have a single thread owning writers and one reader
per "customer" thread, and for all locking to be vastly simplified
and concentrated in the data server alone (because none of the
classes it makes use of is used in more than one thread at a time).
The result is faster and more trustworthy code.
author | Chris Cannam |
---|---|
date | Tue, 27 Jan 2009 13:25:10 +0000 |
parents | 115f60df1e4d |
children | a5a17152b6df |
comparison
equal
deleted
inserted
replaced
536:beb51f558e9c | 537:3cc4b7cd2aa5 |
---|---|
19 #include "base/Window.h" | 19 #include "base/Window.h" |
20 #include "base/Thread.h" | 20 #include "base/Thread.h" |
21 #include "base/StorageAdviser.h" | 21 #include "base/StorageAdviser.h" |
22 | 22 |
23 #include "FFTapi.h" | 23 #include "FFTapi.h" |
24 #include "FFTFileCacheReader.h" | |
25 #include "FFTFileCacheWriter.h" | |
26 #include "FFTMemoryCache.h" | |
24 | 27 |
25 #include <QMutex> | 28 #include <QMutex> |
29 #include <QReadWriteLock> | |
30 #include <QReadLocker> | |
26 #include <QWaitCondition> | 31 #include <QWaitCondition> |
27 #include <QString> | 32 #include <QString> |
28 | 33 |
29 #include <vector> | 34 #include <vector> |
30 #include <deque> | 35 #include <deque> |
31 | 36 |
32 class DenseTimeValueModel; | 37 class DenseTimeValueModel; |
33 class Model; | 38 class Model; |
34 class FFTCache; | |
35 | 39 |
36 class FFTDataServer | 40 class FFTDataServer |
37 { | 41 { |
38 public: | 42 public: |
39 static FFTDataServer *getInstance(const DenseTimeValueModel *model, | 43 static FFTDataServer *getInstance(const DenseTimeValueModel *model, |
138 size_t m_height; | 142 size_t m_height; |
139 size_t m_cacheWidth; | 143 size_t m_cacheWidth; |
140 size_t m_cacheWidthPower; | 144 size_t m_cacheWidthPower; |
141 size_t m_cacheWidthMask; | 145 size_t m_cacheWidthMask; |
142 | 146 |
143 int m_lastUsedCache; | 147 struct CacheBlock { |
144 FFTCache *getCache(size_t x, size_t &col) { | 148 FFTMemoryCache *memoryCache; |
145 col = x & m_cacheWidthMask; | 149 typedef std::map<QThread *, FFTFileCacheReader *> ThreadReaderMap; |
150 ThreadReaderMap fileCacheReader; | |
151 FFTFileCacheWriter *fileCacheWriter; | |
152 CacheBlock() : memoryCache(0), fileCacheWriter(0) { } | |
153 ~CacheBlock() { | |
154 delete memoryCache; | |
155 while (!fileCacheReader.empty()) { | |
156 delete fileCacheReader.begin()->second; | |
157 fileCacheReader.erase(fileCacheReader.begin()); | |
158 } | |
159 delete fileCacheWriter; | |
160 } | |
161 }; | |
162 | |
163 typedef std::vector<CacheBlock *> CacheVector; | |
164 CacheVector m_caches; | |
165 QReadWriteLock m_cacheVectorLock; // locks cache lookup, not use | |
166 | |
167 FFTCacheReader *getCacheReader(size_t x, size_t &col) { | |
168 Profiler profiler("FFTDataServer::getCacheReader"); | |
169 col = x & m_cacheWidthMask; | |
146 int c = x >> m_cacheWidthPower; | 170 int c = x >> m_cacheWidthPower; |
147 // The only use of m_lastUsedCache without a lock is to | 171 m_cacheVectorLock.lockForRead(); |
148 // establish whether a cache has been created at all (they're | 172 CacheBlock *cb(m_caches.at(c)); |
149 // created on demand, but not destroyed until the server is). | 173 if (cb) { |
150 if (c == m_lastUsedCache) return m_caches[c]; | 174 if (cb->memoryCache) return cb->memoryCache; |
151 else return getCacheAux(c); | 175 if (cb->fileCacheWriter) { |
152 } | 176 QThread *me = QThread::currentThread(); |
177 CacheBlock::ThreadReaderMap &map = cb->fileCacheReader; | |
178 if (map.find(me) == map.end()) { | |
179 m_cacheVectorLock.unlock(); | |
180 if (!makeCacheReader(c)) return 0; | |
181 return getCacheReader(x, col); | |
182 } | |
183 FFTCacheReader *reader = cb->fileCacheReader.at(me); | |
184 m_cacheVectorLock.unlock(); | |
185 return reader; | |
186 } | |
187 // if cb exists but cb->fileCacheWriter doesn't, creation | |
188 // must have failed: don't try again | |
189 m_cacheVectorLock.unlock(); | |
190 return 0; | |
191 } | |
192 m_cacheVectorLock.unlock(); | |
193 if (!makeCache(c)) return 0; | |
194 return getCacheReader(x, col); | |
195 } | |
196 | |
197 FFTCacheWriter *getCacheWriter(size_t x, size_t &col) { | |
198 Profiler profiler("FFTDataServer::getCacheWriter"); | |
199 col = x & m_cacheWidthMask; | |
200 int c = x >> m_cacheWidthPower; | |
201 { | |
202 QReadLocker locker(&m_cacheVectorLock); | |
203 CacheBlock *cb(m_caches.at(c)); | |
204 if (cb) { | |
205 if (cb->memoryCache) return cb->memoryCache; | |
206 if (cb->fileCacheWriter) return cb->fileCacheWriter; | |
207 // if cb exists, creation must have failed: don't try again | |
208 return 0; | |
209 } | |
210 } | |
211 if (!makeCache(c)) return 0; | |
212 return getCacheWriter(x, col); | |
213 } | |
214 | |
153 bool haveCache(size_t x) { | 215 bool haveCache(size_t x) { |
154 int c = x >> m_cacheWidthPower; | 216 int c = x >> m_cacheWidthPower; |
155 if (c == m_lastUsedCache) return true; | 217 return (m_caches[c] != 0); |
156 else return (m_caches[c] != 0); | 218 } |
157 } | 219 |
158 | 220 bool makeCache(int c); |
159 typedef std::vector<FFTCache *> CacheVector; | 221 bool makeCacheReader(int c); |
160 CacheVector m_caches; | 222 |
161 | |
162 typedef std::deque<int> IntQueue; | |
163 IntQueue m_dormantCaches; | |
164 | |
165 StorageAdviser::Criteria m_criteria; | 223 StorageAdviser::Criteria m_criteria; |
166 | 224 |
167 void getStorageAdvice(size_t w, size_t h, bool &memory, bool &compact); | 225 void getStorageAdvice(size_t w, size_t h, bool &memory, bool &compact); |
168 | 226 |
169 FFTCache *getCacheAux(size_t c); | |
170 QMutex m_writeMutex; | 227 QMutex m_writeMutex; |
171 QWaitCondition m_condition; | 228 QWaitCondition m_condition; |
172 | 229 |
173 fftsample *m_fftInput; | 230 fftsample *m_fftInput; |
174 fftf_complex *m_fftOutput; | 231 fftf_complex *m_fftOutput; |
197 bool m_suspended; | 254 bool m_suspended; |
198 FillThread *m_fillThread; | 255 FillThread *m_fillThread; |
199 | 256 |
200 void deleteProcessingData(); | 257 void deleteProcessingData(); |
201 void fillColumn(size_t x, bool lockHeld); | 258 void fillColumn(size_t x, bool lockHeld); |
259 void fillComplete(); | |
202 | 260 |
203 QString generateFileBasename() const; | 261 QString generateFileBasename() const; |
204 static QString generateFileBasename(const DenseTimeValueModel *model, | 262 static QString generateFileBasename(const DenseTimeValueModel *model, |
205 int channel, | 263 int channel, |
206 WindowType windowType, | 264 WindowType windowType, |