ossrs/state-threads

Performance improvement for st_usleep.

winlinvip opened this issue · 0 comments

The resolution for epoll_wait is ms, while the st_usleep is us.

ST_HIDDEN void _st_epoll_dispatch(void)
{
    ......

    if (_ST_SLEEPQ == NULL) {
        timeout = -1;
    } else {
        min_timeout = (_ST_SLEEPQ->due <= _ST_LAST_CLOCK) ? 0 : (_ST_SLEEPQ->due - _ST_LAST_CLOCK);
        timeout = (int) (min_timeout / 1000);
    }

    /* Check for I/O operations */
    nfd = epoll_wait(_st_epoll_data->epfd, _st_epoll_data->evtlist, _st_epoll_data->evtlist_size, timeout);
int st_usleep(st_utime_t usecs)
{
    ......

    if (usecs != ST_UTIME_NO_TIMEOUT) {
        me->state = _ST_ST_SLEEPING;
        _ST_ADD_SLEEPQ(me, usecs);

void _st_add_sleep_q(_st_thread_t *thread, st_utime_t timeout)
{
    thread->due = _ST_LAST_CLOCK + timeout;
    thread->flags |= _ST_FL_ON_SLEEPQ;
    thread->heap_index = ++_ST_SLEEPQ_SIZE;
    heap_insert(thread);
}
void _st_vp_check_clock(void)
{
    ......

    now = st_utime();
    elapsed = now - _ST_LAST_CLOCK;
    _ST_LAST_CLOCK = now;
    
    while (_ST_SLEEPQ != NULL) {
        thread = _ST_SLEEPQ;
        ST_ASSERT(thread->flags & _ST_FL_ON_SLEEPQ);
        if (thread->due > now)
            break;
        _ST_DEL_SLEEPQ(thread);
        
        ......

        /* Make thread runnable */
        ST_ASSERT(!(thread->flags & _ST_FL_IDLE_THREAD));
        thread->state = _ST_ST_RUNNABLE;
        _ST_ADD_RUNQ(thread);

What happends when there is a lot of timer, so that the 0us<timeout<1ms? The _st_epoll_dispatch consumes lots of CPUs, because epoll_wait(0ms) while the timer does not run(>0us).

当系统有非常多的timer时,会出现0us<timeout<1ms的情况,这时候epoll会立刻返回epoll_wait(0ms),但是timer并不会执行(>0us)还没有到准确的唤醒时间。