comparison data/fft/FFTDataServer.cpp @ 216:7f8ffe65d453

* Fixes to FFT server lifecycle management
author Chris Cannam
date Mon, 22 Jan 2007 13:20:54 +0000
parents a051929fef3b
children b3dfc3714006
comparison
equal deleted inserted replaced
215:a051929fef3b 216:7f8ffe65d453
185 distance += ((server->getFFTSize() / fftSize) - 1) * 10; 185 distance += ((server->getFFTSize() / fftSize) - 1) * 10;
186 186
187 if (server->getFillCompletion() < 50) distance += 100; 187 if (server->getFillCompletion() < 50) distance += 100;
188 188
189 #ifdef DEBUG_FFT_SERVER 189 #ifdef DEBUG_FFT_SERVER
190 std::cerr << "Distance " << distance << ", best is " << bestdist << std::endl; 190 std::cerr << "FFTDataServer::getFuzzyInstance: Distance for server " << server << " is " << distance << ", best is " << bestdist << std::endl;
191 #endif 191 #endif
192 192
193 if (bestdist == -1 || distance < bestdist) { 193 if (bestdist == -1 || distance < bestdist) {
194 bestdist = distance; 194 bestdist = distance;
195 best = i; 195 best = i;
196 } 196 }
197 } 197 }
198 } 198 }
199 199
200 if (bestdist >= 0) { 200 if (bestdist >= 0) {
201 ++best->second.second; 201 FFTDataServer *server = best->second.first;
202 return best->second.first; 202 #ifdef DEBUG_FFT_SERVER
203 std::cerr << "FFTDataServer::getFuzzyInstance: We like server " << server << " (with distance " << bestdist << ")" << std::endl;
204 #endif
205 claimInstance(server, false);
206 return server;
203 } 207 }
204 } 208 }
205 209
206 // Nothing found, make a new one 210 // Nothing found, make a new one
207 211
216 } 220 }
217 221
218 FFTDataServer * 222 FFTDataServer *
219 FFTDataServer::findServer(QString n) 223 FFTDataServer::findServer(QString n)
220 { 224 {
225 #ifdef DEBUG_FFT_SERVER
226 std::cerr << "FFTDataServer::findServer(\"" << n.toStdString() << "\")" << std::endl;
227 #endif
228
221 if (m_servers.find(n) != m_servers.end()) { 229 if (m_servers.find(n) != m_servers.end()) {
222 ++m_servers[n].second; 230
223 return m_servers[n].first; 231 FFTDataServer *server = m_servers[n].first;
224 } 232
233 #ifdef DEBUG_FFT_SERVER
234 std::cerr << "FFTDataServer::findServer(\"" << n.toStdString() << "\"): found " << server << std::endl;
235 #endif
236
237 claimInstance(server, false);
238
239 return server;
240 }
241
242 #ifdef DEBUG_FFT_SERVER
243 std::cerr << "FFTDataServer::findServer(\"" << n.toStdString() << "\"): not found" << std::endl;
244 #endif
225 245
226 return 0; 246 return 0;
227 } 247 }
228 248
229 void 249 void
230 FFTDataServer::claimInstance(FFTDataServer *server) 250 FFTDataServer::claimInstance(FFTDataServer *server)
231 { 251 {
232 252 claimInstance(server, true);
233 QMutexLocker locker(&m_serverMapMutex); 253 }
254
255 void
256 FFTDataServer::claimInstance(FFTDataServer *server, bool needLock)
257 {
258 QMutexLocker locker(needLock ? &m_serverMapMutex : 0);
259
260 #ifdef DEBUG_FFT_SERVER
261 std::cerr << "FFTDataServer::claimInstance(" << server << ")" << std::endl;
262 #endif
234 263
235 for (ServerMap::iterator i = m_servers.begin(); i != m_servers.end(); ++i) { 264 for (ServerMap::iterator i = m_servers.begin(); i != m_servers.end(); ++i) {
236 if (i->second.first == server) { 265 if (i->second.first == server) {
237 266
238 for (ServerQueue::iterator j = m_releasedServers.begin(); 267 for (ServerQueue::iterator j = m_releasedServers.begin();
239 j != m_releasedServers.end(); ++j) { 268 j != m_releasedServers.end(); ++j) {
269
240 if (*j == server) { 270 if (*j == server) {
271 #ifdef DEBUG_FFT_SERVER
272 std::cerr << "FFTDataServer::claimInstance: found in released server list, removing from it" << std::endl;
273 #endif
241 m_releasedServers.erase(j); 274 m_releasedServers.erase(j);
242 break; 275 break;
243 } 276 }
244 } 277 }
245 278
246 ++i->second.second; 279 ++i->second.second;
280
281 #ifdef DEBUG_FFT_SERVER
282 std::cerr << "FFTDataServer::claimInstance: new refcount is " << i->second.second << std::endl;
283 #endif
284
247 return; 285 return;
248 } 286 }
249 } 287 }
250 288
251 std::cerr << "ERROR: FFTDataServer::claimInstance: instance " 289 std::cerr << "ERROR: FFTDataServer::claimInstance: instance "
253 } 291 }
254 292
255 void 293 void
256 FFTDataServer::releaseInstance(FFTDataServer *server) 294 FFTDataServer::releaseInstance(FFTDataServer *server)
257 { 295 {
296 releaseInstance(server, true);
297 }
298
299 void
300 FFTDataServer::releaseInstance(FFTDataServer *server, bool needLock)
301 {
302 QMutexLocker locker(needLock ? &m_serverMapMutex : 0);
303
258 #ifdef DEBUG_FFT_SERVER 304 #ifdef DEBUG_FFT_SERVER
259 std::cerr << "FFTDataServer::releaseInstance(" << server << ")" << std::endl; 305 std::cerr << "FFTDataServer::releaseInstance(" << server << ")" << std::endl;
260 #endif 306 #endif
261
262 QMutexLocker locker(&m_serverMapMutex);
263 307
264 // -- if ref count > 0, decrement and return 308 // -- if ref count > 0, decrement and return
265 // -- if the instance hasn't been used at all, delete it immediately 309 // -- if the instance hasn't been used at all, delete it immediately
266 // -- if fewer than N instances (N = e.g. 3) remain with zero refcounts, 310 // -- if fewer than N instances (N = e.g. 3) remain with zero refcounts,
267 // leave them hanging around 311 // leave them hanging around
277 if (i->second.second == 0) { 321 if (i->second.second == 0) {
278 std::cerr << "ERROR: FFTDataServer::releaseInstance(" 322 std::cerr << "ERROR: FFTDataServer::releaseInstance("
279 << server << "): instance not allocated" << std::endl; 323 << server << "): instance not allocated" << std::endl;
280 } else if (--i->second.second == 0) { 324 } else if (--i->second.second == 0) {
281 if (server->m_lastUsedCache == -1) { // never used 325 if (server->m_lastUsedCache == -1) { // never used
326 #ifdef DEBUG_FFT_SERVER
327 std::cerr << "FFTDataServer::releaseInstance: instance "
328 << server << " has never been used, erasing"
329 << std::endl;
330 #endif
282 delete server; 331 delete server;
283 m_servers.erase(i); 332 m_servers.erase(i);
284 } else { 333 } else {
285 m_releasedServers.push_back(server); 334 #ifdef DEBUG_FFT_SERVER
335 std::cerr << "FFTDataServer::releaseInstance: instance "
336 << server << " no longer in use, marking for possible collection"
337 << std::endl;
338 #endif
339 bool found = false;
340 for (ServerQueue::iterator j = m_releasedServers.begin();
341 j != m_releasedServers.end(); ++j) {
342 if (*j == server) {
343 std::cerr << "ERROR: FFTDataServer::releaseInstance("
344 << server << "): server is already in "
345 << "released servers list" << std::endl;
346 found = true;
347 }
348 }
349 if (!found) m_releasedServers.push_back(server);
286 server->suspend(); 350 server->suspend();
287 purgeLimbo(); 351 purgeLimbo();
288 } 352 }
353 } else {
354 #ifdef DEBUG_FFT_SERVER
355 std::cerr << "FFTDataServer::releaseInstance: instance "
356 << server << " now has refcount " << i->second.second
357 << std::endl;
358 #endif
289 } 359 }
290 return; 360 return;
291 } 361 }
292 } 362 }
293 363
296 } 366 }
297 367
298 void 368 void
299 FFTDataServer::purgeLimbo(int maxSize) 369 FFTDataServer::purgeLimbo(int maxSize)
300 { 370 {
371 #ifdef DEBUG_FFT_SERVER
372 std::cerr << "FFTDataServer::purgeLimbo(" << maxSize << "): "
373 << m_releasedServers.size() << " candidates" << std::endl;
374 #endif
375
301 while (m_releasedServers.size() > maxSize) { 376 while (m_releasedServers.size() > maxSize) {
302 377
303 FFTDataServer *server = *m_releasedServers.begin(); 378 FFTDataServer *server = *m_releasedServers.begin();
304 379
305 bool found = false; 380 bool found = false;
381
382 #ifdef DEBUG_FFT_SERVER
383 std::cerr << "FFTDataServer::purgeLimbo: considering candidate "
384 << server << std::endl;
385 #endif
306 386
307 for (ServerMap::iterator i = m_servers.begin(); i != m_servers.end(); ++i) { 387 for (ServerMap::iterator i = m_servers.begin(); i != m_servers.end(); ++i) {
308 388
309 if (i->second.first == server) { 389 if (i->second.first == server) {
310 found = true; 390 found = true;
313 << server << " is in released queue, but still has non-zero refcount " 393 << server << " is in released queue, but still has non-zero refcount "
314 << i->second.second << std::endl; 394 << i->second.second << std::endl;
315 // ... so don't delete it 395 // ... so don't delete it
316 break; 396 break;
317 } 397 }
398 #ifdef DEBUG_FFT_SERVER
399 std::cerr << "FFTDataServer::purgeLimbo: looks OK, erasing it"
400 << std::endl;
401 #endif
402
318 m_servers.erase(i); 403 m_servers.erase(i);
319 delete server; 404 delete server;
320 break; 405 break;
321 } 406 }
322 } 407 }
328 delete server; 413 delete server;
329 } 414 }
330 415
331 m_releasedServers.pop_front(); 416 m_releasedServers.pop_front();
332 } 417 }
418
419 #ifdef DEBUG_FFT_SERVER
420 std::cerr << "FFTDataServer::purgeLimbo(" << maxSize << "): "
421 << m_releasedServers.size() << " remain" << std::endl;
422 #endif
423
333 } 424 }
334 425
335 void 426 void
336 FFTDataServer::modelAboutToBeDeleted(Model *model) 427 FFTDataServer::modelAboutToBeDeleted(Model *model)
337 { 428 {
338 QMutexLocker locker(&m_serverMapMutex); 429 QMutexLocker locker(&m_serverMapMutex);
430
431 #ifdef DEBUG_FFT_SERVER
432 std::cerr << "FFTDataServer::modelAboutToBeDeleted(" << model << ")"
433 << std::endl;
434 #endif
339 435
340 for (ServerMap::iterator i = m_servers.begin(); i != m_servers.end(); ++i) { 436 for (ServerMap::iterator i = m_servers.begin(); i != m_servers.end(); ++i) {
341 437
342 FFTDataServer *server = i->second.first; 438 FFTDataServer *server = i->second.first;
343 439
344 if (server->getModel() == model) { 440 if (server->getModel() == model) {
441
442 #ifdef DEBUG_FFT_SERVER
443 std::cerr << "FFTDataServer::modelAboutToBeDeleted: server is "
444 << server << std::endl;
445 #endif
446
345 if (i->second.second > 0) { 447 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; 448 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 } 449 }
348 for (ServerQueue::iterator j = m_releasedServers.begin(); 450 for (ServerQueue::iterator j = m_releasedServers.begin();
349 j != m_releasedServers.end(); ++j) { 451 j != m_releasedServers.end(); ++j) {
350 if (*j == server) { 452 if (*j == server) {
453 #ifdef DEBUG_FFT_SERVER
454 std::cerr << "FFTDataServer::modelAboutToBeDeleted: erasing from released servers" << std::endl;
455 #endif
351 m_releasedServers.erase(j); 456 m_releasedServers.erase(j);
352 break; 457 break;
353 } 458 }
354 } 459 }
460 #ifdef DEBUG_FFT_SERVER
461 std::cerr << "FFTDataServer::modelAboutToBeDeleted: erasing server" << std::endl;
462 #endif
355 m_servers.erase(i); 463 m_servers.erase(i);
356 delete server; 464 delete server;
357 return; 465 return;
358 } 466 }
359 } 467 }
395 size_t end = m_model->getEndFrame(); 503 size_t end = m_model->getEndFrame();
396 504
397 m_width = (end - start) / m_windowIncrement + 1; 505 m_width = (end - start) / m_windowIncrement + 1;
398 m_height = m_fftSize / 2 + 1; // DC == 0, Nyquist == fftsize/2 506 m_height = m_fftSize / 2 + 1; // DC == 0, Nyquist == fftsize/2
399 507
508 #ifdef DEBUG_FFT_SERVER
509 std::cerr << "FFTDataServer(" << this << "): dimensions are "
510 << m_width << "x" << m_height << std::endl;
511 #endif
512
400 size_t maxCacheSize = 20 * 1024 * 1024; 513 size_t maxCacheSize = 20 * 1024 * 1024;
401 size_t columnSize = m_height * sizeof(fftsample) * 2 + sizeof(fftsample); 514 size_t columnSize = m_height * sizeof(fftsample) * 2 + sizeof(fftsample);
402 if (m_width * columnSize < maxCacheSize * 2) m_cacheWidth = m_width; 515 if (m_width * columnSize < maxCacheSize * 2) m_cacheWidth = m_width;
403 else m_cacheWidth = maxCacheSize / columnSize; 516 else m_cacheWidth = maxCacheSize / columnSize;
404 517
781 void 894 void
782 FFTDataServer::getValuesAt(size_t x, size_t y, float &real, float &imaginary) 895 FFTDataServer::getValuesAt(size_t x, size_t y, float &real, float &imaginary)
783 { 896 {
784 Profiler profiler("FFTDataServer::getValuesAt", false); 897 Profiler profiler("FFTDataServer::getValuesAt", false);
785 898
899 if (x >= m_width || y >= m_height) {
900 real = 0;
901 imaginary = 0;
902 return;
903 }
904
786 size_t col; 905 size_t col;
787 FFTCache *cache = getCache(x, col); 906 FFTCache *cache = getCache(x, col);
788 if (!cache) { real = 0; imaginary = 0; return; } 907
908 if (!cache) {
909 real = 0;
910 imaginary = 0;
911 return;
912 }
789 913
790 if (!cache->haveSetColumnAt(col)) { 914 if (!cache->haveSetColumnAt(col)) {
791 #ifdef DEBUG_FFT_SERVER 915 #ifdef DEBUG_FFT_SERVER
792 std::cerr << "FFTDataServer::getValuesAt(" << x << ", " << y << "): filling" << std::endl; 916 std::cerr << "FFTDataServer::getValuesAt(" << x << ", " << y << "): filling" << std::endl;
793 #endif 917 #endif