Почему Free CPU не выделяется для обработки в Linux?

У меня есть одна программа 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 и добавил следующую инструкцию print внутри функции 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. С частотой CPU =2,2 ГГц, если я установлю интервал таймера 1700 нс или даже меньше, P2 не будет запланирован между двумя потоками. Почему P2 не запланирован, даже если не запущен другой процесс / поток и процессор свободен в течение 1700 нс?

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

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

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

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

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

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

0 ответов

Другие вопросы по тегам