Дискретность задержки usleep() и nanosleep() под Linux
От: Vladimir Davydov Украина  
Дата: 15.11.02 08:57
Оценка:
Написал, вот, программку, передающую данные в виде пакетов с заданной скоростью. Заданную скорость задаю путем внесения задержек между пакетами. Задержки делаю с помощью функции usleep(). Запускаю я эту программку под Linux.
И, вот, на какую проблему я наткнулся.
Скорость регулируется скачкообразно, так как usleep() и nanosleep() имеют дискретность задержки в 10 миллисекунд. То есть, нужно, например, сделать задержку 17 мс, а получается только или 10, или 20. И скорость плавно отрегулировать не удается.

Подскажите, пожалуйста, как цивилизованным путем (без 100% загрузки CPU на время задержки) можно добиться задержки с меньшей дискретностью ?
Re: Дискретность задержки usleep() и nanosleep() под Linux
От: Tom Россия http://www.RSDN.ru
Дата: 15.11.02 10:25
Оценка:
Llinux это не RealTime система и эта задача может быть решена только написанием драйвера.
Народная мудрось
всем все никому ничего(с).
Re: Дискретность задержки usleep() и nanosleep() под Linux
От: Kubyshev Andrey  
Дата: 16.11.02 08:06
Оценка:
Здравствуйте, Vladimir Davydov, Вы писали:

Esli eto u tebya serioznyi project, obrati vnimanie na www.rtlinux.com — real time linux.
Re[2]: Дискретность задержки usleep() и nanosleep() под Linu
От: DSD Россия http://911.ru/cv
Дата: 17.11.02 02:15
Оценка:
Здравствуйте, Kubyshev Andrey, Вы писали:

KA>Здравствуйте, Vladimir Davydov, Вы писали:


KA>Esli eto u tebya serioznyi project, obrati vnimanie na www.rtlinux.com — real time linux.


А еще лучше: http://www.qnx.org
--
DSD
Re[3]: Дискретность задержки usleep() и nanosleep() под Linu
От: Kubyshev Andrey  
Дата: 17.11.02 08:40
Оценка:
Здравствуйте, DSD, Вы писали:

DSD>А еще лучше: http://www.qnx.org


Na samom dele ee "luchshest'" dovol'no sporna. Ee izvechnymi nedostatkami yavlyautsya
1. Platnost' dlya commercial usage,
2. Medlennoe razvitie (za 2 goda v nei ne pribavilos' nichego new)
3. Razlichnye bottlenecki v systeme tipa neeffektivnoe disk I/O na kotorye developery prosto zabili.


vse eto ya podcherpnul chitaya newsgroups na news.qnx.com
Re: Дискретность задержки usleep() и nanosleep() под Linux
От: maxp Россия http://penzin.ru/
Дата: 18.11.02 07:13
Оценка:
Здравствуйте, Vladimir Davydov, Вы писали:

VD>Написал, вот, программку, передающую данные в виде пакетов с заданной скоростью. Заданную скорость задаю путем внесения задержек между пакетами. Задержки делаю с помощью функции usleep(). Запускаю я эту программку под Linux.

VD>И, вот, на какую проблему я наткнулся.
VD>Скорость регулируется скачкообразно, так как usleep() и nanosleep() имеют дискретность задержки в 10 миллисекунд. То есть, нужно, например, сделать задержку 17 мс, а получается только или 10, или 20. И скорость плавно отрегулировать не удается.

VD>Подскажите, пожалуйста, как цивилизованным путем (без 100% загрузки CPU на время задержки) можно добиться задержки с меньшей дискретностью ?


10 мс это размер одного кванта времени выделяемого приложению.

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

если я правильно помню, то у nanospeel() есть интересная фича — при маленьких
величинах задержки там работает просто калиброванный пустой цикл, а переключения контекстов
не происходит.

как вариант можно поглядеть в сорцы линуксового кернела на предмет константы HZ,
можно попробовать немного поуменьшить размер кванта времени.
Re[2]: Дискретность задержки usleep() и nanosleep() под Linu
От: Vladimir Davydov Украина  
Дата: 19.11.02 08:24
Оценка:
Здравствуйте, maxp, Вы писали:

M>Здравствуйте, Vladimir Davydov, Вы писали:


M>10 мс это размер одного кванта времени выделяемого приложению.


M>обычно функции типа sleep() вызывают переключение контекста задачи, и вообще в многозадачных системах

M>как-то не принятно полагаться на выделение квантов в точно указанное время,
M>лучше просто брать текущий отсчет gettimeofday() он достаточно точный, т.е. по сути это
M>скорректированный пентиум-каунтер.

Сделал вот так:
void musleep(int usec)
{
  struct timeval tv1, tv2;
  gettimeofday(&tv1, NULL);
  do gettimeofday(&tv2, NULL);
  while ((tv2.tv_sec-tv1.tv_sec)*1000000+(tv2.tv_usec-tv1.tv_usec) < usec);
}

Работает правильно. Но самый большой недостаток этого метода --
это то, что даже один запущенный экземпляр этой функции забирает 100% CPU.
С трудом представляю себе, что они намеряют, если их будет запущено
одновременно 1000 штук.
Re[3]: Дискретность задержки usleep() и nanosleep() под Linu
От: maxp Россия http://penzin.ru/
Дата: 19.11.02 08:42
Оценка:
Здравствуйте, Vladimir Davydov, Вы писали:

M>>10 мс это размер одного кванта времени выделяемого приложению.


M>>обычно функции типа sleep() вызывают переключение контекста задачи, и вообще в многозадачных системах

M>>как-то не принятно полагаться на выделение квантов в точно указанное время,
M>>лучше просто брать текущий отсчет gettimeofday() он достаточно точный, т.е. по сути это
M>>скорректированный пентиум-каунтер.

VD>Сделал вот так:

void musleep(int usec)
{
  struct timeval tv1, tv2;
  gettimeofday(&tv1, NULL);
  do gettimeofday(&tv2, NULL);
  while ((tv2.tv_sec-tv1.tv_sec)*1000000+(tv2.tv_usec-tv1.tv_usec) < usec);
}


VD>Работает правильно. Но самый большой недостаток этого метода --

VD>это то, что даже один запущенный экземпляр этой функции забирает 100% CPU.
VD>С трудом представляю себе, что они намеряют, если их будет запущено
VD>одновременно 1000 штук.

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

в данном случае schedlue() будет происходить во время gettimeofday()
Re: Дискретность задержки usleep() и nanosleep() под Linux
От: svd  
Дата: 20.11.02 22:25
Оценка:
Здравствуйте, Vladimir Davydov, Вы писали:

VD>Написал, вот, программку, передающую данные в виде пакетов с заданной скоростью. Заданную скорость задаю путем внесения задержек между пакетами. Задержки делаю с помощью функции usleep(). Запускаю я эту программку под Linux.

VD>И, вот, на какую проблему я наткнулся.
VD>Скорость регулируется скачкообразно, так как usleep() и nanosleep() имеют дискретность задержки в 10 миллисекунд. То есть, нужно, например, сделать задержку 17 мс, а получается только или 10, или 20.
VD>И скорость плавно отрегулировать не удается.

Ну о какой плавности можно говорить в дискретном мире? Всё определяется степенью дискретности. К тому же как бы "плавно" не передавались данные от источника, всегда наложит свой отпечаток среда передачи, поэтому к месту назначения они могут прийти совсем не так уж и "плавно" Я так понимаю, что речь идёт о передаче пакетов по сети? Но в принципе, это касается не только сети?

VD>Подскажите, пожалуйста, как цивилизованным путем (без 100% загрузки CPU на время задержки) можно добиться задержки с меньшей дискретностью ?


А вообще изначальная задача-то какая была?
Именно передавать пакеты с определёнными интервалами или влиять на скорость прохождения, пропускную способность?
Re: Дискретность задержки usleep() и nanosleep() под Linux
От: Murr Россия  
Дата: 27.01.03 17:43
Оценка: 1 (1)
Здравствуйте, Vladimir Davydov, Вы писали:

VD>Написал, вот, программку, передающую данные в виде пакетов с заданной скоростью. Заданную скорость задаю путем внесения задержек между пакетами. Задержки делаю с помощью функции usleep(). Запускаю я эту программку под Linux.

VD>И, вот, на какую проблему я наткнулся.
VD>Скорость регулируется скачкообразно, так как usleep() и nanosleep() имеют дискретность задержки в 10 миллисекунд. То есть, нужно, например, сделать задержку 17 мс, а получается только или 10, или 20. И скорость плавно отрегулировать не удается.

VD>Подскажите, пожалуйста, как цивилизованным путем (без 100% загрузки CPU на время задержки) можно добиться задержки с меньшей дискретностью ?


В свое время я читал статью об использовании local APIC таймера для создания точных (с разрешением в микросекунду) задержек ("m-second precision timer support for Linux kernel" Uwe Walter, Vincent Oberle). Не знаю включили ли эту идею в новые ядра, а если и нет, то для старых должен быть доступен патч, на котором они проводили тестирование QoS.

Это, конечно, если приложение для x86, точнее даже P6.
Re: Дискретность задержки usleep() и nanosleep() под Linux
От: m.a.g. Мальта http://dottedmag.net/
Дата: 28.01.03 07:24
Оценка:
Здравствуйте, Vladimir Davydov, Вы писали:

VD>Подскажите, пожалуйста, как цивилизованным путем (без 100% загрузки CPU на время задержки) можно добиться задержки с меньшей дискретностью ?


Вроде бы я уже писал... Или это про Солярис было?

Выдержка из man select:

В некоторых программах select вызывается с тремя пустыми наборами файлов, n равным нулю, и ненулевым значением time-
out, что является довольно переносимым способом сделать задержку с миллисекундной точностью.

... << Павел Фомичев [Музыка Эльфов] Листопад >> ...
Re[2]: Дискретность задержки usleep() и nanosleep() под Linu
От: Murr Россия  
Дата: 28.01.03 10:10
Оценка:
Здравствуйте, m.a.g., Вы писали:

MAG>Здравствуйте, Vladimir Davydov, Вы писали:


VD>>Подскажите, пожалуйста, как цивилизованным путем (без 100% загрузки CPU на время задержки) можно добиться задержки с меньшей дискретностью ?


MAG>Вроде бы я уже писал... Или это про Солярис было?


MAG>Выдержка из man select:

MAG>

MAG> В некоторых программах select вызывается с тремя пустыми наборами файлов, n равным нулю, и ненулевым значением time-
MAG> out, что является довольно переносимым способом сделать задержку с миллисекундной точностью.

Вообще-то проблема несколько глубже. Все ОС, которые не являются ОС реального времени гарантируют лишь то, что обработчик получит управление после истечения нужного времени. В Linux задержки select обрабатываются так:

#define HZ 100

...

if ((unsigned long) sec < MAX_SELECT_SECONDS) {
    timeout = ROUND_UP(usec, 1000000/HZ);
    timeout += sec * (unsigned long) HZ;
}

далее при необходимости происходит schedule_timeout (timeout).
Re[3]: Дискретность задержки usleep() и nanosleep() под Linu
От: m.a.g. Мальта http://dottedmag.net/
Дата: 28.01.03 10:24
Оценка:
Здравствуйте, Murr, Вы писали:

M>Вообще-то проблема несколько глубже. Все ОС, которые не являются ОС реального времени гарантируют лишь то, что обработчик получит управление после истечения нужного времени.


Ну, это общая проблема не RT-осей. Если нужна точность, то нжуно менять ось...
... << DDT [] track13.mp3 >> ...
Re: Дискретность задержки usleep() и nanosleep() под Linux
От: RXL  
Дата: 02.02.03 01:10
Оценка:
Здравствуйте, Vladimir Davydov, Вы писали:

VD>Написал, вот, программку, передающую данные в виде пакетов с заданной скоростью. Заданную скорость задаю путем внесения задержек между пакетами. Задержки делаю с помощью функции usleep(). Запускаю я эту программку под Linux.

VD>И, вот, на какую проблему я наткнулся.
VD>Скорость регулируется скачкообразно, так как usleep() и nanosleep() имеют дискретность задержки в 10 миллисекунд. То есть, нужно, например, сделать задержку 17 мс, а получается только или 10, или 20. И скорость плавно отрегулировать не удается.

VD>Подскажите, пожалуйста, как цивилизованным путем (без 100% загрузки CPU на время задержки) можно добиться задержки с меньшей дискретностью ?

В Linux-е nanosleep() с задержкой до 2мс выполняется циклом задерки (100% CPU на этот период) и с точностью 1/HZ секунд (HZ=100 для PC) для большего периода.
Более-менее точную задержку можно сделать так: сначала nanosleep на ((n/10)*10)мс, а затем (n%5) раз вызвать nanosleep на 2мс и затем (n&1) раз на 1мс.
Нагрузка на проц значительно уменьшится, но для нескольких таких процессов не подойдет.
Re[3]: Дискретность задержки usleep() и nanosleep() под Linu
От: Аноним  
Дата: 02.02.03 10:19
Оценка:
Здравствуйте, Vladimir Davydov, Вы писали:

VD>Сделал вот так:

VD>
VD>void musleep(int usec)
VD>{
VD>  struct timeval tv1, tv2;
VD>  gettimeofday(&tv1, NULL);
VD>  do gettimeofday(&tv2, NULL);
VD>  while ((tv2.tv_sec-tv1.tv_sec)*1000000+(tv2.tv_usec-tv1.tv_usec) < usec);
VD>}
VD>

VD>Работает правильно. Но самый большой недостаток этого метода --
VD>это то, что даже один запущенный экземпляр этой функции забирает 100% CPU.
VD>С трудом представляю себе, что они намеряют, если их будет запущено
VD>одновременно 1000 штук.

Если это работает, то точно 17 миллисекунд ты можешь отмерить таким образом: 10 мс -- usleep, а оставшееся время (7 мс) busy wait, своим musleep'ом.

--
Дмитрий
Re: Дискретность задержки usleep() и nanosleep() под Linux
От: Аноним  
Дата: 29.06.06 09:25
Оценка:
Здравствуйте, Vladimir Davydov, Вы писали:

VD>Написал, вот, программку, передающую данные в виде пакетов с заданной скоростью. Заданную скорость задаю путем внесения задержек между пакетами. Задержки делаю с помощью функции usleep(). Запускаю я эту программку под Linux.

VD>И, вот, на какую проблему я наткнулся.
VD>Скорость регулируется скачкообразно, так как usleep() и nanosleep() имеют дискретность задержки в 10 миллисекунд. То есть, нужно, например, сделать задержку 17 мс, а получается только или 10, или 20. И скорость плавно отрегулировать не удается.

VD>Подскажите, пожалуйста, как цивилизованным путем (без 100% загрузки CPU на время задержки) можно добиться задержки с меньшей дискретностью ?



Владимир, так было ли найдено Вами решение этой проблемы ?

Я пока пробую адаптировать APIC таймер под ядро 2.6.
Re: Дискретность задержки usleep() и nanosleep() под Linux
От: Zline  
Дата: 03.07.06 08:54
Оценка:
Здравствуйте, Vladimir Davydov, Вы писали:

VD>Написал, вот, программку, передающую данные в виде пакетов с заданной скоростью. Заданную скорость задаю путем внесения задержек между пакетами. Задержки делаю с помощью функции usleep(). Запускаю я эту программку под Linux.

VD>И, вот, на какую проблему я наткнулся.
VD>Скорость регулируется скачкообразно, так как usleep() и nanosleep() имеют дискретность задержки в 10 миллисекунд. То есть, нужно, например, сделать задержку 17 мс, а получается только или 10, или 20. И скорость плавно отрегулировать не удается.

VD>Подскажите, пожалуйста, как цивилизованным путем (без 100% загрузки CPU на время задержки) можно добиться задержки с меньшей дискретностью ?


Хм, тоже столкнулся с этой задачей, правда пока решение не особо критично. Однако возникает вопрос: зачем usleep принимает аргумент в микросекундах, если может обеспечить точность лишь 10мс?
Re[2]: Дискретность задержки usleep() и nanosleep() под Linu
От: ДимДимыч Украина http://klug.org.ua
Дата: 03.07.06 09:24
Оценка:
Здравствуйте, Zline, Вы писали:

Z>Хм, тоже столкнулся с этой задачей, правда пока решение не особо критично. Однако возникает вопрос: зачем usleep принимает аргумент в микросекундах, если может обеспечить точность лишь 10мс?


Вы удивитесь, но есть еще nanosleep()
А аргументы у них такие, чтобы соответствовать стандартам: usleep — 4.3BSD, nanosleep — POSIX.
Обязательно бахнем! И не раз. Весь мир в труху! Но потом. (ДМБ)
Re[2]: Дискретность задержки usleep() и nanosleep() под Linu
От: srggal Украина  
Дата: 03.07.06 14:46
Оценка:
Здравствуйте, Zline, Вы писали:

Давно не ковырялся в Linux, примерно с того года, юак начался топик

Но, помнится была такая пересенная HZ в ядре — которая как раз и регулировала кванты, тогда, на 2.4 по дефолту на x86 было значения для 10 миллисек, НО был lowlatency patch который снижал, и прилично latency, попробуйте поиграть с ним, если найдете.

На тот момент, в ядре обычного, т.е. не rtLinux не было, да и не могло быть, способа, который бы что-либо гарантирова в части временных задержек — хоть что-то.
Должен заметить, что была очередm в ядре, задачи из которой выполнялись ASAP, но опять же — никаких гарантий на время, да, это быстрей 10 миллисек.
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Re: Дискретность задержки usleep() и nanosleep() под Linux
От: Zline  
Дата: 03.07.06 16:51
Оценка:
Здравствуйте, Vladimir Davydov, Вы писали:

VD>Написал, вот, программку, передающую данные в виде пакетов с заданной скоростью. Заданную скорость задаю путем внесения задержек между пакетами. Задержки делаю с помощью функции usleep(). Запускаю я эту программку под Linux.

VD>И, вот, на какую проблему я наткнулся.
VD>Скорость регулируется скачкообразно, так как usleep() и nanosleep() имеют дискретность задержки в 10 миллисекунд. То есть, нужно, например, сделать задержку 17 мс, а получается только или 10, или 20. И скорость плавно отрегулировать не удается.

VD>Подскажите, пожалуйста, как цивилизованным путем (без 100% загрузки CPU на время задержки) можно добиться задержки с меньшей дискретностью ?


Решил проверить точность функции usleep с помощью такой програмы:

#include <stdio.h>
#include <stdlib.h>
#include <sys/time.h>
#include <unistd.h>

typedef unsigned int dword;

dword mcs(struct timeval *base, struct timeval *cur)
{
        return((cur->tv_sec - base->tv_sec)*1000000 + cur->tv_usec - base->tv_usec);
}

int main(int argc,char **argv)
{
        struct timeval start,stop;
        int i,j;
        dword totl;

        for (j=5; j<155; j+=5)
        {
                printf("%3d: ",j);
                totl = 0;
                for (i=0; i<10; i++)
                {
                        gettimeofday(&start,NULL);
                        usleep(j*1000);
                        gettimeofday(&stop,NULL);
                        totl += mcs(&start,&stop);
                }
                printf("-> %d\n",totl/10);
        }
        return(0);
}

Слева — значение в миллисекундах, переданное usleep'у. Справа — продолжительность задержки, в микросекундах, замеренная с помощью gettimeofday, завязанной на внутренний таймер с частотой порядка 1.2МГц, т.е. имхо весьма точное значение.
(замер производится 10 раз чтобы вычислить более-менее среднее значение)
и вот результат на Linux debian 2.4.27-2-386:
  5: -> 19802
 10: -> 20001
 15: -> 30001
 20: -> 29999
 25: -> 40004
 30: -> 40003
 35: -> 50004
 40: -> 50005
 45: -> 60010
 50: -> 60002
 55: -> 70011
 60: -> 70007
 65: -> 80011
 70: -> 80140
 75: -> 90019
 80: -> 89712
 85: -> 100038
 90: -> 99980
 95: -> 110113
100: -> 110164
105: -> 119912
110: -> 120193
115: -> 129770
120: -> 130021
125: -> 140091
130: -> 139957
135: -> 150052
140: -> 150009
145: -> 159617
150: -> 160016


Либо я где-то ошибся, либо имхо результаты отвратительны. Тут даже не 10мс, тут все 15мс ошибки.

для сравнения решил проверить виндовую Sleep аналогичной программой, время замерял с помощью QueryPerformanceCounter, заметил любопытную закономерность — на процессорах intel точность порядка 1мс! :
  5: -> 5761
 10: -> 10740
 15: -> 15622
 20: -> 20505
 25: -> 25388
 30: -> 30270
 35: -> 35153
 40: -> 40035
 45: -> 45895
 50: -> 50778
 55: -> 55660
 60: -> 60542
 65: -> 65425
 70: -> 70308
 75: -> 75189
 80: -> 80074
 85: -> 85931
 90: -> 90815
 95: -> 95697
100: -> 100580
105: -> 105463
110: -> 110345
115: -> 115228
120: -> 120111
125: -> 124994
130: -> 130848
135: -> 135735
140: -> 140617
145: -> 145500
150: -> 150383

а на AMD похуже, но все же не так плачевно как у usleep:

  5: -> 8877
 10: -> 11712
 15: -> 15621
 20: -> 23432
 25: -> 27337
 30: -> 31248
 35: -> 35150
 40: -> 43020
 45: -> 46822
 50: -> 50779
 55: -> 58595
 60: -> 62498
 65: -> 66681
 70: -> 70486
 75: -> 78856
 80: -> 82092
 85: -> 87666
 90: -> 93925
 95: -> 98062
100: -> 103907
105: -> 107449
110: -> 113277
115: -> 117663
120: -> 121512
125: -> 126868
130: -> 135169
135: -> 136734
140: -> 141040
145: -> 148836
150: -> 153046


Всвязи с вышесказанным решил делать некоторую калибровку в софтинах, юзающих эти функции с малыми задержками (< 50ms). Или все-таки мои выводы неверны и где-то я ошибся?

зы. и как винде удается достичь точности в 1мс (пусть и только на интеловских процах)?
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.