Mercurial > hg > svcore
comparison data/fft/FFTDataServer.cpp @ 359:824ee993ca8d
* merge revision 842 from spectrogram-rejig -- attempt to improve disk/memory
allocation in ffts
author | Chris Cannam |
---|---|
date | Tue, 22 Jan 2008 23:11:48 +0000 |
parents | aa8dbac62024 |
children | cc4eb32efc6c 6f6ab834449d |
comparison
equal
deleted
inserted
replaced
358:9203b82a8c53 | 359:824ee993ca8d |
---|---|
28 #include "base/Thread.h" // for debug mutex locker | 28 #include "base/Thread.h" // for debug mutex locker |
29 | 29 |
30 #include <QMessageBox> | 30 #include <QMessageBox> |
31 #include <QApplication> | 31 #include <QApplication> |
32 | 32 |
33 //#define DEBUG_FFT_SERVER 1 | 33 #define DEBUG_FFT_SERVER 1 |
34 //#define DEBUG_FFT_SERVER_FILL 1 | 34 //#define DEBUG_FFT_SERVER_FILL 1 |
35 | 35 |
36 #ifdef DEBUG_FFT_SERVER_FILL | 36 #ifdef DEBUG_FFT_SERVER_FILL |
37 #ifndef DEBUG_FFT_SERVER | 37 #ifndef DEBUG_FFT_SERVER |
38 #define DEBUG_FFT_SERVER 1 | 38 #define DEBUG_FFT_SERVER 1 |
494 m_fftSize(fftSize), | 494 m_fftSize(fftSize), |
495 m_polar(polar), | 495 m_polar(polar), |
496 m_width(0), | 496 m_width(0), |
497 m_height(0), | 497 m_height(0), |
498 m_cacheWidth(0), | 498 m_cacheWidth(0), |
499 m_memoryCache(false), | 499 m_cacheWidthPower(0), |
500 m_compactCache(false), | 500 m_cacheWidthMask(0), |
501 m_lastUsedCache(-1), | 501 m_lastUsedCache(-1), |
502 m_criteria(criteria), | |
502 m_fftInput(0), | 503 m_fftInput(0), |
503 m_exiting(false), | 504 m_exiting(false), |
504 m_suspended(true), //!!! or false? | 505 m_suspended(true), //!!! or false? |
505 m_fillThread(0) | 506 m_fillThread(0) |
506 { | 507 { |
524 size_t maxCacheSize = 20 * 1024 * 1024; | 525 size_t maxCacheSize = 20 * 1024 * 1024; |
525 size_t columnSize = m_height * sizeof(fftsample) * 2 + sizeof(fftsample); | 526 size_t columnSize = m_height * sizeof(fftsample) * 2 + sizeof(fftsample); |
526 if (m_width * columnSize < maxCacheSize * 2) m_cacheWidth = m_width; | 527 if (m_width * columnSize < maxCacheSize * 2) m_cacheWidth = m_width; |
527 else m_cacheWidth = maxCacheSize / columnSize; | 528 else m_cacheWidth = maxCacheSize / columnSize; |
528 | 529 |
530 #ifdef DEBUG_FFT_SERVER | |
531 std::cerr << "FFTDataServer(" << this << "): cache width nominal " | |
532 << m_cacheWidth << ", actual "; | |
533 #endif | |
534 | |
529 int bits = 0; | 535 int bits = 0; |
530 while (m_cacheWidth) { m_cacheWidth >>= 1; ++bits; } | 536 while (m_cacheWidth > 1) { m_cacheWidth >>= 1; ++bits; } |
537 m_cacheWidthPower = bits + 1; | |
531 m_cacheWidth = 2; | 538 m_cacheWidth = 2; |
532 while (bits) { m_cacheWidth <<= 1; --bits; } | 539 while (bits) { m_cacheWidth <<= 1; --bits; } |
533 | 540 m_cacheWidthMask = m_cacheWidth - 1; |
534 if (criteria == StorageAdviser::NoCriteria) { | 541 |
542 #ifdef DEBUG_FFT_SERVER | |
543 std::cerr << m_cacheWidth << " (power " << m_cacheWidthPower << ", mask " | |
544 << m_cacheWidthMask << ")" << std::endl; | |
545 #endif | |
546 | |
547 if (m_criteria == StorageAdviser::NoCriteria) { | |
535 | 548 |
536 // assume "spectrogram" criteria for polar ffts, and "feature | 549 // assume "spectrogram" criteria for polar ffts, and "feature |
537 // extraction" criteria for rectangular ones. | 550 // extraction" criteria for rectangular ones. |
538 | 551 |
539 if (m_polar) { | 552 if (m_polar) { |
540 criteria = StorageAdviser::Criteria | 553 m_criteria = StorageAdviser::Criteria |
541 (StorageAdviser::SpeedCritical | | 554 (StorageAdviser::SpeedCritical | |
542 StorageAdviser::LongRetentionLikely); | 555 StorageAdviser::LongRetentionLikely); |
543 } else { | 556 } else { |
544 criteria = StorageAdviser::Criteria | 557 m_criteria = StorageAdviser::Criteria |
545 (StorageAdviser::PrecisionCritical); | 558 (StorageAdviser::PrecisionCritical); |
546 } | 559 } |
547 } | 560 } |
548 | |
549 int cells = m_width * m_height; | |
550 int minimumSize = (cells / 1024) * sizeof(uint16_t); // kb | |
551 int maximumSize = (cells / 1024) * sizeof(float); // kb | |
552 | |
553 // We don't have a compact rectangular representation, and compact | |
554 // of course is never precision-critical | |
555 bool canCompact = true; | |
556 if ((criteria & StorageAdviser::PrecisionCritical) || !m_polar) { | |
557 canCompact = false; | |
558 minimumSize = maximumSize; // don't use compact | |
559 } | |
560 | |
561 StorageAdviser::Recommendation recommendation; | |
562 | |
563 try { | |
564 | |
565 recommendation = | |
566 StorageAdviser::recommend(criteria, minimumSize, maximumSize); | |
567 | |
568 } catch (InsufficientDiscSpace s) { | |
569 | |
570 // Delete any unused servers we may have been leaving around | |
571 // in case we wanted them again | |
572 | |
573 purgeLimbo(0); | |
574 | |
575 // This time we don't catch InsufficientDiscSpace -- we | |
576 // haven't allocated anything yet and can safely let the | |
577 // exception out to indicate to the caller that we can't | |
578 // handle it. | |
579 | |
580 recommendation = | |
581 StorageAdviser::recommend(criteria, minimumSize, maximumSize); | |
582 } | |
583 | |
584 std::cerr << "Recommendation was: " << recommendation << std::endl; | |
585 | |
586 m_memoryCache = false; | |
587 | |
588 if ((recommendation & StorageAdviser::UseMemory) || | |
589 (recommendation & StorageAdviser::PreferMemory)) { | |
590 m_memoryCache = true; | |
591 } | |
592 | |
593 m_compactCache = canCompact && | |
594 (recommendation & StorageAdviser::ConserveSpace); | |
595 | |
596 std::cerr << "FFTDataServer: memory cache = " << m_memoryCache << ", compact cache = " << m_compactCache << std::endl; | |
597 | |
598 #ifdef DEBUG_FFT_SERVER | |
599 std::cerr << "Width " << m_width << ", cache width " << m_cacheWidth << " (size " << m_cacheWidth * columnSize << ")" << std::endl; | |
600 #endif | |
601 | |
602 StorageAdviser::notifyPlannedAllocation | |
603 (m_memoryCache ? StorageAdviser::MemoryAllocation : | |
604 StorageAdviser::DiscAllocation, | |
605 m_compactCache ? minimumSize : maximumSize); | |
606 | 561 |
607 for (size_t i = 0; i <= m_width / m_cacheWidth; ++i) { | 562 for (size_t i = 0; i <= m_width / m_cacheWidth; ++i) { |
608 m_caches.push_back(0); | 563 m_caches.push_back(0); |
609 } | 564 } |
610 | 565 |
646 | 601 |
647 MutexLocker locker(&m_writeMutex, | 602 MutexLocker locker(&m_writeMutex, |
648 "FFTDataServer::m_writeMutex[~FFTDataServer]"); | 603 "FFTDataServer::m_writeMutex[~FFTDataServer]"); |
649 | 604 |
650 for (CacheVector::iterator i = m_caches.begin(); i != m_caches.end(); ++i) { | 605 for (CacheVector::iterator i = m_caches.begin(); i != m_caches.end(); ++i) { |
606 | |
651 if (*i) { | 607 if (*i) { |
652 delete *i; | 608 delete *i; |
653 } else { | |
654 StorageAdviser::notifyDoneAllocation | |
655 (m_memoryCache ? StorageAdviser::MemoryAllocation : | |
656 StorageAdviser::DiscAllocation, | |
657 m_cacheWidth * m_height * | |
658 (m_compactCache ? sizeof(uint16_t) : sizeof(float)) / 1024 + 1); | |
659 } | 609 } |
660 } | 610 } |
661 | 611 |
662 deleteProcessingData(); | 612 deleteProcessingData(); |
663 } | 613 } |
722 m_condition.wakeAll(); | 672 m_condition.wakeAll(); |
723 } | 673 } |
724 } | 674 } |
725 } | 675 } |
726 | 676 |
677 void | |
678 FFTDataServer::getStorageAdvice(size_t w, size_t h, | |
679 bool &memoryCache, bool &compactCache) | |
680 { | |
681 int cells = w * h; | |
682 int minimumSize = (cells / 1024) * sizeof(uint16_t); // kb | |
683 int maximumSize = (cells / 1024) * sizeof(float); // kb | |
684 | |
685 // We don't have a compact rectangular representation, and compact | |
686 // of course is never precision-critical | |
687 | |
688 bool canCompact = true; | |
689 if ((m_criteria & StorageAdviser::PrecisionCritical) || !m_polar) { | |
690 canCompact = false; | |
691 minimumSize = maximumSize; // don't use compact | |
692 } | |
693 | |
694 StorageAdviser::Recommendation recommendation; | |
695 | |
696 try { | |
697 | |
698 recommendation = | |
699 StorageAdviser::recommend(m_criteria, minimumSize, maximumSize); | |
700 | |
701 } catch (InsufficientDiscSpace s) { | |
702 | |
703 // Delete any unused servers we may have been leaving around | |
704 // in case we wanted them again | |
705 | |
706 purgeLimbo(0); | |
707 | |
708 // This time we don't catch InsufficientDiscSpace -- we | |
709 // haven't allocated anything yet and can safely let the | |
710 // exception out to indicate to the caller that we can't | |
711 // handle it. | |
712 | |
713 recommendation = | |
714 StorageAdviser::recommend(m_criteria, minimumSize, maximumSize); | |
715 } | |
716 | |
717 std::cerr << "Recommendation was: " << recommendation << std::endl; | |
718 | |
719 memoryCache = false; | |
720 | |
721 if ((recommendation & StorageAdviser::UseMemory) || | |
722 (recommendation & StorageAdviser::PreferMemory)) { | |
723 memoryCache = true; | |
724 } | |
725 | |
726 compactCache = canCompact && | |
727 (recommendation & StorageAdviser::ConserveSpace); | |
728 | |
729 std::cerr << "FFTDataServer: memory cache = " << memoryCache << ", compact cache = " << compactCache << std::endl; | |
730 | |
731 #ifdef DEBUG_FFT_SERVER | |
732 std::cerr << "Width " << w << " of " << m_width << ", height " << h << ", size " << w * h << std::endl; | |
733 #endif | |
734 } | |
735 | |
727 FFTCache * | 736 FFTCache * |
728 FFTDataServer::getCacheAux(size_t c) | 737 FFTDataServer::getCacheAux(size_t c) |
729 { | 738 { |
730 Profiler profiler("FFTDataServer::getCacheAux", false); | 739 Profiler profiler("FFTDataServer::getCacheAux", false); |
731 #ifdef DEBUG_FFT_SERVER | 740 #ifdef DEBUG_FFT_SERVER |
782 size_t width = m_cacheWidth; | 791 size_t width = m_cacheWidth; |
783 if (c * m_cacheWidth + width > m_width) { | 792 if (c * m_cacheWidth + width > m_width) { |
784 width = m_width - c * m_cacheWidth; | 793 width = m_width - c * m_cacheWidth; |
785 } | 794 } |
786 | 795 |
796 bool memoryCache = false; | |
797 bool compactCache = false; | |
798 | |
799 getStorageAdvice(width, m_height, memoryCache, compactCache); | |
800 | |
787 try { | 801 try { |
788 | 802 |
789 if (m_memoryCache) { | 803 if (memoryCache) { |
790 | 804 |
791 cache = new FFTMemoryCache | 805 cache = new FFTMemoryCache |
792 (m_compactCache ? FFTMemoryCache::Compact : | 806 (compactCache ? FFTMemoryCache::Compact : |
793 // FFTMemoryCache::Polar); | 807 m_polar ? FFTMemoryCache::Polar : |
794 m_polar ? FFTMemoryCache::Polar : | 808 FFTMemoryCache::Rectangular); |
795 FFTMemoryCache::Rectangular); | 809 |
796 | 810 } else { |
797 } else if (m_compactCache) { | |
798 | 811 |
799 cache = new FFTFileCache | 812 cache = new FFTFileCache |
800 (name, | 813 (name, |
801 MatrixFile::ReadWrite, | 814 MatrixFile::ReadWrite, |
802 FFTFileCache::Compact); | 815 compactCache ? FFTFileCache::Compact : |
803 | 816 m_polar ? FFTFileCache::Polar : |
804 } else { | 817 FFTFileCache::Rectangular); |
805 | |
806 cache = new FFTFileCache | |
807 (name, | |
808 MatrixFile::ReadWrite, | |
809 m_polar ? FFTFileCache::Polar : | |
810 FFTFileCache::Rectangular); | |
811 } | 818 } |
812 | 819 |
813 cache->resize(width, m_height); | 820 cache->resize(width, m_height); |
814 cache->reset(); | 821 cache->reset(); |
815 | 822 |
816 } catch (std::bad_alloc) { | 823 } catch (std::bad_alloc) { |
817 | 824 |
818 delete cache; | 825 delete cache; |
819 cache = 0; | 826 cache = 0; |
820 | 827 |
821 if (m_memoryCache) { | 828 if (memoryCache) { |
822 | 829 |
823 std::cerr << "WARNING: Memory allocation failed when resizing" | 830 std::cerr << "WARNING: Memory allocation failed when resizing" |
824 << " FFT memory cache no. " << c << " to " << width | 831 << " FFT memory cache no. " << c << " to " << width |
825 << "x" << m_height << " (of total width " << m_width | 832 << "x" << m_height << " (of total width " << m_width |
826 << "): falling back to disc cache" << std::endl; | 833 << "): falling back to disc cache" << std::endl; |
827 | 834 |
828 try { | 835 try { |
829 | 836 |
830 cache = new FFTFileCache(name, MatrixFile::ReadWrite, | 837 purgeLimbo(0); |
838 | |
839 cache = new FFTFileCache(name, | |
840 MatrixFile::ReadWrite, | |
831 FFTFileCache::Compact); | 841 FFTFileCache::Compact); |
832 | 842 |
833 cache->resize(width, m_height); | 843 cache->resize(width, m_height); |
834 cache->reset(); | 844 cache->reset(); |
835 | 845 |
852 (0, QApplication::tr("FFT cache resize failed"), | 862 (0, QApplication::tr("FFT cache resize failed"), |
853 QApplication::tr | 863 QApplication::tr |
854 ("Failed to create or resize an FFT model slice.\n" | 864 ("Failed to create or resize an FFT model slice.\n" |
855 "There may be insufficient memory or disc space to continue.")); | 865 "There may be insufficient memory or disc space to continue.")); |
856 } | 866 } |
857 | |
858 StorageAdviser::notifyDoneAllocation | |
859 (m_memoryCache ? StorageAdviser::MemoryAllocation : | |
860 StorageAdviser::DiscAllocation, | |
861 width * m_height * | |
862 (m_compactCache ? sizeof(uint16_t) : sizeof(float)) / 1024 + 1); | |
863 | 867 |
864 m_caches[c] = cache; | 868 m_caches[c] = cache; |
865 m_lastUsedCache = c; | 869 m_lastUsedCache = c; |
866 return cache; | 870 return cache; |
867 } | 871 } |