annotate base/StorageAdviser.cpp @ 458:f60360209e5c

* Fix race condition in FFTFileCache when reading from the same FFT model from multiple threads (e.g. when applying more than one plugin at once)
author Chris Cannam
date Wed, 15 Oct 2008 12:08:02 +0000
parents cff476cfce77
children 57f3eec55957
rev   line source
Chris@168 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
Chris@168 2
Chris@168 3 /*
Chris@168 4 Sonic Visualiser
Chris@168 5 An audio file viewer and annotation editor.
Chris@168 6 Centre for Digital Music, Queen Mary, University of London.
Chris@202 7 This file copyright 2006 QMUL.
Chris@168 8
Chris@168 9 This program is free software; you can redistribute it and/or
Chris@168 10 modify it under the terms of the GNU General Public License as
Chris@168 11 published by the Free Software Foundation; either version 2 of the
Chris@168 12 License, or (at your option) any later version. See the file
Chris@168 13 COPYING included with this distribution for more information.
Chris@168 14 */
Chris@168 15
Chris@168 16 #include "StorageAdviser.h"
Chris@168 17
Chris@168 18 #include "Exceptions.h"
Chris@168 19 #include "TempDirectory.h"
Chris@168 20
Chris@168 21 #include "system/System.h"
Chris@168 22
Chris@168 23 #include <iostream>
Chris@168 24
Chris@436 25 //#define DEBUG_STORAGE_ADVISER 1
Chris@374 26
Chris@205 27 long StorageAdviser::m_discPlanned = 0;
Chris@205 28 long StorageAdviser::m_memoryPlanned = 0;
Chris@205 29
Chris@168 30 StorageAdviser::Recommendation
Chris@411 31 StorageAdviser::m_baseRecommendation = StorageAdviser::NoRecommendation;
Chris@411 32
Chris@411 33 StorageAdviser::Recommendation
Chris@168 34 StorageAdviser::recommend(Criteria criteria,
Chris@168 35 int minimumSize,
Chris@168 36 int maximumSize)
Chris@168 37 {
Chris@374 38 #ifdef DEBUG_STORAGE_ADVISER
Chris@170 39 std::cerr << "StorageAdviser::recommend: Criteria " << criteria
Chris@170 40 << ", minimumSize " << minimumSize
Chris@170 41 << ", maximumSize " << maximumSize << std::endl;
Chris@374 42 #endif
Chris@170 43
Chris@411 44 if (m_baseRecommendation != NoRecommendation) {
Chris@411 45 return m_baseRecommendation; // for now
Chris@411 46 }
Chris@411 47
Chris@168 48 QString path = TempDirectory::getInstance()->getPath();
Chris@170 49 int discFree = GetDiscSpaceMBAvailable(path.toLocal8Bit());
Chris@170 50 int memoryFree, memoryTotal;
Chris@170 51 GetRealMemoryMBAvailable(memoryFree, memoryTotal);
Chris@168 52
Chris@205 53 if (discFree > m_discPlanned / 1024 + 1) {
Chris@205 54 discFree -= m_discPlanned / 1024 + 1;
Chris@205 55 } else if (discFree > 0) { // can also be -1 for unknown
Chris@205 56 discFree = 0;
Chris@205 57 }
Chris@205 58
Chris@205 59 if (memoryFree > m_memoryPlanned / 1024 + 1) {
Chris@205 60 memoryFree -= m_memoryPlanned / 1024 + 1;
Chris@205 61 } else if (memoryFree > 0) { // can also be -1 for unknown
Chris@205 62 memoryFree = 0;
Chris@205 63 }
Chris@205 64
Chris@374 65 #ifdef DEBUG_STORAGE_ADVISER
Chris@334 66 std::cerr << "Disc space: " << discFree << ", memory free: " << memoryFree << ", memory total: " << memoryTotal << ", min " << minimumSize << ", max " << maximumSize << std::endl;
Chris@374 67 #endif
Chris@168 68
Chris@192 69 //!!! We have a potentially serious problem here if multiple
Chris@192 70 //recommendations are made in advance of any of the resulting
Chris@192 71 //allocations, as the allocations that have been recommended for
Chris@192 72 //won't be taken into account in subsequent recommendations.
Chris@192 73
Chris@170 74 enum StorageStatus {
Chris@170 75 Unknown,
Chris@170 76 Insufficient,
Chris@170 77 Marginal,
Chris@170 78 Sufficient
Chris@170 79 };
Chris@168 80
Chris@170 81 StorageStatus memoryStatus = Unknown;
Chris@170 82 StorageStatus discStatus = Unknown;
Chris@170 83
Chris@170 84 int minmb = minimumSize / 1024 + 1;
Chris@170 85 int maxmb = maximumSize / 1024 + 1;
Chris@170 86
Chris@170 87 if (memoryFree == -1) memoryStatus = Unknown;
Chris@415 88 else if (memoryFree < memoryTotal / 3) memoryStatus = Insufficient;
Chris@170 89 else if (minmb > (memoryFree * 3) / 4) memoryStatus = Insufficient;
Chris@170 90 else if (maxmb > (memoryFree * 3) / 4) memoryStatus = Marginal;
Chris@170 91 else if (minmb > (memoryFree / 3)) memoryStatus = Marginal;
Chris@170 92 else if (memoryTotal == -1 ||
Chris@170 93 minmb > (memoryTotal / 10)) memoryStatus = Marginal;
Chris@170 94 else memoryStatus = Sufficient;
Chris@170 95
Chris@170 96 if (discFree == -1) discStatus = Unknown;
Chris@170 97 else if (minmb > (discFree * 3) / 4) discStatus = Insufficient;
Chris@173 98 else if (maxmb > (discFree / 4)) discStatus = Marginal;
Chris@173 99 else if (minmb > (discFree / 10)) discStatus = Marginal;
Chris@170 100 else discStatus = Sufficient;
Chris@170 101
Chris@374 102 #ifdef DEBUG_STORAGE_ADVISER
Chris@170 103 std::cerr << "Memory status: " << memoryStatus << ", disc status "
Chris@170 104 << discStatus << std::endl;
Chris@374 105 #endif
Chris@170 106
Chris@170 107 int recommendation = NoRecommendation;
Chris@170 108
Chris@170 109 if (memoryStatus == Insufficient || memoryStatus == Unknown) {
Chris@170 110
Chris@170 111 recommendation |= UseDisc;
Chris@170 112
Chris@170 113 if (discStatus == Insufficient && minmb > discFree) {
Chris@170 114 throw InsufficientDiscSpace(path, minmb, discFree);
Chris@170 115 }
Chris@170 116
Chris@170 117 if (discStatus == Insufficient || discStatus == Marginal) {
Chris@170 118 recommendation |= ConserveSpace;
Chris@170 119 } else if (discStatus == Unknown && !(criteria & PrecisionCritical)) {
Chris@170 120 recommendation |= ConserveSpace;
Chris@170 121 } else {
Chris@170 122 recommendation |= UseAsMuchAsYouLike;
Chris@170 123 }
Chris@170 124
Chris@170 125 } else if (memoryStatus == Marginal) {
Chris@170 126
Chris@170 127 if (((criteria & SpeedCritical) ||
Chris@170 128 (criteria & FrequentLookupLikely)) &&
Chris@170 129 !(criteria & PrecisionCritical) &&
Chris@170 130 !(criteria & LongRetentionLikely)) {
Chris@170 131
Chris@170 132 // requirements suggest a preference for memory
Chris@170 133
Chris@170 134 if (discStatus != Insufficient) {
Chris@170 135 recommendation |= PreferMemory;
Chris@170 136 } else {
Chris@170 137 recommendation |= UseMemory;
Chris@170 138 }
Chris@170 139
Chris@170 140 recommendation |= ConserveSpace;
Chris@170 141
Chris@170 142 } else {
Chris@170 143
Chris@170 144 if (discStatus == Insufficient) {
Chris@170 145 recommendation |= (UseMemory | ConserveSpace);
Chris@170 146 } else if (discStatus == Marginal) {
Chris@170 147 recommendation |= (PreferMemory | ConserveSpace);
Chris@170 148 } else if (discStatus == Unknown) {
Chris@170 149 recommendation |= (PreferDisc | ConserveSpace);
Chris@170 150 } else {
Chris@170 151 recommendation |= (UseDisc | UseAsMuchAsYouLike);
Chris@170 152 }
Chris@170 153 }
Chris@170 154
Chris@170 155 } else {
Chris@170 156
Chris@170 157 if (discStatus == Insufficient) {
Chris@170 158 recommendation |= (UseMemory | ConserveSpace);
Chris@170 159 } else if (discStatus != Sufficient) {
Chris@170 160 recommendation |= (PreferMemory | ConserveSpace);
Chris@170 161 } else {
Chris@170 162
Chris@170 163 if ((criteria & SpeedCritical) ||
Chris@170 164 (criteria & FrequentLookupLikely)) {
Chris@170 165 recommendation |= PreferMemory;
Chris@170 166 if (criteria & PrecisionCritical) {
Chris@170 167 recommendation |= UseAsMuchAsYouLike;
Chris@170 168 } else {
Chris@170 169 recommendation |= ConserveSpace;
Chris@170 170 }
Chris@170 171 } else {
Chris@170 172 recommendation |= PreferDisc;
Chris@170 173 recommendation |= UseAsMuchAsYouLike;
Chris@170 174 }
Chris@170 175 }
Chris@170 176 }
Chris@170 177
Chris@170 178 return Recommendation(recommendation);
Chris@168 179 }
Chris@168 180
Chris@205 181 void
Chris@205 182 StorageAdviser::notifyPlannedAllocation(AllocationArea area, int size)
Chris@205 183 {
Chris@205 184 if (area == MemoryAllocation) m_memoryPlanned += size;
Chris@205 185 else if (area == DiscAllocation) m_discPlanned += size;
Chris@259 186 // std::cerr << "storage planned up: memory: " << m_memoryPlanned << ", disc "
Chris@259 187 // << m_discPlanned << std::endl;
Chris@205 188 }
Chris@205 189
Chris@205 190 void
Chris@205 191 StorageAdviser::notifyDoneAllocation(AllocationArea area, int size)
Chris@205 192 {
Chris@205 193 if (area == MemoryAllocation) {
Chris@205 194 if (m_memoryPlanned > size) m_memoryPlanned -= size;
Chris@205 195 else m_memoryPlanned = 0;
Chris@205 196 } else if (area == DiscAllocation) {
Chris@205 197 if (m_discPlanned > size) m_discPlanned -= size;
Chris@205 198 else m_discPlanned = 0;
Chris@205 199 }
Chris@259 200 // std::cerr << "storage planned down: memory: " << m_memoryPlanned << ", disc "
Chris@259 201 // << m_discPlanned << std::endl;
Chris@205 202 }
Chris@205 203
Chris@411 204 void
Chris@411 205 StorageAdviser::setFixedRecommendation(Recommendation recommendation)
Chris@411 206 {
Chris@411 207 m_baseRecommendation = recommendation;
Chris@411 208 }
Chris@411 209