Как спать на несколько микросекунд - PullRequest
7 голосов
/ 13 февраля 2011

Рассмотрим следующий код:

#include <stdio.h>
#include <time.h>
#include <math.h>

// Compile with gcc -lrt -lm -o test_clock test_clock.c

#define CLOCK CLOCK_MONOTONIC

int main(int argc, char** argv) {
    double temp, elapsed;
    int j;
    struct timespec requestStart, requestEnd, req;

    // Pseudo-sleep
    clock_gettime(CLOCK, &requestStart);
    temp = 0;
    for(j=0; j < 40; j++)
        temp += sin(j);
    clock_gettime(CLOCK, &requestEnd);
    elapsed = ( requestEnd.tv_sec - requestStart.tv_sec ) / 1e-6
                 + ( requestEnd.tv_nsec - requestStart.tv_nsec ) / 1e3;
    printf("Elapsed: %lf us\n", elapsed);

    // Nanosleep
    clock_gettime(CLOCK, &requestStart);
    req.tv_nsec = 5000;
    req.tv_sec = 0;
    clock_nanosleep(CLOCK, 0, &req, NULL);
    clock_gettime(CLOCK, &requestEnd);
    elapsed = ( requestEnd.tv_sec - requestStart.tv_sec ) / 1e-6
                 + ( requestEnd.tv_nsec - requestStart.tv_nsec ) / 1e3;

    printf("Elapsed: %lf us\n", elapsed);

}

В моей системе 2.6.32 результат равен

Elapsed: 5.308000 us
Elapsed: 69.142000 us

Я согласен, что это наиболее вероятно, потому что nanosleep () просит ядро ​​перепланировать процесс. Как я могу избежать этого? Я хочу сохранить владение процессором и просто бездействовать в течение точного времени.

Ответы [ 7 ]

8 голосов
/ 14 февраля 2011

Если вы хотите, чтобы ваше приложение могло "спать" как можно точнее, сначала поместите ваше приложение в режим реального времени

  • используйте класс планировщика реального времени для вашей программы / потока: SCHED_FIFO или SCHED_RR
  • повысить приоритетность вашей программы / потока
  • и если вы собираетесь "спать" меньше, чем минимальное количество, которое будет обрабатывать ядро, занято вручную

Взгляните на http://www.drdobbs.com/184402031

И этот другой вопрос: Использование процессора с высоким энергопотреблением?

7 голосов
/ 13 февраля 2011

Планировщик ОС не собирается делать что-то вроде: «О, снимите этот поток с процессора ровно на 86 тактов, а затем снова включите».

Вы отказываетесь от процессора, вы отказались от процессора. ОС вернет вас обратно, когда он захочет. Скорее всего, вам придется подождать, пока все, что работает, не выйдет из процессора, прежде чем вы сможете снова включиться.

2 голосов
/ 09 июля 2014
// busy wait for 10 microseconds
struct timespec ttime,curtime;

// get the time
clock_gettime(CLOCK_REALTIME,&ttime);

// clear the nanoseconds and keep the seconds in order not to overflow the nanoseconds
ttime.tv_nsec = 0;

// set it back
clock_settime(CLOCK_REALTIME,&ttime);

// get the time again 
clock_gettime(CLOCK_REALTIME,&ttime);

// increase the nano seconds by 10*1000
ttime.tv_nsec += 10000;

// loop
while(true){
  clock_gettime(CLOCK_REALTIME,&curtime);
  if (curtime.tv_nsec > ttime.tv_nsec)
    break;
}

// это намного лучше, чем уснуть.

2 голосов
/ 14 февраля 2011

Что ж, вам придется научиться жить с этим, так как страница руководства гласит: the actual time slept may be longer, due to system latencies and possible limitations in the timer resolution of the hardware: -)

Теперь, что касается ответа на ваш вопрос, я думаю, это потому, что ваш первый цикл выполняется в процессе. Другими словами, здесь не используются переключатели контекста, так как вы работаете с центральным процессором и будете выполнять всю эту работу в пределах ваших 100 мс квантов, предоставленных вам планировщиком.

Тем не менее, есть большая вероятность, что nanosleep вас отключит, поскольку вы явно просите усыпить. Это не будет настолько неэффективно, что просто поместить ваш процесс в узкий цикл while, пока продолжительность не закончится:

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

1 голос
/ 09 октября 2012

Вы можете использовать метод usleep, чтобы заснуть в микросекундных единицах.

0 голосов
/ 14 февраля 2011

Это промежуточный ответ - я не знаю соответствующих внутренних компонентов linux, надеюсь, что эксперт может прийти и разобраться с этим.

Одна из возможностей заключается в том, что 69us - это просто сырые накладные расходы на планирование и планирование.затем перепланировать поток.Несмотря на короткий сон, ядро ​​может проделать большую работу для переключения контекста (или половины переключения контекста, если нечего планировать), а затем отменить его почти немедленно.Я не знаю, сколько времени это «должно» занять на linux на типичном ПК.

Если это не объясняет, у планировщика обычно есть понятие «временного интервала», то есть как долгозапланированный поток останется запущенным до того, как планировщик подумает о его переключении, если только он не отменяет сам себя, или что-то с более высоким приоритетом становится планируемым.Ядро будет иметь низкоуровневые таймеры, запускающие прерывания в конце временного интервала (в дополнение к прерываниям, которые запускаются для некоторых других событий, таких как ввод / вывод, которые могут разблокировать поток).Когда временной интервал заканчивается, планировщик может решить, продолжить ли тот же поток или переключиться на другой.

Так что, когда вы спите, похоже, либо (а) планировщик фактически не устанавливает таймерэто сделает ваш поток планируемым в запрошенное время, он просто ожидает временной интервал, и поэтому процессор простаивает дольше, чем необходимо;или (b) он делает ваш поток планируемым в запрошенное время, но когда вы прекратили выполнение в спящем режиме, вошел какой-то другой поток с равным приоритетом, и у планировщика нет оснований предпочитать вас этому, пока не наступит ваша очередь«опять же, согласно тем правилам, которые обычно использует планировщик, чтобы решить, какой поток запланировать.

69us довольно короток, чтобы быть артефактом временного среза.Вы можете задержать на очень короткие периоды, сидя в цикле, проверяя время, как спин-блокировка.Однако, как говорят все остальные, в системе не в реальном времени, более или менее по определению, вы не можете требовать, чтобы планировщик запускал ваш поток в любое конкретное время.Даже в системе реального времени, если вы конкурируете с потоками с равным приоритетом, вы можете проиграть, а если вы конкурируете с потоками с более высоким приоритетом, вы потеряете .

0 голосов
/ 14 февраля 2011

Эффективность - операционная система, которая позволяла включать и выключать задачи с точностью до нескольких тактов, сделала бы очень мало.

Существуют специализированные ОС, которые делают это, но на обычном оборудовании вы платитемного накладных расходов для гипервизора

...