LINUX.ORG.RU

clock_nanosleep(); Процесс спит не заданное время.


0

3

При попытке заснуть с помощью clock_nanosleep() получается неточный результат - ошибка от +1 мс до секунды с фигом, притом раз на раз не приходится. Точней - один раз запускаю тест - ошибка от 1 до 5 мс, но и это ОЧЕНЬ много. другой раз ошибка может быть десятки мс, третий 0.5 - 2 секунды. Что я делаю не так?

Код для теста:

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

int main() 
{ 
  struct timespec before_sleep, after_sleep, time_for_sleep;
  while(1) 
  { 
    clock_gettime(CLOCK_MONOTONIC, &before_sleep);
    time_for_sleep = before_sleep; time_for_sleep.tv_nsec += 100000000; // прибавляем 100 мс

    clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &time_for_sleep, NULL); //засыпаем на 100 мс

    clock_gettime(CLOCK_MONOTONIC, &after_sleep);

    printf("before: %d:%d - sec:nsec", before_sleep.tv_sec, before_sleep.tv_nsec);
    printf("after: %d:%d - sec:nsec", after_sleep.tv_sec, after_sleep.tv_nsec);

  } 
}

Этот пост писал на другой машине ввинде, поэтому могут быть ошибки в коде))

strace ./a.out

clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, {243083, 1089826488}, 0) = -1 EINVAL (Invalid argument) write(1, «before: 243083:989826488 - sec:n»..., 73before: 243083:989826488 - sec:nsec after: 243083:989872617 - sec:nsec ) = 73 clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, {243083, 1089944222}, 0) = -1 EINVAL (Invalid argument) write(1, «before: 243083:989944222 - sec:n»..., 73before: 243083:989944222 - sec:nsec after: 243083:989990813 - sec:nsec ) = 73 clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, {243083, 1090044544}, 0) = -1 EINVAL (Invalid argument) write(1, «before: 243083:990044544 - sec:n»..., 73before: 243083:990044544 - sec:nsec after: 243083:990090740 - sec:nsec ) = 73 clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, {243083, 1090144335}, 0) = -1 EINVAL (Invalid argument) write(1, «before: 243083:990144335 - sec:n»..., 73before: 243083:990144335 - sec:nsec after: 243083:990190467 - sec:nsec ) = 73 clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, {243083, 1090244070}, 0) = -1 EINVAL (Invalid argument) write(1, «before: 243083:990244070 - sec:n»..., 73before: 243083:990244070 - sec:nsec after: 243083:990290214 - sec:nsec ) = 73

ae1234 ★★
()

EINVAL The value in the tv_nsec field was not in the range 0 to 999999999 or tv_sec was negative.

Просто инкрементировать time_for_sleep.tv_nsec нельзя. Надо проверять.

И почему бы просто не воспользоваться nanosleep'ом?

Eddy_Em ☆☆☆☆☆
()

Когда Вы прибавляете 100000000, то tv_nsec может стать > 999999999.

Почему бы не сделать проще?

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

int main()
{
  struct timespec before_sleep, after_sleep, time_for_sleep;
  time_for_sleep.tv_sec = 0;
  time_for_sleep.tv_nsec = 100000000;
  while(1)
  {
    clock_gettime(CLOCK_MONOTONIC, &before_sleep);

    clock_nanosleep(CLOCK_MONOTONIC, 0, &time_for_sleep, NULL); //засыпаем на 100 мс

    clock_gettime(CLOCK_MONOTONIC, &after_sleep);

    printf("before: %d:%d - sec:nsec\n", before_sleep.tv_sec, before_sleep.tv_nsec);
    printf("after: %d:%d - sec:nsec\n", after_sleep.tv_sec, after_sleep.tv_nsec);

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

мне тут проверку влом было писать. Всё проверяется.

В с часами CLOCK_REALTIME результат аналогичный - тормозит, можете попробовать.

И почему бы просто не воспользоваться nanosleep'ом?

мне удобнее с TIMER_ABSTIME;

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

Не засывает у меня на 100мс, проблема остаётся. Дело не проверке, в реальном коде она у меня есть.

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

Сделай предварительно sched_setscheduler со SCHED_FIFO

так и сделано, приоритет 99, ядро с PREEMPT патчем. Но результат, что для моей программы, что для этого маленького теста аналогичный.

Может дело быть в железе или в конфигурации самосборного ядра?

golodranez ★★★★
() автор топика

> ошибка от 1 до 5 мс, но и это ОЧЕНЬ много

> от 1 до 5 мс

#define _POSIX_C_SOURCE 199309L

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

int main() {
    sched_setscheduler(0, SCHED_FIFO, &(struct sched_param) {
        .sched_priority = sched_get_priority_max(SCHED_FIFO)
    });

    for (int n = 10; n--;) {
        struct timespec a, b;
        clock_gettime(CLOCK_REALTIME, &a);
        nanosleep(&(struct timespec) { .tv_nsec = 100000000l }, NULL);
        clock_gettime(CLOCK_REALTIME, &b);
        printf("%ld\n", b.tv_nsec - a.tv_nsec + (b.tv_sec - a.tv_sec) * 1000000000l);
    }
}
# ./a.out
100020125
100013795
100019639
100020281
100016999
100017880
100017279
100017362
100018040
100015961

#_

запаздывает на 15—20мкс.

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

И да - HIGH_RESOLUTION_TIMERS включены?

Да.

Timer List Version: v0.5
HRTIMER_MAX_CLOCK_BASES: 2
now at 4771691577816 nsecs

cpu: 0
 clock 0:
  .base:       ffff88000560bd28
  .index:      0
  .resolution: 4000250 nsecs
  .get_time:   ktime_get_real
  .offset:     0 nsecs
active timers:
 clock 1:
  .base:       ffff88000560bd78
  .index:      1
  .resolution: 4000250 nsecs
  .get_time:   ktime_get
  .offset:     0 nsecs
active timers:
 #0: def_rt_bandwidth, sched_rt_period_timer, S:01, enqueue_task_rt, swapper/1
 # expires at 4772000000000-4772000000000 nsecs [in 308422184 to 308422184 nsecs]
 #1: <ffff8801143f5a48>, hrtimer_wakeup, S:01, hrtimer_start_range_ns, hald-addon-stor/2258
 # expires at 4772000349292-4772002345291 nsecs [in 308771476 to 310767475 nsecs]
 #2: <ffff880114f79a48>, hrtimer_wakeup, S:01, hrtimer_start_range_ns, hald-addon-stor/2269
 # expires at 4772000475205-4772002470204 nsecs [in 308897389 to 310892388 nsecs]
 #3: <ffff88000560ac20>, mce_start_timer, S:01, hrtimer_start_range_ns, swapper/0
 # expires at 4772045095729-4772045095729 nsecs [in 353517913 to 353517913 nsecs]
 #4: <ffff8801140a1a48>, hrtimer_wakeup, S:01, hrtimer_start_range_ns, hald-addon-stor/2267
 # expires at 4773000461893-4773002456892 nsecs [in 1308884077 to 1310879076 nsecs]
 #5: <ffff880114f75a48>, hrtimer_wakeup, S:01, hrtimer_start_range_ns, hald-addon-stor/2270
 # expires at 4773000967343-4773002940342 nsecs [in 1309389527 to 1311362526 nsecs]
 #6: <ffff880117aab8e8>, hrtimer_wakeup, S:01, hrtimer_start_range_ns, init/1
 # expires at 4773419869337-4773424869336 nsecs [in 1728291521 to 1733291520 nsecs]
 #7: <ffff880114e73e88>, hrtimer_wakeup, S:01, hrtimer_start_range_ns, cron/2309
 # expires at 4807121263449-4807121313449 nsecs [in 35429685633 to 35429735633 nsecs]
 #8: <ffff8801167f5a48>, hrtimer_wakeup, S:01, hrtimer_start_range_ns, syslog-ng/1712
 # expires at 4813957755788-4814057755788 nsecs [in 42266177972 to 42366177972 nsecs]
 #9: <ffff880114ae3218>, it_real_fn, S:01, hrtimer_start, master/2275
 # expires at 5090466572950-5090466572950 nsecs [in 318774995134 to 318774995134 nsecs]
  .expires_next   : 9223372036854775807 nsecs
  .hres_active    : 0
  .nr_events      : 0
  .nr_retries     : 0
  .nr_hangs       : 0
  .max_hang_time  : 0 nsecs
  .nohz_mode      : 0
  .idle_tick      : 0 nsecs
  .tick_stopped   : 0
  .idle_jiffies   : 0
  .idle_calls     : 0
  .idle_sleeps    : 0
  .idle_entrytime : 4771690939399 nsecs
  .idle_waketime  : 0 nsecs
  .idle_exittime  : 0 nsecs
  .idle_sleeptime : 4075229010749 nsecs
  .last_jiffies   : 0
  .next_jiffies   : 0
  .idle_expires   : 0 nsecs
jiffies: 4296085072

cpu: 1
 clock 0:
  .base:       ffff88000570bd28
  .index:      0
  .resolution: 4000250 nsecs
  .get_time:   ktime_get_real
  .offset:     0 nsecs
active timers:
 clock 1:
  .base:       ffff88000570bd78
  .index:      1
  .resolution: 4000250 nsecs
  .get_time:   ktime_get
  .offset:     0 nsecs
active timers:
 #0: <ffff8801160e58e8>, hrtimer_wakeup, S:01, hrtimer_start_range_ns, X/2320
 # expires at 4772190732618-4772191232617 nsecs [in 499154802 to 499654801 nsecs]
 #1: <ffff8801155dba48>, hrtimer_wakeup, S:01, hrtimer_start_range_ns, hald-addon-stor/2271
 # expires at 4773000342671-4773002315670 nsecs [in 1308764855 to 1310737854 nsecs]
 #2: <ffff88000570ac20>, mce_start_timer, S:01, hrtimer_start_range_ns, swapper/0
 # expires at 4773009384700-4773009384700 nsecs [in 1317806884 to 1317806884 nsecs]
  .expires_next   : 4155546108 nsecs
  .hres_active    : 0
  .nr_events      : 0
  .nr_retries     : 0
  .nr_hangs       : 0
  .max_hang_time  : 0 nsecs
  .nohz_mode      : 0
  .idle_tick      : 0 nsecs
  .tick_stopped   : 0
  .idle_jiffies   : 0
  .idle_calls     : 0
  .idle_sleeps    : 0
  .idle_entrytime : 4771690737368 nsecs
  .idle_waketime  : 0 nsecs
  .idle_exittime  : 0 nsecs
  .idle_sleeptime : 3980132597719 nsecs
  .last_jiffies   : 0
  .next_jiffies   : 0
  .idle_expires   : 0 nsecs
jiffies: 4296085072


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

Т.е. у меня наверное чтото с железом или с ядром. Самый прикол в том, что фиг с ними с 1-20 мс, хоть это и явный глюк. Но откуда секунды могут браться?

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

> Но откуда секунды могут браться?

а хз.

кстати, только досмотрел, что у тебя clock_nanosleep с TIMER_ABSTIME, а не nanosleep :)

#define _POSIX_C_SOURCE  200112L

#include <stdio.h>
#include <time.h>
#include <sched.h>
#include <stdlib.h>

int main() {
    sched_setscheduler(0, SCHED_FIFO, &(struct sched_param) {
        .sched_priority = sched_get_priority_max(SCHED_FIFO)
    });

    for (int n = 10; n--;) {
        struct timespec a, b;
        clock_gettime(CLOCK_REALTIME, &a);
        ldiv_t t = ldiv(a.tv_nsec + 100000000l, 1000000000l);
        clock_nanosleep(CLOCK_REALTIME, TIMER_ABSTIME, &(struct timespec) {
            .tv_sec  = a.tv_sec + t.quot,
            .tv_nsec = t.rem
        }, NULL);
        clock_gettime(CLOCK_REALTIME, &b);
        printf("%ld\n", b.tv_nsec - a.tv_nsec + (b.tv_sec - a.tv_sec) * 1000000000l);
    }
}
# ./a.out
100016360
100015479
100016085
100017676
100015160
100015960
100017917
100016882
100016961
100018279
# _

так даже точнее :)

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

Там есть строки с hrtimer_interrupt?

нет, таких строк нет.

cpu: 2
 clock 0:
  .base:       ffff88000580bd28
  .index:      0
  .resolution: 4000250 nsecs
  .get_time:   ktime_get_real
  .offset:     0 nsecs
active timers:
 clock 1:
  .base:       ffff88000580bd78
  .index:      1
  .resolution: 4000250 nsecs
  .get_time:   ktime_get
  .offset:     0 nsecs
active timers:
 #0: <ffff88010f567a48>, hrtimer_wakeup, S:01, hrtimer_start_range_ns, hald-addon-stor/2288
 # expires at 4771623928860-4771625928859 nsecs [in -67648956 to -65648957 nsecs]
 #1: <ffff88000580ac20>, mce_start_timer, S:01, hrtimer_start_range_ns, swapper/0
 # expires at 4774746615748-4774746615748 nsecs [in 3055037932 to 3055037932 nsecs]
 #2: <ffff8801143b5a98>, it_real_fn, S:01, hrtimer_start, pickup/2311
 # expires at 5090466571548-5090466571548 nsecs [in 318774993732 to 318774993732 nsecs]
  .expires_next   : 8438513404 nsecs
  .hres_active    : 0
  .nr_events      : 0
  .nr_retries     : 0
  .nr_hangs       : 0
  .max_hang_time  : 0 nsecs
  .nohz_mode      : 0
  .idle_tick      : 0 nsecs
  .tick_stopped   : 0
  .idle_jiffies   : 0
  .idle_calls     : 0
  .idle_sleeps    : 0
  .idle_entrytime : 4771690658718 nsecs
  .idle_waketime  : 0 nsecs
  .idle_exittime  : 0 nsecs
  .idle_sleeptime : 4169346453447 nsecs
  .last_jiffies   : 0
  .next_jiffies   : 0
  .idle_expires   : 0 nsecs
jiffies: 4296085072

cpu: 3
 clock 0:
  .base:       ffff88000590bd28
  .index:      0
  .resolution: 4000250 nsecs
  .get_time:   ktime_get_real
  .offset:     0 nsecs
active timers:
 clock 1:
  .base:       ffff88000590bd78
  .index:      1
  .resolution: 4000250 nsecs
  .get_time:   ktime_get
  .offset:     0 nsecs
active timers:
 #0: <ffff880113f21a48>, hrtimer_wakeup, S:01, hrtimer_start_range_ns, hald-addon-stor/2268
 # expires at 4771780949998-4771782949997 nsecs [in 89372182 to 91372181 nsecs]
 #1: <ffff88000590ac20>, mce_start_timer, S:01, hrtimer_start_range_ns, swapper/0
 # expires at 4773506516200-4773506516200 nsecs [in 1814938384 to 1814938384 nsecs]
 #2: <ffff880113968f18>, it_real_fn, S:01, hrtimer_start, qmgr/2312
 # expires at 4849436982127-4849436982127 nsecs [in 77745404311 to 77745404311 nsecs]
  .expires_next   : 8426513404 nsecs
  .hres_active    : 0
  .nr_events      : 0
  .nr_retries     : 0
  .nr_hangs       : 0
  .max_hang_time  : 0 nsecs
  .nohz_mode      : 0
  .idle_tick      : 0 nsecs
  .tick_stopped   : 0
  .idle_jiffies   : 0
  .idle_calls     : 0
  .idle_sleeps    : 0
  .idle_entrytime : 4771690808876 nsecs
  .idle_waketime  : 0 nsecs
  .idle_exittime  : 0 nsecs
  .idle_sleeptime : 3797745361408 nsecs
  .last_jiffies   : 0
  .next_jiffies   : 0
  .idle_expires   : 0 nsecs
jiffies: 4296085072


Tick Device: mode:     0
Broadcast device
Clock Event Device: pit
 max_delta_ns:   27461866
 min_delta_ns:   12571
 mult:           5124677
 shift:          32
 mode:           1
 next_event:     9223372036854775807 nsecs
 set_next_event: pit_next_event
 set_mode:       init_pit_timer
 event_handler:  clockevents_handle_noop
tick_broadcast_mask: 00000000
tick_broadcast_oneshot_mask: 00000000


Tick Device: mode:     0
Per CPU device: 0
Clock Event Device: lapic
 max_delta_ns:   1007350148
 min_delta_ns:   1801
 mult:           35765908
 shift:          32
 mode:           2
 next_event:     9223372036854775807 nsecs
 set_next_event: lapic_next_event
 set_mode:       lapic_timer_setup
 event_handler:  tick_handle_periodic

Tick Device: mode:     0
Per CPU device: 1
Clock Event Device: lapic
 max_delta_ns:   1007350148
 min_delta_ns:   1801
 mult:           35765908
 shift:          32
 mode:           2
 next_event:     4155546108 nsecs
 set_next_event: lapic_next_event
 set_mode:       lapic_timer_setup
 event_handler:  tick_handle_periodic

Tick Device: mode:     0
Per CPU device: 2
Clock Event Device: lapic
 max_delta_ns:   1007350148
 min_delta_ns:   1801
 mult:           35765908
 shift:          32
 mode:           2
 next_event:     8438513404 nsecs
 set_next_event: lapic_next_event
 set_mode:       lapic_timer_setup
 event_handler:  tick_handle_periodic

Tick Device: mode:     0
Per CPU device: 3
Clock Event Device: lapic
 max_delta_ns:   1007350148
 min_delta_ns:   1801
 mult:           35765908
 shift:          32
 mode:           2
 next_event:     8426513404 nsecs
 set_next_event: lapic_next_event
 set_mode:       lapic_timer_setup
 event_handler:  tick_handle_periodic


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

> Т.е. у меня наверное чтото с железом или с ядром.

arm (ядро 3.2.2 без -rt-патча):

# ./a.out 
107822800
105461761
117122480
106451439
106454321
117134240
117144319
106445841
106467279
117118560
# _

всё плохо, 6-17 мс…

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

конечно с ABSTIME должно быть точнее)) Хотя с SCHED_FIFO может и пофигу.

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

То, что есть lapic, способный oneshot, но нет hrtimer_interrupt, означает отсутствие стабильного clocksource. dmesg в студию

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

Это значит, что таймеры у тебя тикают равномерно с периодом HZ, и возможности hrtimers не используются.

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

В ядре есть такая опция Tickless system - timer interrupts will only trigger on an as-needed basis when the system is busy and when the system is idle.

Не объяснишь для простого смертного, что это значит и не связано ли это с моей проблемой? У меня она включена.

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

В ядре есть такая опция Tickless system - timer interrupts will only trigger on an as-needed basis when the system is busy and when the system is idle.

Это для экономии энергии на ноутбуках. Влиять не должно.

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

сейчас гляну.

Ещё вот такое нашёл на rt.wiki.kernel.org

NOTE: Since rt patch 2.6.18-rt6 you will probably have to activate ACPI option to activate high resolution timer. Since the TSC timer on PC platforms, as used in the previous versions, are now marked as unsuitable for hrt mode due to many lacks of functionalities and reliabilties, you will need i.E. pm_timer as provided by ACPI to use as clock source. To activate the pm_timer, you can just activate the ACPI_SUPPORT in menuconfig and deactivate all other sub modules like «fan», «processor» or «button».

Из этого абзаца я не пойму, какую именно опцию ACPI нужно включить? У меня ACPI выключено полностью. Есть Run-time PM Core funtionality, но по описанию не похоже.

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

Попробуй echo hpet > /sys/devices/system/clocksource/clocksource0/current_clocksource

попробовал, а что должно случиться?

$cat /sys/devices/system/clocksource/clocksource0/current_clocksource

tsc

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

cat /sys/devices/system/clocksource/clocksource0/available_clocksource

tsc jiffies

Сейчас пересобрал ядро с включённым ACPI - в /proc/timer_list появился - event_handler: hrtimer_interrupt

clock_nanosleep отрабатывает норсально, есть задержка в 15-50 микросекунд - это нормально? Мо математика в проге стала считаться в ТРИ(!) раза медленней.... жесть. Это изза ACPI?

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

tsc jiffies

Как-то негусто

Сейчас пересобрал ядро с включённым ACPI - в /proc/timer_list появился - event_handler: hrtimer_interrupt

То, что нужно

clock_nanosleep отрабатывает норсально, есть задержка в 15-50 микросекунд - это нормально?

Задержка на wakeup и прочие служебные операции будет в любом случае. Насколько большая - зависит от процессора.

Мо математика в проге стала считаться в ТРИ(!) раза медленней.... жесть. Это изза ACPI?

При прочих равных (конфиг, компилятор и т.д.) это странно.

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

Ты не понял, чтоли?

В линуксе тебе никто никаких гарантий по времени не дает.

«Лагает» столько, сколько надо для выполнения операции.

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

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

lovesan

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

При прочих равных (конфиг, компилятор и т.д.) это странно.

В конфигах Makeфайла ошибся, всё ок.

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

В линуксе тебе никто никаких гарантий по времени не дает.

прекрати выпячивать своё ЧСВ почитай уже шоле Documentation/scheduler

Любое простейшее обращение к памяти может заставить ждать хоть полминуты

ты реально баклан

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

Че ты мне тыкаешь в свой documentation? Иди сам ее и прочитай. В линаксе не реалтайм планировщик.

ты реально баклан

Гагага. Нет, баклан это ты, раз такие элементарные вещи не понимаешь.

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

такие элементарные вещи не понимаешь.

ой-ой, ты наверно про своппинг, да? Гуляй, мальчик, тред не для таких умных как ты.

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

Ты хотяб тему бы прочитать удосужился....

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

> Это с PREEMPT RT патчем ядро или без?

это персоналка на работе, какое нафиг PREEMPT RT :) там ядром от св. Патрика (2.6.28.х) :)

на арм-девайсе тоже без PREEMPT RT было из-за эпичного бага…

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