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@1276
|
100 SVDEBUG << "StorageAdviser: disc planned: " << (m_discPlanned / 1024)
|
Chris@1276
|
101 << "K, memory planned: " << (m_memoryPlanned / 1024) << "K" << endl;
|
Chris@1276
|
102 SVDEBUG << "StorageAdviser: min requested: " << minimumSize
|
Chris@1276
|
103 << "K, max requested: " << maximumSize << "K" << endl;
|
Chris@1276
|
104
|
Chris@1038
|
105 if (discFree > ssize_t(m_discPlanned / 1024 + 1)) {
|
Chris@205
|
106 discFree -= m_discPlanned / 1024 + 1;
|
Chris@205
|
107 } else if (discFree > 0) { // can also be -1 for unknown
|
Chris@205
|
108 discFree = 0;
|
Chris@205
|
109 }
|
Chris@205
|
110
|
Chris@1038
|
111 if (memoryFree > ssize_t(m_memoryPlanned / 1024 + 1)) {
|
Chris@205
|
112 memoryFree -= m_memoryPlanned / 1024 + 1;
|
Chris@205
|
113 } else if (memoryFree > 0) { // can also be -1 for unknown
|
Chris@205
|
114 memoryFree = 0;
|
Chris@205
|
115 }
|
Chris@205
|
116
|
Chris@192
|
117 //!!! We have a potentially serious problem here if multiple
|
Chris@192
|
118 //recommendations are made in advance of any of the resulting
|
Chris@192
|
119 //allocations, as the allocations that have been recommended for
|
Chris@192
|
120 //won't be taken into account in subsequent recommendations.
|
Chris@192
|
121
|
Chris@170
|
122 StorageStatus memoryStatus = Unknown;
|
Chris@170
|
123 StorageStatus discStatus = Unknown;
|
Chris@170
|
124
|
Chris@1038
|
125 ssize_t minmb = ssize_t(minimumSize / 1024 + 1);
|
Chris@1038
|
126 ssize_t maxmb = ssize_t(maximumSize / 1024 + 1);
|
Chris@170
|
127
|
Chris@170
|
128 if (memoryFree == -1) memoryStatus = Unknown;
|
Chris@1103
|
129 else if (memoryFree < memoryTotal / 3 && memoryFree < 512) memoryStatus = Insufficient;
|
Chris@170
|
130 else if (minmb > (memoryFree * 3) / 4) memoryStatus = Insufficient;
|
Chris@170
|
131 else if (maxmb > (memoryFree * 3) / 4) memoryStatus = Marginal;
|
Chris@170
|
132 else if (minmb > (memoryFree / 3)) memoryStatus = Marginal;
|
Chris@170
|
133 else if (memoryTotal == -1 ||
|
Chris@170
|
134 minmb > (memoryTotal / 10)) memoryStatus = Marginal;
|
Chris@170
|
135 else memoryStatus = Sufficient;
|
Chris@170
|
136
|
Chris@170
|
137 if (discFree == -1) discStatus = Unknown;
|
Chris@170
|
138 else if (minmb > (discFree * 3) / 4) discStatus = Insufficient;
|
Chris@173
|
139 else if (maxmb > (discFree / 4)) discStatus = Marginal;
|
Chris@173
|
140 else if (minmb > (discFree / 10)) discStatus = Marginal;
|
Chris@170
|
141 else discStatus = Sufficient;
|
Chris@170
|
142
|
Chris@1276
|
143 SVDEBUG << "StorageAdviser: memory status: " << memoryStatus
|
Chris@1276
|
144 << " (" << storageStatusToString(memoryStatus) << ")"
|
Chris@1276
|
145 << ", disc status " << discStatus
|
Chris@1276
|
146 << " (" << storageStatusToString(discStatus) << ")" << endl;
|
Chris@170
|
147
|
Chris@170
|
148 int recommendation = NoRecommendation;
|
Chris@170
|
149
|
Chris@170
|
150 if (memoryStatus == Insufficient || memoryStatus == Unknown) {
|
Chris@170
|
151
|
Chris@170
|
152 recommendation |= UseDisc;
|
Chris@170
|
153
|
Chris@170
|
154 if (discStatus == Insufficient && minmb > discFree) {
|
Chris@170
|
155 throw InsufficientDiscSpace(path, minmb, discFree);
|
Chris@170
|
156 }
|
Chris@170
|
157
|
Chris@170
|
158 if (discStatus == Insufficient || discStatus == Marginal) {
|
Chris@170
|
159 recommendation |= ConserveSpace;
|
Chris@170
|
160 } else if (discStatus == Unknown && !(criteria & PrecisionCritical)) {
|
Chris@170
|
161 recommendation |= ConserveSpace;
|
Chris@170
|
162 } else {
|
Chris@170
|
163 recommendation |= UseAsMuchAsYouLike;
|
Chris@170
|
164 }
|
Chris@170
|
165
|
Chris@170
|
166 } else if (memoryStatus == Marginal) {
|
Chris@170
|
167
|
Chris@170
|
168 if (((criteria & SpeedCritical) ||
|
Chris@170
|
169 (criteria & FrequentLookupLikely)) &&
|
Chris@170
|
170 !(criteria & PrecisionCritical) &&
|
Chris@170
|
171 !(criteria & LongRetentionLikely)) {
|
Chris@170
|
172
|
Chris@170
|
173 // requirements suggest a preference for memory
|
Chris@170
|
174
|
Chris@170
|
175 if (discStatus != Insufficient) {
|
Chris@170
|
176 recommendation |= PreferMemory;
|
Chris@170
|
177 } else {
|
Chris@170
|
178 recommendation |= UseMemory;
|
Chris@170
|
179 }
|
Chris@170
|
180
|
Chris@170
|
181 recommendation |= ConserveSpace;
|
Chris@170
|
182
|
Chris@170
|
183 } else {
|
Chris@170
|
184
|
Chris@170
|
185 if (discStatus == Insufficient) {
|
Chris@170
|
186 recommendation |= (UseMemory | ConserveSpace);
|
Chris@170
|
187 } else if (discStatus == Marginal) {
|
Chris@170
|
188 recommendation |= (PreferMemory | ConserveSpace);
|
Chris@170
|
189 } else if (discStatus == Unknown) {
|
Chris@170
|
190 recommendation |= (PreferDisc | ConserveSpace);
|
Chris@170
|
191 } else {
|
Chris@170
|
192 recommendation |= (UseDisc | UseAsMuchAsYouLike);
|
Chris@170
|
193 }
|
Chris@170
|
194 }
|
Chris@170
|
195
|
Chris@170
|
196 } else {
|
Chris@170
|
197
|
Chris@170
|
198 if (discStatus == Insufficient) {
|
Chris@170
|
199 recommendation |= (UseMemory | ConserveSpace);
|
Chris@170
|
200 } else if (discStatus != Sufficient) {
|
Chris@170
|
201 recommendation |= (PreferMemory | ConserveSpace);
|
Chris@170
|
202 } else {
|
Chris@170
|
203
|
Chris@170
|
204 if ((criteria & SpeedCritical) ||
|
Chris@170
|
205 (criteria & FrequentLookupLikely)) {
|
Chris@170
|
206 recommendation |= PreferMemory;
|
Chris@170
|
207 if (criteria & PrecisionCritical) {
|
Chris@170
|
208 recommendation |= UseAsMuchAsYouLike;
|
Chris@170
|
209 } else {
|
Chris@170
|
210 recommendation |= ConserveSpace;
|
Chris@170
|
211 }
|
Chris@170
|
212 } else {
|
Chris@170
|
213 recommendation |= PreferDisc;
|
Chris@170
|
214 recommendation |= UseAsMuchAsYouLike;
|
Chris@170
|
215 }
|
Chris@170
|
216 }
|
Chris@170
|
217 }
|
Chris@170
|
218
|
Chris@1276
|
219 SVDEBUG << "StorageAdviser: returning recommendation " << recommendation
|
Chris@1276
|
220 << " (" << recommendationToString(recommendation) << ")" << endl;
|
Chris@1098
|
221
|
Chris@170
|
222 return Recommendation(recommendation);
|
Chris@168
|
223 }
|
Chris@168
|
224
|
Chris@205
|
225 void
|
Chris@1038
|
226 StorageAdviser::notifyPlannedAllocation(AllocationArea area, size_t size)
|
Chris@205
|
227 {
|
Chris@205
|
228 if (area == MemoryAllocation) m_memoryPlanned += size;
|
Chris@205
|
229 else if (area == DiscAllocation) m_discPlanned += size;
|
Chris@1276
|
230 SVDEBUG << "StorageAdviser: storage planned up: now memory: " << m_memoryPlanned << ", disc "
|
Chris@1276
|
231 << m_discPlanned << endl;
|
Chris@205
|
232 }
|
Chris@205
|
233
|
Chris@205
|
234 void
|
Chris@1038
|
235 StorageAdviser::notifyDoneAllocation(AllocationArea area, size_t size)
|
Chris@205
|
236 {
|
Chris@205
|
237 if (area == MemoryAllocation) {
|
Chris@205
|
238 if (m_memoryPlanned > size) m_memoryPlanned -= size;
|
Chris@205
|
239 else m_memoryPlanned = 0;
|
Chris@205
|
240 } else if (area == DiscAllocation) {
|
Chris@205
|
241 if (m_discPlanned > size) m_discPlanned -= size;
|
Chris@205
|
242 else m_discPlanned = 0;
|
Chris@205
|
243 }
|
Chris@1276
|
244 SVDEBUG << "StorageAdviser: storage planned down: now memory: " << m_memoryPlanned << ", disc "
|
Chris@1276
|
245 << m_discPlanned << endl;
|
Chris@205
|
246 }
|
Chris@205
|
247
|
Chris@411
|
248 void
|
Chris@411
|
249 StorageAdviser::setFixedRecommendation(Recommendation recommendation)
|
Chris@411
|
250 {
|
Chris@411
|
251 m_baseRecommendation = recommendation;
|
Chris@411
|
252 }
|
Chris@411
|
253
|