annotate base/StorageAdviser.cpp @ 1752:6d09d68165a4 by-id

Further review of ById: make IDs only available when adding a model to the ById store, not by querying the item directly. This means any id encountered in the wild must have been added to the store at some point (even if later released), which simplifies reasoning about lifecycles
author Chris Cannam
date Fri, 05 Jul 2019 15:28:07 +0100
parents cee1be4fb8c1
children
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@1276 25 QString
Chris@1276 26 StorageAdviser::criteriaToString(int criteria)
Chris@1276 27 {
Chris@1276 28 QStringList labels;
Chris@1276 29 if (criteria & SpeedCritical) labels.push_back("SpeedCritical");
Chris@1276 30 if (criteria & PrecisionCritical) labels.push_back("PrecisionCritical");
Chris@1276 31 if (criteria & LongRetentionLikely) labels.push_back("LongRetentionLikely");
Chris@1276 32 if (criteria & FrequentLookupLikely) labels.push_back("FrequentLookupLikely");
Chris@1276 33 if (labels.empty()) return "None";
Chris@1276 34 else return labels.join("+");
Chris@1276 35 }
Chris@1276 36
Chris@1276 37 QString
Chris@1276 38 StorageAdviser::recommendationToString(int recommendation)
Chris@1276 39 {
Chris@1276 40 QStringList labels;
Chris@1276 41 if (recommendation & UseMemory) labels.push_back("UseMemory");
Chris@1276 42 if (recommendation & PreferMemory) labels.push_back("PreferMemory");
Chris@1276 43 if (recommendation & PreferDisc) labels.push_back("PreferDisc");
Chris@1276 44 if (recommendation & UseDisc) labels.push_back("UseDisc");
Chris@1276 45 if (recommendation & ConserveSpace) labels.push_back("ConserveSpace");
Chris@1276 46 if (recommendation & UseAsMuchAsYouLike) labels.push_back("UseAsMuchAsYouLike");
Chris@1276 47 if (labels.empty()) return "None";
Chris@1276 48 else return labels.join("+");
Chris@1276 49 }
Chris@1276 50
Chris@1276 51 QString
Chris@1276 52 StorageAdviser::storageStatusToString(StorageStatus status)
Chris@1276 53 {
Chris@1276 54 if (status == Insufficient) return "Insufficient";
Chris@1276 55 if (status == Marginal) return "Marginal";
Chris@1276 56 if (status == Sufficient) return "Sufficient";
Chris@1276 57 return "Unknown";
Chris@1276 58 }
Chris@374 59
Chris@1038 60 size_t StorageAdviser::m_discPlanned = 0;
Chris@1038 61 size_t StorageAdviser::m_memoryPlanned = 0;
Chris@205 62
Chris@168 63 StorageAdviser::Recommendation
Chris@411 64 StorageAdviser::m_baseRecommendation = StorageAdviser::NoRecommendation;
Chris@411 65
Chris@411 66 StorageAdviser::Recommendation
Chris@168 67 StorageAdviser::recommend(Criteria criteria,
Chris@1429 68 size_t minimumSize,
Chris@1429 69 size_t maximumSize)
Chris@168 70 {
Chris@1276 71 SVDEBUG << "StorageAdviser::recommend: criteria " << criteria
Chris@1276 72 << " (" + criteriaToString(criteria) + ")"
Chris@1276 73 << ", minimumSize " << minimumSize
Chris@1276 74 << ", maximumSize " << maximumSize << endl;
Chris@170 75
Chris@411 76 if (m_baseRecommendation != NoRecommendation) {
Chris@1276 77 SVDEBUG << "StorageAdviser::recommend: Returning fixed recommendation "
Chris@1276 78 << m_baseRecommendation << " ("
Chris@1276 79 << recommendationToString(m_baseRecommendation) << ")" << endl;
Chris@411 80 return m_baseRecommendation; // for now
Chris@411 81 }
Chris@411 82
Chris@541 83 QString path;
Chris@541 84 try {
Chris@541 85 path = TempDirectory::getInstance()->getPath();
Chris@1465 86 } catch (const std::exception &e) {
Chris@1276 87 SVDEBUG << "StorageAdviser::recommend: ERROR: Failed to get temporary directory path: " << e.what() << endl;
Chris@1276 88 int r = UseMemory | ConserveSpace;
Chris@1276 89 SVDEBUG << "StorageAdviser: returning fallback " << r
Chris@1276 90 << " (" << recommendationToString(r) << ")" << endl;
Chris@1276 91 return Recommendation(r);
Chris@541 92 }
Chris@1038 93 ssize_t discFree = GetDiscSpaceMBAvailable(path.toLocal8Bit());
Chris@1038 94 ssize_t memoryFree, memoryTotal;
Chris@170 95 GetRealMemoryMBAvailable(memoryFree, memoryTotal);
Chris@168 96
Chris@1276 97 SVDEBUG << "StorageAdviser: disc space: " << discFree
Chris@1276 98 << "M, memory free: " << memoryFree
Chris@1276 99 << "M, memory total: " << memoryTotal << "M" << endl;
Chris@1405 100
Chris@1405 101 // In 32-bit addressing mode we can't address more than 4Gb.
Chris@1405 102 // If the total memory is reported as more than 4Gb, we should
Chris@1405 103 // reduce the available amount by the difference between 4Gb
Chris@1405 104 // and the total. This won't give us an accurate idea of the
Chris@1405 105 // amount of memory available any more, but it should be enough
Chris@1405 106 // to prevent us from trying to allocate more for our own use
Chris@1405 107 // than can be addressed at all!
Chris@1405 108 if (sizeof(void *) < 8) {
Chris@1405 109 if (memoryTotal > 4096) {
Chris@1405 110 ssize_t excess = memoryTotal - 4096;
Chris@1405 111 if (memoryFree > excess) {
Chris@1405 112 memoryFree -= excess;
Chris@1405 113 } else {
Chris@1405 114 memoryFree = 0;
Chris@1405 115 }
Chris@1405 116 SVDEBUG << "StorageAdviser: more real memory found than we "
Chris@1405 117 << "can address in a 32-bit process, reducing free "
Chris@1405 118 << "estimate to " << memoryFree << "M accordingly" << endl;
Chris@1405 119 }
Chris@1405 120 }
Chris@1405 121
Chris@1276 122 SVDEBUG << "StorageAdviser: disc planned: " << (m_discPlanned / 1024)
Chris@1276 123 << "K, memory planned: " << (m_memoryPlanned / 1024) << "K" << endl;
Chris@1276 124 SVDEBUG << "StorageAdviser: min requested: " << minimumSize
Chris@1276 125 << "K, max requested: " << maximumSize << "K" << endl;
Chris@1276 126
Chris@1038 127 if (discFree > ssize_t(m_discPlanned / 1024 + 1)) {
Chris@205 128 discFree -= m_discPlanned / 1024 + 1;
Chris@205 129 } else if (discFree > 0) { // can also be -1 for unknown
Chris@205 130 discFree = 0;
Chris@205 131 }
Chris@205 132
Chris@1038 133 if (memoryFree > ssize_t(m_memoryPlanned / 1024 + 1)) {
Chris@205 134 memoryFree -= m_memoryPlanned / 1024 + 1;
Chris@205 135 } else if (memoryFree > 0) { // can also be -1 for unknown
Chris@205 136 memoryFree = 0;
Chris@205 137 }
Chris@205 138
Chris@192 139 //!!! We have a potentially serious problem here if multiple
Chris@192 140 //recommendations are made in advance of any of the resulting
Chris@192 141 //allocations, as the allocations that have been recommended for
Chris@192 142 //won't be taken into account in subsequent recommendations.
Chris@192 143
Chris@170 144 StorageStatus memoryStatus = Unknown;
Chris@170 145 StorageStatus discStatus = Unknown;
Chris@170 146
Chris@1038 147 ssize_t minmb = ssize_t(minimumSize / 1024 + 1);
Chris@1038 148 ssize_t maxmb = ssize_t(maximumSize / 1024 + 1);
Chris@170 149
Chris@170 150 if (memoryFree == -1) memoryStatus = Unknown;
Chris@1103 151 else if (memoryFree < memoryTotal / 3 && memoryFree < 512) memoryStatus = Insufficient;
Chris@170 152 else if (minmb > (memoryFree * 3) / 4) memoryStatus = Insufficient;
Chris@170 153 else if (maxmb > (memoryFree * 3) / 4) memoryStatus = Marginal;
Chris@170 154 else if (minmb > (memoryFree / 3)) memoryStatus = Marginal;
Chris@170 155 else if (memoryTotal == -1 ||
Chris@170 156 minmb > (memoryTotal / 10)) memoryStatus = Marginal;
Chris@170 157 else memoryStatus = Sufficient;
Chris@170 158
Chris@170 159 if (discFree == -1) discStatus = Unknown;
Chris@170 160 else if (minmb > (discFree * 3) / 4) discStatus = Insufficient;
Chris@173 161 else if (maxmb > (discFree / 4)) discStatus = Marginal;
Chris@173 162 else if (minmb > (discFree / 10)) discStatus = Marginal;
Chris@170 163 else discStatus = Sufficient;
Chris@170 164
Chris@1276 165 SVDEBUG << "StorageAdviser: memory status: " << memoryStatus
Chris@1276 166 << " (" << storageStatusToString(memoryStatus) << ")"
Chris@1276 167 << ", disc status " << discStatus
Chris@1276 168 << " (" << storageStatusToString(discStatus) << ")" << endl;
Chris@170 169
Chris@170 170 int recommendation = NoRecommendation;
Chris@170 171
Chris@170 172 if (memoryStatus == Insufficient || memoryStatus == Unknown) {
Chris@170 173
Chris@170 174 recommendation |= UseDisc;
Chris@170 175
Chris@170 176 if (discStatus == Insufficient && minmb > discFree) {
Chris@170 177 throw InsufficientDiscSpace(path, minmb, discFree);
Chris@170 178 }
Chris@170 179
Chris@170 180 if (discStatus == Insufficient || discStatus == Marginal) {
Chris@170 181 recommendation |= ConserveSpace;
Chris@170 182 } else if (discStatus == Unknown && !(criteria & PrecisionCritical)) {
Chris@170 183 recommendation |= ConserveSpace;
Chris@170 184 } else {
Chris@170 185 recommendation |= UseAsMuchAsYouLike;
Chris@170 186 }
Chris@170 187
Chris@170 188 } else if (memoryStatus == Marginal) {
Chris@170 189
Chris@170 190 if (((criteria & SpeedCritical) ||
Chris@170 191 (criteria & FrequentLookupLikely)) &&
Chris@170 192 !(criteria & PrecisionCritical) &&
Chris@170 193 !(criteria & LongRetentionLikely)) {
Chris@170 194
Chris@170 195 // requirements suggest a preference for memory
Chris@170 196
Chris@170 197 if (discStatus != Insufficient) {
Chris@170 198 recommendation |= PreferMemory;
Chris@170 199 } else {
Chris@170 200 recommendation |= UseMemory;
Chris@170 201 }
Chris@170 202
Chris@170 203 recommendation |= ConserveSpace;
Chris@170 204
Chris@170 205 } else {
Chris@170 206
Chris@170 207 if (discStatus == Insufficient) {
Chris@170 208 recommendation |= (UseMemory | ConserveSpace);
Chris@170 209 } else if (discStatus == Marginal) {
Chris@170 210 recommendation |= (PreferMemory | ConserveSpace);
Chris@170 211 } else if (discStatus == Unknown) {
Chris@170 212 recommendation |= (PreferDisc | ConserveSpace);
Chris@170 213 } else {
Chris@170 214 recommendation |= (UseDisc | UseAsMuchAsYouLike);
Chris@170 215 }
Chris@170 216 }
Chris@170 217
Chris@170 218 } else {
Chris@170 219
Chris@170 220 if (discStatus == Insufficient) {
Chris@170 221 recommendation |= (UseMemory | ConserveSpace);
Chris@170 222 } else if (discStatus != Sufficient) {
Chris@170 223 recommendation |= (PreferMemory | ConserveSpace);
Chris@170 224 } else {
Chris@170 225
Chris@170 226 if ((criteria & SpeedCritical) ||
Chris@170 227 (criteria & FrequentLookupLikely)) {
Chris@170 228 recommendation |= PreferMemory;
Chris@170 229 if (criteria & PrecisionCritical) {
Chris@170 230 recommendation |= UseAsMuchAsYouLike;
Chris@170 231 } else {
Chris@170 232 recommendation |= ConserveSpace;
Chris@170 233 }
Chris@170 234 } else {
Chris@170 235 recommendation |= PreferDisc;
Chris@170 236 recommendation |= UseAsMuchAsYouLike;
Chris@170 237 }
Chris@170 238 }
Chris@170 239 }
Chris@170 240
Chris@1276 241 SVDEBUG << "StorageAdviser: returning recommendation " << recommendation
Chris@1276 242 << " (" << recommendationToString(recommendation) << ")" << endl;
Chris@1098 243
Chris@170 244 return Recommendation(recommendation);
Chris@168 245 }
Chris@168 246
Chris@205 247 void
Chris@1038 248 StorageAdviser::notifyPlannedAllocation(AllocationArea area, size_t size)
Chris@205 249 {
Chris@205 250 if (area == MemoryAllocation) m_memoryPlanned += size;
Chris@205 251 else if (area == DiscAllocation) m_discPlanned += size;
Chris@1276 252 SVDEBUG << "StorageAdviser: storage planned up: now memory: " << m_memoryPlanned << ", disc "
Chris@1276 253 << m_discPlanned << endl;
Chris@205 254 }
Chris@205 255
Chris@205 256 void
Chris@1038 257 StorageAdviser::notifyDoneAllocation(AllocationArea area, size_t size)
Chris@205 258 {
Chris@205 259 if (area == MemoryAllocation) {
Chris@205 260 if (m_memoryPlanned > size) m_memoryPlanned -= size;
Chris@205 261 else m_memoryPlanned = 0;
Chris@205 262 } else if (area == DiscAllocation) {
Chris@205 263 if (m_discPlanned > size) m_discPlanned -= size;
Chris@205 264 else m_discPlanned = 0;
Chris@205 265 }
Chris@1276 266 SVDEBUG << "StorageAdviser: storage planned down: now memory: " << m_memoryPlanned << ", disc "
Chris@1276 267 << m_discPlanned << endl;
Chris@205 268 }
Chris@205 269
Chris@411 270 void
Chris@411 271 StorageAdviser::setFixedRecommendation(Recommendation recommendation)
Chris@411 272 {
Chris@411 273 m_baseRecommendation = recommendation;
Chris@411 274 }
Chris@411 275