trunk/src/osd/modules/sync/work_osd.c
| r242719 | r242720 | |
| 53 | 53 | |
| 54 | 54 | #define ENV_PROCESSORS "OSDPROCESSORS" |
| 55 | 55 | |
| 56 | // TODO: tests have shown, that 50000 appears to be the best value |
| 56 | 57 | #if defined(OSD_WINDOWS) |
| 57 | 58 | #define SPIN_LOOP_TIME (osd_ticks_per_second() / 1000) |
| 58 | 59 | #else |
| r242719 | r242720 | |
| 74 | 75 | #define end_timing(v) do { } while (0) |
| 75 | 76 | #endif |
| 76 | 77 | |
| 78 | // TODO: move this in a common place |
| 77 | 79 | #if __GNUC__ && defined(__i386__) && !defined(__x86_64) |
| 78 | 80 | #undef YieldProcessor |
| 79 | 81 | #endif |
| r242719 | r242720 | |
| 167 | 169 | static void * worker_thread_entry(void *param); |
| 168 | 170 | static void worker_thread_process(osd_work_queue *queue, work_thread_info *thread); |
| 169 | 171 | static bool queue_has_list_items(osd_work_queue *queue); |
| 172 | static void spin_on_queue(work_thread_info *thread, osd_work_queue *queue, osd_ticks_t timeout); |
| 170 | 173 | |
| 171 | 174 | |
| 172 | 175 | //============================================================ |
| r242719 | r242720 | |
| 204 | 207 | // on a single-CPU system, create 1 thread for I/O queues, and 0 threads for everything else |
| 205 | 208 | if (numprocs == 1) |
| 206 | 209 | queue->threads = (flags & WORK_QUEUE_FLAG_IO) ? 1 : 0; |
| 210 | // TODO: chose either |
| 207 | 211 | #if defined(OSD_WINDOWS) |
| 208 | 212 | // on an n-CPU system, create n threads for multi queues, and 1 thread for everything else |
| 209 | 213 | else |
| r242719 | r242720 | |
| 217 | 221 | if (osdworkqueuemaxthreads != NULL && sscanf(osdworkqueuemaxthreads, "%d", &threadnum) == 1 && queue->threads > threadnum) |
| 218 | 222 | queue->threads = threadnum; |
| 219 | 223 | |
| 224 | // TODO: do we still have the scaling problems? |
| 220 | 225 | #if defined(OSD_WINDOWS) |
| 221 | 226 | // multi-queues with high frequency items should top out at 4 for now |
| 222 | 227 | // since we have scaling problems above that |
| r242719 | r242720 | |
| 307 | 312 | // if we're a high frequency queue, spin until done |
| 308 | 313 | if (queue->flags & WORK_QUEUE_FLAG_HIGH_FREQ && queue->items != 0) |
| 309 | 314 | { |
| 310 | | osd_ticks_t stopspin = osd_ticks() + timeout; |
| 311 | | |
| 312 | | // spin until we're done |
| 313 | | begin_timing(thread->spintime); |
| 314 | | |
| 315 | | #if defined(OSD_WINDOWS) |
| 316 | | while (queue->items != 0 && osd_ticks() < stopspin) |
| 317 | | osd_yield_processor(); |
| 318 | | #else |
| 319 | | do { |
| 320 | | int spin = 10000; |
| 321 | | while (--spin && queue->items != 0) |
| 322 | | osd_yield_processor(); |
| 323 | | } while (queue->items != 0 && osd_ticks() < stopspin); |
| 324 | | #endif |
| 325 | | |
| 326 | | end_timing(thread->spintime); |
| 327 | | |
| 315 | spin_on_queue(thread, queue, timeout); |
| 328 | 316 | begin_timing(thread->waittime); |
| 329 | 317 | return (queue->items == 0); |
| 330 | 318 | } |
| r242719 | r242720 | |
| 562 | 550 | // if we don't have an event, we need to spin (shouldn't ever really happen) |
| 563 | 551 | if (item->event == NULL) |
| 564 | 552 | { |
| 553 | // TODO: merge this with spin_on_queue() |
| 554 | // TODO: do we need to measure the spin time here as well? and how can we do it? |
| 565 | 555 | osd_ticks_t stopspin = osd_ticks() + timeout; |
| 566 | 556 | #if defined(OSD_WINDOWS) |
| 567 | 557 | while (!item->done && osd_ticks() < stopspin) |
| r242719 | r242720 | |
| 684 | 674 | // process work items |
| 685 | 675 | for ( ;; ) |
| 686 | 676 | { |
| 687 | | osd_ticks_t stopspin; |
| 688 | | |
| 689 | 677 | // process as much as we can |
| 690 | 678 | worker_thread_process(queue, thread); |
| 691 | 679 | |
| 692 | 680 | // if we're a high frequency queue, spin for a while before giving up |
| 693 | 681 | if (queue->flags & WORK_QUEUE_FLAG_HIGH_FREQ && queue->list == NULL) |
| 694 | 682 | { |
| 695 | | // spin for a while looking for more work |
| 696 | | begin_timing(thread->spintime); |
| 697 | | stopspin = osd_ticks() + SPIN_LOOP_TIME; |
| 698 | | |
| 699 | | #if defined(OSD_WINDOWS) |
| 700 | | while (queue->list == NULL && osd_ticks() < stopspin) |
| 701 | | osd_yield_processor(); |
| 702 | | #else |
| 703 | | do { |
| 704 | | int spin = 10000; |
| 705 | | while (--spin && queue->list == NULL) |
| 706 | | osd_yield_processor(); |
| 707 | | } while (queue->list == NULL && osd_ticks() < stopspin); |
| 708 | | #endif |
| 709 | | |
| 710 | | end_timing(thread->spintime); |
| 683 | spin_on_queue(thread, queue, SPIN_LOOP_TIME); |
| 711 | 684 | } |
| 712 | 685 | |
| 713 | 686 | // if nothing more, release the processor |
| r242719 | r242720 | |
| 822 | 795 | osd_scalable_lock_release(queue->lock, lockslot); |
| 823 | 796 | return has_list_items; |
| 824 | 797 | } |
| 798 | |
| 799 | void spin_on_queue(work_thread_info *thread, osd_work_queue *queue, osd_ticks_t timeout) |
| 800 | { |
| 801 | osd_ticks_t stopspin = osd_ticks() + timeout; |
| 802 | |
| 803 | begin_timing(thread->spintime); |
| 804 | |
| 805 | // TODO: chose either |
| 806 | #if defined(OSD_WINDOWS) |
| 807 | while (queue->list == NULL && osd_ticks() < stopspin) |
| 808 | osd_yield_processor(); |
| 809 | #else |
| 810 | do { |
| 811 | int spin = 10000; |
| 812 | while (--spin && queue->list == NULL) |
| 813 | osd_yield_processor(); |
| 814 | } while (queue->list == NULL && osd_ticks() < stopspin); |
| 815 | #endif |
| 816 | |
| 817 | end_timing(thread->spintime); |
| 818 | } |
| | No newline at end of file |