Mercurial > hg > svcore
comparison data/fileio/MatrixFile.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 | 65311fb86166 |
children | 52303ec15cd2 |
comparison
equal
deleted
inserted
replaced
407:88ad01799040 | 408:115f60df1e4d |
---|---|
16 #include "MatrixFile.h" | 16 #include "MatrixFile.h" |
17 #include "base/TempDirectory.h" | 17 #include "base/TempDirectory.h" |
18 #include "system/System.h" | 18 #include "system/System.h" |
19 #include "base/Profiler.h" | 19 #include "base/Profiler.h" |
20 #include "base/Exceptions.h" | 20 #include "base/Exceptions.h" |
21 #include "base/Thread.h" | |
21 | 22 |
22 #include <sys/types.h> | 23 #include <sys/types.h> |
23 #include <sys/stat.h> | 24 #include <sys/stat.h> |
24 #include <fcntl.h> | 25 #include <fcntl.h> |
25 #include <unistd.h> | 26 #include <unistd.h> |
147 seekTo(0, 0); | 148 seekTo(0, 0); |
148 } | 149 } |
149 | 150 |
150 m_fileName = fileName; | 151 m_fileName = fileName; |
151 | 152 |
152 m_columnBitsetWriteMutex.lock(); | 153 { |
153 | 154 MutexLocker locker |
154 if (m_columnBitsets.find(m_fileName) == m_columnBitsets.end()) { | 155 (&m_columnBitsetWriteMutex, |
155 m_columnBitsets[m_fileName] = new ResizeableBitset; | 156 "MatrixFile::MatrixFile::m_columnBitsetWriteMutex"); |
156 } | 157 |
157 m_columnBitset = m_columnBitsets[m_fileName]; | 158 if (m_columnBitsets.find(m_fileName) == m_columnBitsets.end()) { |
158 | 159 m_columnBitsets[m_fileName] = new ResizeableBitset; |
159 m_columnBitsetWriteMutex.unlock(); | 160 } |
160 | 161 m_columnBitset = m_columnBitsets[m_fileName]; |
161 QMutexLocker locker(&m_refcountMutex); | 162 } |
163 | |
164 MutexLocker locker(&m_refcountMutex, | |
165 "MatrixFile::MatrixFile::m_refcountMutex"); | |
162 ++m_refcount[fileName]; | 166 ++m_refcount[fileName]; |
163 | 167 |
164 // std::cerr << "MatrixFile(" << this << "): fd " << m_fd << ", file " << fileName.toStdString() << ", ref " << m_refcount[fileName] << std::endl; | 168 // std::cerr << "MatrixFile(" << this << "): fd " << m_fd << ", file " << fileName.toStdString() << ", ref " << m_refcount[fileName] << std::endl; |
165 | 169 |
166 // std::cerr << "MatrixFile::MatrixFile: Done, size is " << "(" << m_width << ", " << m_height << ")" << std::endl; | 170 // std::cerr << "MatrixFile::MatrixFile: Done, size is " << "(" << m_width << ", " << m_height << ")" << std::endl; |
191 } | 195 } |
192 } | 196 } |
193 | 197 |
194 if (m_fileName != "") { | 198 if (m_fileName != "") { |
195 | 199 |
196 QMutexLocker locker(&m_refcountMutex); | 200 MutexLocker locker(&m_refcountMutex, |
201 "MatrixFile::~MatrixFile::m_refcountMutex"); | |
197 | 202 |
198 if (--m_refcount[m_fileName] == 0) { | 203 if (--m_refcount[m_fileName] == 0) { |
199 | 204 |
200 if (::unlink(m_fileName.toLocal8Bit())) { | 205 if (::unlink(m_fileName.toLocal8Bit())) { |
201 // ::perror("Unlink failed"); | 206 // ::perror("Unlink failed"); |
202 // std::cerr << "WARNING: MatrixFile::~MatrixFile: reference count reached 0, but failed to unlink file \"" << m_fileName.toStdString() << "\"" << std::endl; | 207 // std::cerr << "WARNING: MatrixFile::~MatrixFile: reference count reached 0, but failed to unlink file \"" << m_fileName.toStdString() << "\"" << std::endl; |
203 } else { | 208 } else { |
204 // std::cerr << "deleted " << m_fileName.toStdString() << std::endl; | 209 // std::cerr << "deleted " << m_fileName.toStdString() << std::endl; |
205 } | 210 } |
206 | 211 |
207 QMutexLocker locker2(&m_columnBitsetWriteMutex); | 212 MutexLocker locker2 |
213 (&m_columnBitsetWriteMutex, | |
214 "MatrixFile::~MatrixFile::m_columnBitsetWriteMutex"); | |
208 m_columnBitsets.erase(m_fileName); | 215 m_columnBitsets.erase(m_fileName); |
209 delete m_columnBitset; | 216 delete m_columnBitset; |
210 } | 217 } |
211 } | 218 } |
212 | 219 |
225 { | 232 { |
226 Profiler profiler("MatrixFile::resize", true); | 233 Profiler profiler("MatrixFile::resize", true); |
227 | 234 |
228 assert(m_mode == ReadWrite); | 235 assert(m_mode == ReadWrite); |
229 | 236 |
230 QMutexLocker locker(&m_fdMutex); | 237 MutexLocker locker(&m_fdMutex, "MatrixFile::resize::m_fdMutex"); |
231 | 238 |
232 totalStorage -= (m_headerSize + (m_width * m_height * m_cellSize)); | 239 totalStorage -= (m_headerSize + (m_width * m_height * m_cellSize)); |
233 totalMemory -= (2 * m_defaultCacheWidth * m_height * m_cellSize); | 240 totalMemory -= (2 * m_defaultCacheWidth * m_height * m_cellSize); |
234 | 241 |
235 off_t off = m_headerSize + (w * h * m_cellSize); | 242 off_t off = m_headerSize + (w * h * m_cellSize); |
270 m_defaultCacheWidth = (maxCacheMB * 1024 * 1024) / (2 * h * m_cellSize); | 277 m_defaultCacheWidth = (maxCacheMB * 1024 * 1024) / (2 * h * m_cellSize); |
271 if (m_defaultCacheWidth < 16) m_defaultCacheWidth = 16; | 278 if (m_defaultCacheWidth < 16) m_defaultCacheWidth = 16; |
272 } | 279 } |
273 | 280 |
274 if (m_columnBitset) { | 281 if (m_columnBitset) { |
275 QMutexLocker locker(&m_columnBitsetWriteMutex); | 282 MutexLocker locker(&m_columnBitsetWriteMutex, |
283 "MatrixFile::resize::m_columnBitsetWriteMutex"); | |
276 m_columnBitset->resize(w); | 284 m_columnBitset->resize(w); |
277 } | 285 } |
278 | 286 |
279 if (m_cache.data) { | 287 if (m_cache.data) { |
280 free(m_cache.data); | 288 free(m_cache.data); |
317 for (size_t x = 0; x < m_width; ++x) setColumnAt(x, emptyCol); | 325 for (size_t x = 0; x < m_width; ++x) setColumnAt(x, emptyCol); |
318 free(emptyCol); | 326 free(emptyCol); |
319 } | 327 } |
320 | 328 |
321 if (m_columnBitset) { | 329 if (m_columnBitset) { |
322 QMutexLocker locker(&m_columnBitsetWriteMutex); | 330 MutexLocker locker(&m_columnBitsetWriteMutex, |
331 "MatrixFile::reset::m_columnBitsetWriteMutex"); | |
323 m_columnBitset->resize(m_width); | 332 m_columnBitset->resize(m_width); |
324 } | 333 } |
325 } | 334 } |
326 | 335 |
327 void | 336 void |
328 MatrixFile::getColumnAt(size_t x, void *data) | 337 MatrixFile::getColumnAt(size_t x, void *data) |
329 { | 338 { |
330 // Profiler profiler("MatrixFile::getColumnAt"); | 339 Profiler profiler("MatrixFile::getColumnAt"); |
331 | 340 |
332 // assert(haveSetColumnAt(x)); | 341 // assert(haveSetColumnAt(x)); |
333 | 342 |
334 if (getFromCache(x, 0, m_height, data)) return; | 343 if (getFromCache(x, 0, m_height, data)) return; |
335 | 344 |
336 // Profiler profiler2("MatrixFile::getColumnAt (uncached)"); | 345 Profiler profiler2("MatrixFile::getColumnAt (uncached)"); |
337 | 346 |
338 ssize_t r = 0; | 347 ssize_t r = 0; |
339 | 348 |
340 #ifdef DEBUG_MATRIX_FILE | 349 #ifdef DEBUG_MATRIX_FILE |
341 std::cerr << "MatrixFile::getColumnAt(" << x << ")" | 350 std::cerr << "MatrixFile::getColumnAt(" << x << ")" |
349 } | 358 } |
350 | 359 |
351 std::cerr << std::endl; | 360 std::cerr << std::endl; |
352 #endif | 361 #endif |
353 | 362 |
354 m_fdMutex.lock(); | 363 { |
355 | 364 MutexLocker locker(&m_fdMutex, "MatrixFile::getColumnAt::m_fdMutex"); |
356 if (seekTo(x, 0)) { | 365 |
357 r = ::read(m_fd, data, m_height * m_cellSize); | 366 if (seekTo(x, 0)) { |
358 } | 367 r = ::read(m_fd, data, m_height * m_cellSize); |
359 | 368 } |
360 m_fdMutex.unlock(); | 369 } |
361 | 370 |
362 if (r < 0) { | 371 if (r < 0) { |
363 ::perror("MatrixFile::getColumnAt: read failed"); | 372 ::perror("MatrixFile::getColumnAt: read failed"); |
364 std::cerr << "ERROR: MatrixFile::getColumnAt: " | 373 std::cerr << "ERROR: MatrixFile::getColumnAt: " |
365 << "Failed to read column " << x << " (height " << m_height << ", cell size " << m_cellSize << ", fd " << m_fd << ", file \"" | 374 << "Failed to read column " << x << " (height " << m_height << ", cell size " << m_cellSize << ", fd " << m_fd << ", file \"" |
371 } | 380 } |
372 | 381 |
373 bool | 382 bool |
374 MatrixFile::getFromCache(size_t x, size_t ystart, size_t ycount, void *data) | 383 MatrixFile::getFromCache(size_t x, size_t ystart, size_t ycount, void *data) |
375 { | 384 { |
376 m_cacheMutex.lock(); | 385 bool fail = false; |
377 | 386 bool primeLeft = false; |
378 if (!m_cache.data || x < m_cache.x || x >= m_cache.x + m_cache.width) { | 387 |
379 bool left = (m_cache.data && x < m_cache.x); | 388 { |
380 m_cacheMutex.unlock(); | 389 MutexLocker locker(&m_cacheMutex, |
381 primeCache(x, left); // this doesn't take effect until a later callback | 390 "MatrixFile::getFromCache::m_cacheMutex"); |
391 | |
392 if (!m_cache.data || x < m_cache.x || x >= m_cache.x + m_cache.width) { | |
393 fail = true; | |
394 primeLeft = (m_cache.data && x < m_cache.x); | |
395 } else { | |
396 memcpy(data, | |
397 m_cache.data + m_cellSize * ((x - m_cache.x) * m_height + ystart), | |
398 ycount * m_cellSize); | |
399 } | |
400 } | |
401 | |
402 if (fail) { | |
403 primeCache(x, primeLeft); // this doesn't take effect until a later callback | |
382 m_prevX = x; | 404 m_prevX = x; |
383 return false; | 405 return false; |
384 } | 406 } |
385 | |
386 memcpy(data, | |
387 m_cache.data + m_cellSize * ((x - m_cache.x) * m_height + ystart), | |
388 ycount * m_cellSize); | |
389 | |
390 m_cacheMutex.unlock(); | |
391 | 407 |
392 if (m_cache.x > 0 && x < m_prevX && x < m_cache.x + m_cache.width/4) { | 408 if (m_cache.x > 0 && x < m_prevX && x < m_cache.x + m_cache.width/4) { |
393 primeCache(x, true); | 409 primeCache(x, true); |
394 } | 410 } |
395 | 411 |
412 std::cerr << "MatrixFile::setColumnAt(" << x << ")" << std::endl; | 428 std::cerr << "MatrixFile::setColumnAt(" << x << ")" << std::endl; |
413 #endif | 429 #endif |
414 | 430 |
415 ssize_t w = 0; | 431 ssize_t w = 0; |
416 bool seekFailed = false; | 432 bool seekFailed = false; |
417 | 433 |
418 m_fdMutex.lock(); | 434 { |
419 | 435 MutexLocker locker(&m_fdMutex, "MatrixFile::setColumnAt::m_fdMutex"); |
420 if (seekTo(x, 0)) { | 436 |
421 w = ::write(m_fd, data, m_height * m_cellSize); | 437 if (seekTo(x, 0)) { |
422 } else { | 438 w = ::write(m_fd, data, m_height * m_cellSize); |
423 seekFailed = true; | 439 } else { |
424 } | 440 seekFailed = true; |
425 | 441 } |
426 m_fdMutex.unlock(); | 442 } |
427 | 443 |
428 if (!seekFailed && w != ssize_t(m_height * m_cellSize)) { | 444 if (!seekFailed && w != ssize_t(m_height * m_cellSize)) { |
429 ::perror("WARNING: MatrixFile::setColumnAt: write failed"); | 445 ::perror("WARNING: MatrixFile::setColumnAt: write failed"); |
430 throw FileOperationFailed(m_fileName, "write"); | 446 throw FileOperationFailed(m_fileName, "write"); |
431 } else if (seekFailed) { | 447 } else if (seekFailed) { |
432 throw FileOperationFailed(m_fileName, "seek"); | 448 throw FileOperationFailed(m_fileName, "seek"); |
433 } else { | 449 } else { |
434 QMutexLocker locker(&m_columnBitsetWriteMutex); | 450 MutexLocker locker |
451 (&m_columnBitsetWriteMutex, | |
452 "MatrixFile::setColumnAt::m_columnBitsetWriteMutex"); | |
435 m_columnBitset->set(x); | 453 m_columnBitset->set(x); |
436 } | 454 } |
437 } | 455 } |
438 | 456 |
439 void | 457 void |
440 MatrixFile::suspend() | 458 MatrixFile::suspend() |
441 { | 459 { |
442 QMutexLocker locker(&m_fdMutex); | 460 MutexLocker locker(&m_fdMutex, "MatrixFile::suspend::m_fdMutex"); |
443 QMutexLocker locker2(&m_cacheMutex); | 461 MutexLocker locker2(&m_cacheMutex, "MatrixFile::suspend::m_cacheMutex"); |
444 | 462 |
445 if (m_fd < 0) return; // already suspended | 463 if (m_fd < 0) return; // already suspended |
446 | 464 |
447 #ifdef DEBUG_MATRIX_FILE | 465 #ifdef DEBUG_MATRIX_FILE |
448 std::cerr << "MatrixFile(" << this << ":" << m_fileName.toStdString() << ")::suspend(): fd was " << m_fd << std::endl; | 466 std::cerr << "MatrixFile(" << this << ":" << m_fileName.toStdString() << ")::suspend(): fd was " << m_fd << std::endl; |
537 | 555 |
538 rw = std::min(rw, ti); | 556 rw = std::min(rw, ti); |
539 if (rw < 10 || rx + rw <= x) return; | 557 if (rw < 10 || rx + rw <= x) return; |
540 } | 558 } |
541 | 559 |
542 QMutexLocker locker(&m_cacheMutex); | 560 MutexLocker locker(&m_cacheMutex, "MatrixFile::primeCache::m_cacheMutex"); |
543 | 561 |
544 FileReadThread::Request request; | 562 FileReadThread::Request request; |
545 | 563 |
546 if (m_requestToken >= 0 && | 564 if (m_requestToken >= 0 && |
547 m_readThread->getRequest(m_requestToken, request)) { | 565 m_readThread->getRequest(m_requestToken, request)) { |
599 | 617 |
600 m_requestToken = -1; | 618 m_requestToken = -1; |
601 } | 619 } |
602 | 620 |
603 if (m_fd < 0) { | 621 if (m_fd < 0) { |
604 m_fdMutex.lock(); | 622 MutexLocker locker(&m_fdMutex, "MatrixFile::primeCache::m_fdMutex"); |
605 if (m_fd < 0) resume(); | 623 if (m_fd < 0) resume(); |
606 m_fdMutex.unlock(); | |
607 } | 624 } |
608 | 625 |
609 request.fd = m_fd; | 626 request.fd = m_fd; |
610 request.mutex = &m_fdMutex; | 627 request.mutex = &m_fdMutex; |
611 request.start = m_headerSize + rx * m_height * m_cellSize; | 628 request.start = m_headerSize + rx * m_height * m_cellSize; |