Почему Linux CFS не выделяет Free CPU другому доступному процессу очереди выполнения в Core2Duo? - PullRequest
0 голосов
/ 11 декабря 2018

Я работаю в Core2Duo, 2,20 ГГц системе с ОС Ubuntu-12.04, ядром 3.18.26.

Я внес некоторые изменения в исходный код ядра Linux.

Чтобы получить всеПроцессы, участвующие (который запланирован и который не запланирован) в переключении контекста, я внес изменения в ядро ​​(kernel / sched / core.c и добавил следующий оператор печати внутри функции context_switch).

trace_printk(KERN_INFO
    "**$$,context_switch,%d,%llu,%llu,%d,%llu,%llu\n",
    (int)(prev->pid),
    prev->se.vruntime,
    prev->se.sum_exec_runtime,
    (int)(next->pid),
    next->se.vruntime,
    next->se.sum_exec_runtime);`

Iя использую два разных процесса P1 (с 100 потоками - T0, T1, ..., T99) и P2 в одном ядре процессора.P2 уже долго работал, поэтому его vruntime высокий.

Внутри P1 создаются первые 100 потоков, все потоки, кроме T0, находятся в состоянии блокировки (в ожидании семафора).

  1. T0 выполняет некоторую задачу, затем устанавливает таймер с длительностью 2000 наносек и добровольно освобождает процессор.Поскольку нет доступных потоков, P2 назначается.
  2. После 2000 нсек таймер истек, и он пробуждает следующий поток T1, который немедленно вытесняет P2.
  3. T1 выполняет некоторую задачу, затем устанавливает таймер с длительностью 2000 наносек и добровольно освобождает процессор.Поскольку нет доступных потоков, P2 назначается.
  4. После 2000 нсек таймер истек, и он пробуждает следующий поток T2, который немедленно вытесняет P2.

Это повторяется, и потоки T0, T1, ... T99 выполняются циклически.

Итак, последовательность выполнения, как показано ниже

T0-P2-T1-P2-T2-P2-T3-......T99-P2-T0-P2.....

Мои экспериментальные результаты показывают, что

, когда я устанавливаю интервал таймера 1800 нсек, процесс P2 получает среднее значение 1450 нсек.

, когда я устанавливаю интервал таймера 2000 нсек, процесс P2 получает среднее значение 1600 нсек.,

когда я устанавливаю интервал таймера 2500 нсек, процесс P2 получает в среднем 2050 нсек.

когда я устанавливаю интервал таймера 3000 нсек, процесс P2 получает в среднем 2600 нсек.

Итак, я заключаю, что в моей системе Core2Duo время переключения контекста составляет около 350-450 нс. Правильно ли я это сказать?

Другое наблюдение состоит в том, чтоКогда я устанавливаю интервал таймера 1600 нсек или 1700 нсек, процесс P2 не планируется по расписанию между двумя потоками, хотя ЦП свободен - это означает, что ЦП становится свободным примерно на 1200-1300 нсек, хотя Р2 находится в очереди готовности, готов кзапустить.Почему это происходит?

Вот мой фрагмент кода:

// Program - P2
int main(int argc, char *argv[])
{
cpu_set_t my_set;        
CPU_ZERO(&my_set);       
CPU_SET(1, &my_set);     
sched_setaffinity(0, sizeof(cpu_set_t), &my_set);

while(1){

// does some task
   }
}



    // Program - P1
// timer handler awakening next thread
        static void handler(int sig, siginfo_t *si, void *uc)
        {
        thread_no++;
        ret = sem_post(&sem[(thread_no)%NUM_THREADS]);
            if (ret)
            {
                printf("Error in Sem Post\n");
            }
    }

void *threadA(void *data_)
{
int turn = (intptr_t)data_;
cpu_set_t my_set;        
CPU_ZERO(&my_set);       
CPU_SET(1, &my_set);     
sched_setaffinity(0, sizeof(cpu_set_t), &my_set);

while(1)
    {

        ret = sem_wait(&sem[turn]);
        if (ret)
        {
            printf("Error in Sem Post\n");
        }

        // does some work here


        its.it_value.tv_sec = 0;
        its.it_value.tv_nsec = DELAY1;
        its.it_interval.tv_sec = 0;
        its.it_interval.tv_nsec = 0;

        ret = timer_settime(timerid, 0, &its, NULL);
        if ( ret < 0 )
            perror("timer_settime");

    }  
}

int main(int argc, char *argv[])
{

    sa.sa_flags = SA_RESTART;
    sa.sa_sigaction = handler;
    sigemptyset(&sa.sa_mask);
    err = sigaction(SIG, &sa, NULL);
    if (0 != err) {
        printf("sigaction failed\n"); }

    sev.sigev_notify = SIGEV_SIGNAL;
    sev.sigev_signo = SIG;
    sev.sigev_value.sival_ptr = &timerid;
    ret = timer_create(CLOCKID, &sev, &timerid);
    if ( ret < 0 )
        perror("timer_create");

    sem_init(&sem[0], 0, 1); 
    for ( i = 1; i < NUM_THREADS; ++i)
        {
            sem_init(&sem[i], 0, 0); 
        }   
    data=0;    
    while(data < NUM_THREADS)
    {
        //create our threads
        err = pthread_create(&tid[data], NULL, threadA, (void *)(intptr_t)data);
        if(err != 0)
            printf("\n can't create thread :[%s]", strerror(err));
        data++;
    }
}

показывает трассировку ядра, CPU свободен, достаточно времени для переключения контекста - поток Ti на P2,пока P2 не запланирован, позднее происходит переключение контекста между Ti и T (i + 1). Почему linux CFS не выбирает следующий процесс для планирования в этом случае, если длительность таймера меньше 1700 нсек?

...