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

У меня есть одна программа P1, имеющая N (100) потоков.Первоначально все потоки находятся в состоянии блокировки (с использованием семафора), кроме потока 0.

// Program - P1
    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++;
    }
} 

Я создал один таймер, используя timer_create () внутри программы P1 (и все потоки используют один и тот же таймер), устанавливает таймер с интервалом T. По истечении интервала таймера вызывается обработчик таймера, который отправляет сигнал следующему потоку i + 1 для пробуждения.

Вот как работают мои программы

Step 1: Thread 0 does some work, sets timer ,goes into block state ( releasing CPU )

Step 2: On timer expiration, timer handler called 

Step 3: Thread 1 is awaken, does some work, sets timer , goes into block state ( releasing CPU )

Step 4: On timer expiration, timer handler called 
Step 5: Thread 2 is awaken, does some work, sets timer , goes into block state ( releasing CPU )
:

:

:


Step 2n-1: next thread  Thread n-1 is awaken, does some work, sets timer , goes into block state ( releasing CPU )

Step 2n:  On timer expiration, timer handler called 

Step 2n+1: next thread  Thread 0 is awaken, does some work, sets timer , goes into block state ( releasing CPU )

Это отлично работает, все мои потоки пробуждаются обработчиком таймера и работают в циклическом порядке.

У меня есть другая программаP2 работает непрерывно в течение длительного времени (поэтому vruntime очень высок), даже до того, как P1 начинает работать, и P2 находится в одном ядре ЦП с P1 (со всеми потоками).

// 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
   }
}

Итак, когда не будет запущенных потоков, Должен быть запущен P2.

Итак, я ожидаю, что на шаге 1 поток 0 освобождает ЦП, должен быть запланирован P2 и истекает таймер момента и пробуждается следующий поток на шаге 3, P2 должен быть немедленно прерван.согласно политике планирования CFS (поскольку vruntime пробужденного потока очень низок по сравнению с P2).Это означает, что я ожидаю, что P2 будет запланирован между Step1-Step3, Step3-Step5, когда все потоки находятся в состоянии блокировки, процессор свободен и следующий поток еще не пробужден.

Чтобы получить все процессы, вовлеченные в контекстпереключаясь, я сделал изменения в ядре ( 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);

, чтобы я мог получить все детали процессов, которые получаютсязапланированный и который запланирован.Из вышеприведенной информации я вычислил, сколько времени P2 получает в каждом прогоне перед вытеснением.

Вот некоторые из моих открытий, которые я не могу понять, почему?

  1. При частоте ЦП = 2,2 ГГц, если я установлю интервал таймера 1700 нс или даже меньше, P2 не будет запланирован между двумя потоками. Почему P2 не запланирован, даже если не запущен другой процесс / поток, а ЦП свободен в течение 1700 нс?

  2. С частотой ЦП= 3,4 ГГц, если я установлю интервал таймера 1000 нс или даже меньше, P2 не будет запланирован между двумя потоками. Почему P2 не запланирован, даже если другой процесс не запущен, а ЦП свободен в течение 1000 нс?

С другой частотой ЦП и для другого таймераинтервал, другой процесс P2 не запланирован?

Существует ли какая-либо связь между частотой процессора и временем истечения таймера?Это связано с синхронизацией переключения контекста?

Мой последний вопрос - если выполняется одно переключение контекста и будет готов новый процесс с более высоким приоритетом, будет ли завершено текущее переключение контекста, выполнено какое-то время, затем запланирован следующий процесс с более высоким приоритетом или он остановитсятекущее переключение контекста и немедленное планирование следующего процесса с более высоким приоритетом?

Я использую Core-i7 @ 3,40 ГГц, Ubuntu-16.04, cgroups отключены, и P1 и P2 работают на одном терминале.cpupower используется для установки частоты пользователя.

Заранее спасибо.

...