annotate base/StorageAdviser.cpp @ 1693:718ce5fb9fec single-point

Merge
author Chris Cannam
date Thu, 25 Apr 2019 11:30:51 +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