Chris@168: /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ Chris@168: Chris@168: /* Chris@168: Sonic Visualiser Chris@168: An audio file viewer and annotation editor. Chris@168: Centre for Digital Music, Queen Mary, University of London. Chris@202: This file copyright 2006 QMUL. Chris@168: Chris@168: This program is free software; you can redistribute it and/or Chris@168: modify it under the terms of the GNU General Public License as Chris@168: published by the Free Software Foundation; either version 2 of the Chris@168: License, or (at your option) any later version. See the file Chris@168: COPYING included with this distribution for more information. Chris@168: */ Chris@168: Chris@168: #include "StorageAdviser.h" Chris@168: Chris@168: #include "Exceptions.h" Chris@168: #include "TempDirectory.h" Chris@168: Chris@168: #include "system/System.h" Chris@168: Chris@168: #include Chris@168: Chris@1276: QString Chris@1276: StorageAdviser::criteriaToString(int criteria) Chris@1276: { Chris@1276: QStringList labels; Chris@1276: if (criteria & SpeedCritical) labels.push_back("SpeedCritical"); Chris@1276: if (criteria & PrecisionCritical) labels.push_back("PrecisionCritical"); Chris@1276: if (criteria & LongRetentionLikely) labels.push_back("LongRetentionLikely"); Chris@1276: if (criteria & FrequentLookupLikely) labels.push_back("FrequentLookupLikely"); Chris@1276: if (labels.empty()) return "None"; Chris@1276: else return labels.join("+"); Chris@1276: } Chris@1276: Chris@1276: QString Chris@1276: StorageAdviser::recommendationToString(int recommendation) Chris@1276: { Chris@1276: QStringList labels; Chris@1276: if (recommendation & UseMemory) labels.push_back("UseMemory"); Chris@1276: if (recommendation & PreferMemory) labels.push_back("PreferMemory"); Chris@1276: if (recommendation & PreferDisc) labels.push_back("PreferDisc"); Chris@1276: if (recommendation & UseDisc) labels.push_back("UseDisc"); Chris@1276: if (recommendation & ConserveSpace) labels.push_back("ConserveSpace"); Chris@1276: if (recommendation & UseAsMuchAsYouLike) labels.push_back("UseAsMuchAsYouLike"); Chris@1276: if (labels.empty()) return "None"; Chris@1276: else return labels.join("+"); Chris@1276: } Chris@1276: Chris@1276: QString Chris@1276: StorageAdviser::storageStatusToString(StorageStatus status) Chris@1276: { Chris@1276: if (status == Insufficient) return "Insufficient"; Chris@1276: if (status == Marginal) return "Marginal"; Chris@1276: if (status == Sufficient) return "Sufficient"; Chris@1276: return "Unknown"; Chris@1276: } Chris@374: Chris@1038: size_t StorageAdviser::m_discPlanned = 0; Chris@1038: size_t StorageAdviser::m_memoryPlanned = 0; Chris@205: Chris@168: StorageAdviser::Recommendation Chris@411: StorageAdviser::m_baseRecommendation = StorageAdviser::NoRecommendation; Chris@411: Chris@411: StorageAdviser::Recommendation Chris@168: StorageAdviser::recommend(Criteria criteria, Chris@1038: size_t minimumSize, Chris@1038: size_t maximumSize) Chris@168: { Chris@1276: SVDEBUG << "StorageAdviser::recommend: criteria " << criteria Chris@1276: << " (" + criteriaToString(criteria) + ")" Chris@1276: << ", minimumSize " << minimumSize Chris@1276: << ", maximumSize " << maximumSize << endl; Chris@170: Chris@411: if (m_baseRecommendation != NoRecommendation) { Chris@1276: SVDEBUG << "StorageAdviser::recommend: Returning fixed recommendation " Chris@1276: << m_baseRecommendation << " (" Chris@1276: << recommendationToString(m_baseRecommendation) << ")" << endl; Chris@411: return m_baseRecommendation; // for now Chris@411: } Chris@411: Chris@541: QString path; Chris@541: try { Chris@541: path = TempDirectory::getInstance()->getPath(); Chris@541: } catch (std::exception e) { Chris@1276: SVDEBUG << "StorageAdviser::recommend: ERROR: Failed to get temporary directory path: " << e.what() << endl; Chris@1276: int r = UseMemory | ConserveSpace; Chris@1276: SVDEBUG << "StorageAdviser: returning fallback " << r Chris@1276: << " (" << recommendationToString(r) << ")" << endl; Chris@1276: return Recommendation(r); Chris@541: } Chris@1038: ssize_t discFree = GetDiscSpaceMBAvailable(path.toLocal8Bit()); Chris@1038: ssize_t memoryFree, memoryTotal; Chris@170: GetRealMemoryMBAvailable(memoryFree, memoryTotal); Chris@168: Chris@1276: SVDEBUG << "StorageAdviser: disc space: " << discFree Chris@1276: << "M, memory free: " << memoryFree Chris@1276: << "M, memory total: " << memoryTotal << "M" << endl; Chris@1276: SVDEBUG << "StorageAdviser: disc planned: " << (m_discPlanned / 1024) Chris@1276: << "K, memory planned: " << (m_memoryPlanned / 1024) << "K" << endl; Chris@1276: SVDEBUG << "StorageAdviser: min requested: " << minimumSize Chris@1276: << "K, max requested: " << maximumSize << "K" << endl; Chris@1276: Chris@1038: if (discFree > ssize_t(m_discPlanned / 1024 + 1)) { Chris@205: discFree -= m_discPlanned / 1024 + 1; Chris@205: } else if (discFree > 0) { // can also be -1 for unknown Chris@205: discFree = 0; Chris@205: } Chris@205: Chris@1038: if (memoryFree > ssize_t(m_memoryPlanned / 1024 + 1)) { Chris@205: memoryFree -= m_memoryPlanned / 1024 + 1; Chris@205: } else if (memoryFree > 0) { // can also be -1 for unknown Chris@205: memoryFree = 0; Chris@205: } Chris@205: Chris@192: //!!! We have a potentially serious problem here if multiple Chris@192: //recommendations are made in advance of any of the resulting Chris@192: //allocations, as the allocations that have been recommended for Chris@192: //won't be taken into account in subsequent recommendations. Chris@192: Chris@170: StorageStatus memoryStatus = Unknown; Chris@170: StorageStatus discStatus = Unknown; Chris@170: Chris@1038: ssize_t minmb = ssize_t(minimumSize / 1024 + 1); Chris@1038: ssize_t maxmb = ssize_t(maximumSize / 1024 + 1); Chris@170: Chris@170: if (memoryFree == -1) memoryStatus = Unknown; Chris@1103: else if (memoryFree < memoryTotal / 3 && memoryFree < 512) memoryStatus = Insufficient; Chris@170: else if (minmb > (memoryFree * 3) / 4) memoryStatus = Insufficient; Chris@170: else if (maxmb > (memoryFree * 3) / 4) memoryStatus = Marginal; Chris@170: else if (minmb > (memoryFree / 3)) memoryStatus = Marginal; Chris@170: else if (memoryTotal == -1 || Chris@170: minmb > (memoryTotal / 10)) memoryStatus = Marginal; Chris@170: else memoryStatus = Sufficient; Chris@170: Chris@170: if (discFree == -1) discStatus = Unknown; Chris@170: else if (minmb > (discFree * 3) / 4) discStatus = Insufficient; Chris@173: else if (maxmb > (discFree / 4)) discStatus = Marginal; Chris@173: else if (minmb > (discFree / 10)) discStatus = Marginal; Chris@170: else discStatus = Sufficient; Chris@170: Chris@1276: SVDEBUG << "StorageAdviser: memory status: " << memoryStatus Chris@1276: << " (" << storageStatusToString(memoryStatus) << ")" Chris@1276: << ", disc status " << discStatus Chris@1276: << " (" << storageStatusToString(discStatus) << ")" << endl; Chris@170: Chris@170: int recommendation = NoRecommendation; Chris@170: Chris@170: if (memoryStatus == Insufficient || memoryStatus == Unknown) { Chris@170: Chris@170: recommendation |= UseDisc; Chris@170: Chris@170: if (discStatus == Insufficient && minmb > discFree) { Chris@170: throw InsufficientDiscSpace(path, minmb, discFree); Chris@170: } Chris@170: Chris@170: if (discStatus == Insufficient || discStatus == Marginal) { Chris@170: recommendation |= ConserveSpace; Chris@170: } else if (discStatus == Unknown && !(criteria & PrecisionCritical)) { Chris@170: recommendation |= ConserveSpace; Chris@170: } else { Chris@170: recommendation |= UseAsMuchAsYouLike; Chris@170: } Chris@170: Chris@170: } else if (memoryStatus == Marginal) { Chris@170: Chris@170: if (((criteria & SpeedCritical) || Chris@170: (criteria & FrequentLookupLikely)) && Chris@170: !(criteria & PrecisionCritical) && Chris@170: !(criteria & LongRetentionLikely)) { Chris@170: Chris@170: // requirements suggest a preference for memory Chris@170: Chris@170: if (discStatus != Insufficient) { Chris@170: recommendation |= PreferMemory; Chris@170: } else { Chris@170: recommendation |= UseMemory; Chris@170: } Chris@170: Chris@170: recommendation |= ConserveSpace; Chris@170: Chris@170: } else { Chris@170: Chris@170: if (discStatus == Insufficient) { Chris@170: recommendation |= (UseMemory | ConserveSpace); Chris@170: } else if (discStatus == Marginal) { Chris@170: recommendation |= (PreferMemory | ConserveSpace); Chris@170: } else if (discStatus == Unknown) { Chris@170: recommendation |= (PreferDisc | ConserveSpace); Chris@170: } else { Chris@170: recommendation |= (UseDisc | UseAsMuchAsYouLike); Chris@170: } Chris@170: } Chris@170: Chris@170: } else { Chris@170: Chris@170: if (discStatus == Insufficient) { Chris@170: recommendation |= (UseMemory | ConserveSpace); Chris@170: } else if (discStatus != Sufficient) { Chris@170: recommendation |= (PreferMemory | ConserveSpace); Chris@170: } else { Chris@170: Chris@170: if ((criteria & SpeedCritical) || Chris@170: (criteria & FrequentLookupLikely)) { Chris@170: recommendation |= PreferMemory; Chris@170: if (criteria & PrecisionCritical) { Chris@170: recommendation |= UseAsMuchAsYouLike; Chris@170: } else { Chris@170: recommendation |= ConserveSpace; Chris@170: } Chris@170: } else { Chris@170: recommendation |= PreferDisc; Chris@170: recommendation |= UseAsMuchAsYouLike; Chris@170: } Chris@170: } Chris@170: } Chris@170: Chris@1276: SVDEBUG << "StorageAdviser: returning recommendation " << recommendation Chris@1276: << " (" << recommendationToString(recommendation) << ")" << endl; Chris@1098: Chris@170: return Recommendation(recommendation); Chris@168: } Chris@168: Chris@205: void Chris@1038: StorageAdviser::notifyPlannedAllocation(AllocationArea area, size_t size) Chris@205: { Chris@205: if (area == MemoryAllocation) m_memoryPlanned += size; Chris@205: else if (area == DiscAllocation) m_discPlanned += size; Chris@1276: SVDEBUG << "StorageAdviser: storage planned up: now memory: " << m_memoryPlanned << ", disc " Chris@1276: << m_discPlanned << endl; Chris@205: } Chris@205: Chris@205: void Chris@1038: StorageAdviser::notifyDoneAllocation(AllocationArea area, size_t size) Chris@205: { Chris@205: if (area == MemoryAllocation) { Chris@205: if (m_memoryPlanned > size) m_memoryPlanned -= size; Chris@205: else m_memoryPlanned = 0; Chris@205: } else if (area == DiscAllocation) { Chris@205: if (m_discPlanned > size) m_discPlanned -= size; Chris@205: else m_discPlanned = 0; Chris@205: } Chris@1276: SVDEBUG << "StorageAdviser: storage planned down: now memory: " << m_memoryPlanned << ", disc " Chris@1276: << m_discPlanned << endl; Chris@205: } Chris@205: Chris@411: void Chris@411: StorageAdviser::setFixedRecommendation(Recommendation recommendation) Chris@411: { Chris@411: m_baseRecommendation = recommendation; Chris@411: } Chris@411: