Mercurial > hg > svcore
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 |