LINUX.ORG.RU

Задержки в gettimeofday()?


0

0

В моей программе иногда вызывается эта функция для получения точного времени (нужно хотя бы миллисекунды) и после нескольких экспериментов я пришёл к выводу, что вызов gettimeofday иногда привносит в выполнение программы достаточно ощутимые задержки (до 200 мсек). Хотелось бы разобраться с этим вопросом и в первую очередь хотелось бы посмотреть на исходник gettimeofday, но я не знаю где его откопать (в glibc?). Может быть есть какой-нибудь другой способ получения точного времени, скажем чтение из /dev/rtc? Хотя я не уверен, что gettimeofday не поступает именно так. В общем, был бы благодарен за комментарии по этому поводу знающих людей :-)

anonymous

> ощутимые задержки (до 200 мсек)

msec или usec? в любом случае много.

скорее всего, просто выполняется другой процесс.

исходники здесь: kernel/time.c:do_gettimeofday()

единственно, что может замедлить этот вызов - это
если кто-то постоянно берет write_seqlock на xtime.

idle ★★★★★
()
Ответ на: комментарий от idle

Спасибо за ответ!

>исходники здесь: kernel/time.c:do_gettimeofday()

Я нашёл там только интерфейсы к ней, они вызывают do_gettimeofday(), а где она определена найти не могу. Ядро 2.4.22.

>единственно, что может замедлить этот вызов - это если кто-то постоянно берет write_seqlock на xtime.

А где-нибудь можно почитать об этом подробнее, а то для меня всё это звучит очень незнакомо :-(

anonymous
()
Ответ на: комментарий от anonymous

> а где она определена найти не могу. Ядро 2.4.22

в 4.2 смотрите arch/i386/kernel/time.c:do_gettimeofday()

еще раз, как вы определяете задержку? скорее всего, во
время этой "задержки" выполняется другой процесc.

idle ★★★★★
()
Ответ на: комментарий от idle

Проблема возникает при параллельной работе двух и более моих процессов (извиняюсь, из моего сообщения это не было ясно). Каждый из них на работает в бесконечном цикле и в течение одного прохода вызывает gettimeofday() несколько раз. То есть, судя по исходнику gettimeofday() (спасибо, нашёл), перед чтением происходит ожидание освобождения замка и в этом может быть главная причина задержки, особенно если учесть, что get..() вызывается несколько раз за цикл? Извиняюсь за возможно идиотский вопрос, но можно делать то же самое, но без замков? :-) Или единственный выход -- читать время только один раз за проход?

anonymous
()
Ответ на: комментарий от anonymous

> Проблема возникает при параллельной работе двух и более моих процессов
> Каждый из них на работает в бесконечном цикле и в течение одного прохода вызывает gettimeofday()

а процессоров в вашем компьютере сколько? один?

ну так как же они оба могут работать без задержек?

idle ★★★★★
()
Ответ на: комментарий от idle

Процессор один. Просто время выполнения одного цикла при работе двух процессов возрастает где-то аж в 2000 раз по сравнению с одним.

anonymous
()
Ответ на: комментарий от anonymous

> Просто время выполнения одного цикла при работе двух
> процессов возрастает где-то аж в 2000

для каждой итерации, или только для некоторых?

и еще раз, задержка в 200 чего?

idle ★★★★★
()
Ответ на: комментарий от idle

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

anonymous
()
Ответ на: комментарий от idle

Для одного в среднем ~70--100 usec, для двух ~60000--120000 usec. Пробовал в init 3, выключив практически все сервисы.

anonymous
()
Ответ на: комментарий от anonymous

> Для одного в среднем ~70--100 usec, для двух ~60000--120000 usec

это что, время выполнения gettimeofday?

послушайте, попытайтесь четко сформулировать проблему.

вас же спрашивают: каждая итерация, или только некоторые
замедляются?

напишите минимальный тестовый пример, который демонстрирует
проблему, покажите код.

я думаю, проблема где-то у вас. не может gettimeofday()
тормозить на 1 cpu из-за переключений между 2-мя процессами.

idle ★★★★★
()
Ответ на: комментарий от anonymous

>Для одного в среднем ~70--100 usec, для двух ~60000--120000 usec.

Где ты берёш такие странные цифры??

На стандартном 2.4 ядре задержки должны составлять 10 милисекунд на один вызов gettimeofday().

cvv ★★★★★
()
Ответ на: комментарий от cvv

> На стандартном 2.4 ядре задержки должны составлять
> 10 милисекунд на один вызов gettimeofday()

cvv, я думаю, эта опИска.

на моем P3 1.1 GHz меньше микросекунды на вызов.
правда, мерял на 2.6 + sysenter.

на 2.2 чуть побольше, но все равно такой же порядок.

idle ★★★★★
()
Ответ на: комментарий от cvv

Sorry, offtopic

strace -f ./soffice 2>&1|grep gettimeofday|nl

177 [pid 5192] gettimeofday({1102952067, 895967}, NULL) = 0
178 [pid 5192] gettimeofday({1102952067, 927583}, NULL) = 0
179 [pid 5192] gettimeofday({1102952067, 931603}, NULL) = 0
180 [pid 5192] gettimeofday({1102952067, 932118}, NULL) = 0
181 [pid 5192] gettimeofday({1102952067, 932479}, NULL) = 0

То есть я правильно понимаю, что openoffice для полной загрузки почти 2 секунды (1810мс) тратит на вызов gettimeofday?

Я написал в эту тему, потому что давно заметил, что этих вызовов очень много при загрузке, и при отслеживании в strace чаще всего он подвисает именно на gettimeofday.

Интересно, можно ли сделать "ускоряющий" hook для soffice в glibc? Кстати, если загрузить OpenOffice и подождать секунд десять, то количество вызовов от момента старта возрастет до ~650, итого 6,5 секунд. Это много, вам так не кажется?

saper ★★★★★
()
Ответ на: Sorry, offtopic от saper

> strace -f ./soffice 2>&1|grep gettimeofday|nl

strace -e trace=gettimeofday будет получше.

> 177 [pid 5192] gettimeofday({1102952067, 895967}, NULL) = 0
> 178 [pid 5192] gettimeofday({1102952067, 927583}, NULL) = 0
>
> То есть я правильно понимаю, что openoffice для полной загрузки
> почти 2 секунды (1810мс) тратит на вызов gettimeofday?

почему вы так решили?

у strace еще флаг -T есть. правда, сам strace замедляет
выполнение программы, особенно для таких "легковесных"
вызовов.

idle ★★★★★
()
Ответ на: комментарий от idle

>> На стандартном 2.4 ядре задержки должны составлять

>> 10 милисекунд на один вызов gettimeofday()

>cvv, я думаю, эта опИска.

неа. на моей системе все вызовы gettimeofday() которые я когда либо трассировал имели именно такую длительность. Ни больше ни меньше. что мне сильно мешало. А вообщето ета ситуация неплохо описана одним из разработчиков gcc в "Программирование для линукс".

>на моем P3 1.1 GHz меньше микросекунды на вызов.

>правда, мерял на 2.6 + sysenter.

здесь не знаю. для моих задач такое совсем не подходит.

кстати а ты уверен что в твоём случае имеет место гейт в ядро??? Или ет какаято user-space заглушка???

cvv ★★★★★
()
Ответ на: комментарий от cvv

> кстати а ты уверен что в твоём случае имеет место гейт в ядро???
> Или ет какаято user-space заглушка???

да уверен, я с ядром-то и ковырялся как раз.

> неа. на моей системе все вызовы gettimeofday() которые я когда
> либо трассировал имели именно такую длительность.

да не может этого быть. что за ядро? нет ли в dmesg каких
сообщений о timer source? выключить acpi, pm пробовали?
10ms - это неработающий gettimeofday().

ну подумайте хотя бы о том, что netif_rx() вызывает ее
для skb->stamp, у вас бы и сетка толком не работала.

а вообще - вот вам код, что печатает?

#include <stdio.h>
#include <unistd.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <sys/prctl.h>

void profile(int on)
{
        static struct rusage    r_0;
        static struct timeval   t_0;
        struct rusage   r_1;
        struct timeval  t_1;

        if (on) {
                getrusage(RUSAGE_SELF, &r_0);
                gettimeofday(&t_0, 0);
                return;
        }

        gettimeofday(&t_1, 0);
        getrusage(RUSAGE_SELF, &r_1);

        timersub(&t_1, &t_0, &t_1);
        timersub(&r_1.ru_utime, &r_0.ru_utime, &r_1.ru_utime);
        timersub(&r_1.ru_stime, &r_0.ru_stime, &r_1.ru_stime);

        #define TV(tv)  ((tv).tv_sec + (tv).tv_usec/1e6)

        printf("%.03f %.03f %.03f\n", TV(t_1),
                TV(r_1.ru_utime), TV(r_1.ru_stime));
}

int main(void)
{
        struct timeval dummy;
        int n;

        profile(1);
        for (n = 0; n < 1000 * 1000; ++n)
                gettimeofday(&dummy, 0);
        profile(0);

        return 0;
}

idle ★★★★★
()
Ответ на: комментарий от cvv

cvv:
> А вообщето ета ситуация неплохо описана одним из разработчиков
> gcc в "Программирование для линукс".

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

idle ★★★★★
()

По поводу 10 мс: разве что первый раз - за счет lazy memory allocation (если с памятью напряг), первый раз при копировании уснет (или будет небольшая задержка при отображении готовой пустой страницы). А вообще gettimeofday не спит (AFAIK) и уж на 10мс работы у нее точно нет.

Murr ★★
()
Ответ на: комментарий от idle

Спасибо, сделал, как ты сказал, получил (через OpenOffice Calc):

кол-во вызовов:
num = 262

минимальное время на вызов:
min = 0.000008

максимальное время на вызов:
max = 0.003589

время на все вызовы:
sum = 0.036675

среднее время на вызов:
avg = sum/num = 0.00013998

Не знаю в чем он меряет, man умалчивает, если в секундах, то времени получается затрачено очень мало (см. sum). Странно, значит мне показалось?

saper ★★★★★
()
Ответ на: комментарий от idle

Тоже решил протестить вашим кодом, получил (три запуска делал):
0.416 0.240 0.170
0.408 0.160 0.240
0.411 0.200 0.210

Athlon-850/VIA KT133.

saper ★★★★★
()
Ответ на: комментарий от idle

Собрал твою программу с опциями: -O20 -march=athlon-tbird -fexpensive-optimizations -fomit-frame-pointer -funroll-all-loops
получил результат еще интереснее предидущего:
0.398 0.230 0.160
0.401 0.200 0.200
0.401 0.130 0.260

Постепенное добавление флагов оптимизации показало улучшение характеристик:
- при добавлении -march=athlon-tbird (у меня этот процессор);
- при добавлении -O20 -fomit-frame-pointer -funroll-all-loops (я их сразу добавил таким набором);
- при добавлении -fexpensive-optimizations.

Улучшения были заметны по первой цифре, выдаваемой программой.

saper ★★★★★
()
Ответ на: комментарий от saper

Ядро 2.4.27 с kernel.org, дистрибутив Slackware (glibc не сильно патченная - всего 3-5 патчей по ~1Кб каждый).Timer source dmesg не показывает, сейчас посмотрю на ноуте, у которого точно ACPI PM timer source.

saper ★★★★★
()
Ответ на: комментарий от saper

Ноутбук, P3-800/i440BX, ядро 2.6.9-ac4, дистрибутив тот же, сделал первый тест, удивился, пересобрал ядро, результаты до/после пересборки:

Using pmtmr for high-res timesource:
- без оптимизации
2.425 0.260 2.149
2.432 0.283 2.127
2.421 0.268 2.139
- та же оптимизация, что и выше, только -march=pentium3
2.427 0.275 2.136
2.432 0.284 2.128
2.439 0.279 2.131

Using tsc for high-res timesource
- без оптимизации
0.637 0.255 0.371
0.639 0.212 0.415
0.639 0.248 0.380
- та же оптимизация, что и выше, только -march=pentium3
0.620 0.238 0.366
0.631 0.228 0.391
0.625 0.229 0.380

Конечно напрашивается странный вывод: tsc лучше pmtrr (рекомендуемого в help ядра для ноутбука)?

saper ★★★★★
()
Ответ на: комментарий от saper

Я надеюсь мои эксперименты и их результаты помогут автору оригинального сообщения решить свою проблему.

saper ★★★★★
()
Ответ на: комментарий от saper

>Конечно напрашивается странный вывод: tsc лучше pmtrr (рекомендуемого в help ядра для ноутбука)?

Чего тут странного, если процессор - самое высокочастотное устройство в PC?

Murr ★★
()
Ответ на: комментарий от Murr

Кстати, поясните все же про 10мс.
Частота самого худшего таймера на i386 - 1 (или 10) МГц.
Причем сам код gettimeofday - минимален.
Даже если посчитать выравнивание чтения из портов ввода-вывода по тактам шины, то все равно разрешение - куда меньше 10 мс (при частотах шины от 100 Мгц).

Murr ★★
()
Ответ на: комментарий от Murr

IMHO, к 10 мс можно приблизиться(но чтобы это заняло 10 мс - не верю) только когда практически все данные и код в вызове вылезли из кэша.

Murr ★★
()
Ответ на: комментарий от Murr

>Чего тут странного, если процессор - самое высокочастотное устройство в PC?

Кроме того, чтение TSC, как и чтение любого другого регистра, ничего не стоит процессору в отличие от операций со внешними устройствами.

Murr ★★
()
Ответ на: комментарий от saper

saper:
> Конечно напрашивается странный вывод: tsc лучше pmtrr
> (рекомендуемого в help ядра для ноутбука)?

то, что он быстрее - не удивительно, Murr прав.

но tsc не очень надежен, особенно на ноутбуках. т.е.
при всякого рода power management, freq. scaling он
может "поплыть", поэтому, наверное, и не рекомендуют.

idle ★★★★★
()
Ответ на: комментарий от idle

>не похоже на 10ms, не правда ли ? :)))

м-да. Так что профайлер крайний???

cvv ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.