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;