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@1038
|
68 size_t minimumSize,
|
Chris@1038
|
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@541
|
86 } catch (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
|