У меня есть одна программа 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 получает в каждом прогоне перед вытеснением.
Вот некоторые из моих открытий, которые я не могу понять, почему?
При частоте ЦП = 2,2 ГГц, если я установлю интервал таймера 1700 нс или даже меньше, P2 не будет запланирован между двумя потоками. Почему P2 не запланирован, даже если не запущен другой процесс / поток, а ЦП свободен в течение 1700 нс?
С частотой ЦП= 3,4 ГГц, если я установлю интервал таймера 1000 нс или даже меньше, P2 не будет запланирован между двумя потоками. Почему P2 не запланирован, даже если другой процесс не запущен, а ЦП свободен в течение 1000 нс?
С другой частотой ЦП и для другого таймераинтервал, другой процесс P2 не запланирован?
Существует ли какая-либо связь между частотой процессора и временем истечения таймера?Это связано с синхронизацией переключения контекста?
Мой последний вопрос - если выполняется одно переключение контекста и будет готов новый процесс с более высоким приоритетом, будет ли завершено текущее переключение контекста, выполнено какое-то время, затем запланирован следующий процесс с более высоким приоритетом или он остановитсятекущее переключение контекста и немедленное планирование следующего процесса с более высоким приоритетом?
Я использую Core-i7 @ 3,40 ГГц, Ubuntu-16.04, cgroups отключены, и P1 и P2 работают на одном терминале.cpupower используется для установки частоты пользователя.
Заранее спасибо.