comparison data/fft/FFTDataServer.cpp @ 215:a051929fef3b

* Attempt to improve management of FFT models that are not currently in use. I think these are some problems with this at the moment.
author Chris Cannam
date Fri, 19 Jan 2007 14:38:57 +0000
parents e0e7f6c5fda9
children 7f8ffe65d453
comparison
equal deleted inserted replaced
214:ce6f65ab3327 215:a051929fef3b
38 #define DEBUG_FFT_SERVER 1 38 #define DEBUG_FFT_SERVER 1
39 #endif 39 #endif
40 #endif 40 #endif
41 41
42 FFTDataServer::ServerMap FFTDataServer::m_servers; 42 FFTDataServer::ServerMap FFTDataServer::m_servers;
43 FFTDataServer::ServerQueue FFTDataServer::m_releasedServers;
43 QMutex FFTDataServer::m_serverMapMutex; 44 QMutex FFTDataServer::m_serverMapMutex;
44 45
45 FFTDataServer * 46 FFTDataServer *
46 FFTDataServer::getInstance(const DenseTimeValueModel *model, 47 FFTDataServer::getInstance(const DenseTimeValueModel *model,
47 int channel, 48 int channel,
231 232
232 QMutexLocker locker(&m_serverMapMutex); 233 QMutexLocker locker(&m_serverMapMutex);
233 234
234 for (ServerMap::iterator i = m_servers.begin(); i != m_servers.end(); ++i) { 235 for (ServerMap::iterator i = m_servers.begin(); i != m_servers.end(); ++i) {
235 if (i->second.first == server) { 236 if (i->second.first == server) {
237
238 for (ServerQueue::iterator j = m_releasedServers.begin();
239 j != m_releasedServers.end(); ++j) {
240 if (*j == server) {
241 m_releasedServers.erase(j);
242 break;
243 }
244 }
245
236 ++i->second.second; 246 ++i->second.second;
237 return; 247 return;
238 } 248 }
239 } 249 }
240 250
248 #ifdef DEBUG_FFT_SERVER 258 #ifdef DEBUG_FFT_SERVER
249 std::cerr << "FFTDataServer::releaseInstance(" << server << ")" << std::endl; 259 std::cerr << "FFTDataServer::releaseInstance(" << server << ")" << std::endl;
250 #endif 260 #endif
251 261
252 QMutexLocker locker(&m_serverMapMutex); 262 QMutexLocker locker(&m_serverMapMutex);
253
254 //!!! not a good strategy. Want something like:
255 263
256 // -- if ref count > 0, decrement and return 264 // -- if ref count > 0, decrement and return
257 // -- if the instance hasn't been used at all, delete it immediately 265 // -- if the instance hasn't been used at all, delete it immediately
258 // -- if fewer than N instances (N = e.g. 3) remain with zero refcounts, 266 // -- if fewer than N instances (N = e.g. 3) remain with zero refcounts,
259 // leave them hanging around 267 // leave them hanging around
262 // -- if we run out of disk space when allocating an instance, go back 270 // -- if we run out of disk space when allocating an instance, go back
263 // and delete the spare N instances before trying again 271 // and delete the spare N instances before trying again
264 // -- have an additional method to indicate that a model has been 272 // -- have an additional method to indicate that a model has been
265 // destroyed, so that we can delete all of its fft server instances 273 // destroyed, so that we can delete all of its fft server instances
266 274
267 // also:
268 //
269
270 for (ServerMap::iterator i = m_servers.begin(); i != m_servers.end(); ++i) { 275 for (ServerMap::iterator i = m_servers.begin(); i != m_servers.end(); ++i) {
271 if (i->second.first == server) { 276 if (i->second.first == server) {
272 if (i->second.second == 0) { 277 if (i->second.second == 0) {
273 std::cerr << "ERROR: FFTDataServer::releaseInstance(" 278 std::cerr << "ERROR: FFTDataServer::releaseInstance("
274 << server << "): instance not allocated" << std::endl; 279 << server << "): instance not allocated" << std::endl;
275 } else if (--i->second.second == 0) { 280 } else if (--i->second.second == 0) {
276 if (server->m_lastUsedCache == -1) { // never used 281 if (server->m_lastUsedCache == -1) { // never used
277 delete server; 282 delete server;
278 m_servers.erase(i); 283 m_servers.erase(i);
279 } else { 284 } else {
285 m_releasedServers.push_back(server);
280 server->suspend(); 286 server->suspend();
281 purgeLimbo(); 287 purgeLimbo();
282 } 288 }
283 } 289 }
284 return; 290 return;
290 } 296 }
291 297
292 void 298 void
293 FFTDataServer::purgeLimbo(int maxSize) 299 FFTDataServer::purgeLimbo(int maxSize)
294 { 300 {
295 ServerMap::iterator i = m_servers.end(); 301 while (m_releasedServers.size() > maxSize) {
296 302
297 int count = 0; 303 FFTDataServer *server = *m_releasedServers.begin();
298 304
299 while (i != m_servers.begin()) { 305 bool found = false;
300 --i; 306
301 if (i->second.second == 0) { 307 for (ServerMap::iterator i = m_servers.begin(); i != m_servers.end(); ++i) {
302 if (++count > maxSize) { 308
303 delete i->second.first; 309 if (i->second.first == server) {
310 found = true;
311 if (i->second.second > 0) {
312 std::cerr << "ERROR: FFTDataServer::purgeLimbo: Server "
313 << server << " is in released queue, but still has non-zero refcount "
314 << i->second.second << std::endl;
315 // ... so don't delete it
316 break;
317 }
304 m_servers.erase(i); 318 m_servers.erase(i);
305 return; 319 delete server;
306 } 320 break;
321 }
322 }
323
324 if (!found) {
325 std::cerr << "ERROR: FFTDataServer::purgeLimbo: Server "
326 << server << " is in released queue, but not in server map!"
327 << std::endl;
328 delete server;
329 }
330
331 m_releasedServers.pop_front();
332 }
333 }
334
335 void
336 FFTDataServer::modelAboutToBeDeleted(Model *model)
337 {
338 QMutexLocker locker(&m_serverMapMutex);
339
340 for (ServerMap::iterator i = m_servers.begin(); i != m_servers.end(); ++i) {
341
342 FFTDataServer *server = i->second.first;
343
344 if (server->getModel() == model) {
345 if (i->second.second > 0) {
346 std::cerr << "ERROR: FFTDataServer::modelAboutToBeDeleted: Model " << model << " (\"" << model->objectName().toStdString() << "\") is about to be deleted, but is still being referred to by FFT server " << server << " with non-zero refcount " << i->second.second << std::endl;
347 }
348 for (ServerQueue::iterator j = m_releasedServers.begin();
349 j != m_releasedServers.end(); ++j) {
350 if (*j == server) {
351 m_releasedServers.erase(j);
352 break;
353 }
354 }
355 m_servers.erase(i);
356 delete server;
357 return;
307 } 358 }
308 } 359 }
309 } 360 }
310 361
311 FFTDataServer::FFTDataServer(QString fileBaseName, 362 FFTDataServer::FFTDataServer(QString fileBaseName,
372 } 423 }
373 424
374 int cells = m_width * m_height; 425 int cells = m_width * m_height;
375 int minimumSize = (cells / 1024) * sizeof(uint16_t); // kb 426 int minimumSize = (cells / 1024) * sizeof(uint16_t); // kb
376 int maximumSize = (cells / 1024) * sizeof(float); // kb 427 int maximumSize = (cells / 1024) * sizeof(float); // kb
377
378 // This can throw InsufficientDiscSpace. We don't catch it here -- we
379 // haven't allocated anything yet and can safely let the exception out.
380 // Caller needs to check for it.
381 428
382 StorageAdviser::Recommendation recommendation = 429 StorageAdviser::Recommendation recommendation;
383 StorageAdviser::recommend(criteria, minimumSize, maximumSize); 430
431 try {
432
433 recommendation =
434 StorageAdviser::recommend(criteria, minimumSize, maximumSize);
435
436 } catch (InsufficientDiscSpace s) {
437
438 // Delete any unused servers we may have been leaving around
439 // in case we wanted them again
440
441 purgeLimbo(0);
442
443 // This time we don't catch InsufficientDiscSpace -- we
444 // haven't allocated anything yet and can safely let the
445 // exception out to indicate to the caller that we can't
446 // handle it.
447
448 recommendation =
449 StorageAdviser::recommend(criteria, minimumSize, maximumSize);
450 }
384 451
385 std::cerr << "Recommendation was: " << recommendation << std::endl; 452 std::cerr << "Recommendation was: " << recommendation << std::endl;
386 453
387 m_memoryCache = ((recommendation & StorageAdviser::UseMemory) || 454 m_memoryCache = ((recommendation & StorageAdviser::UseMemory) ||
388 (recommendation & StorageAdviser::PreferMemory)); 455 (recommendation & StorageAdviser::PreferMemory));